From afe25eda244a896ce0f6e19ae31723254ec45172 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 26 Jun 2024 14:43:06 +0200 Subject: [PATCH 01/14] change(web): remove support for es5 Fixes: #11878 --- android/.gitignore | 2 -- .../app/src/main/assets/keyboard.es5.html | 30 ---------------- .../java/com/keyman/engine/KMManager.java | 32 +++-------------- android/KMEA/build.sh | 2 -- .../sourcemap-path-remapper/tsconfig.json | 2 +- common/web/es-bundling/build.sh | 3 +- common/web/es-bundling/src/common-bundle.mts | 4 +-- common/web/es-bundling/src/configuration.mts | 7 ++-- common/web/keyboard-processor/build.sh | 13 ++++--- common/web/keyboard-processor/package.json | 16 ++++----- .../src/keyboards/loaders/tsconfig.dom.json | 4 +-- .../src/keyboards/loaders/tsconfig.node.json | 4 +-- .../src/text/stringDivergence.ts | 9 +++-- .../tests/dom/cases/domKeyboardLoader.spec.ts | 18 +++++----- .../tests/dom/web-test-runner.config.mjs | 4 +-- .../web/keyboard-processor/tsconfig.all.json | 2 +- common/web/keyboard-processor/tsconfig.json | 9 +++-- common/web/keyman-version/tsconfig.json | 2 +- common/web/lm-message-types/tsconfig.json | 2 +- common/web/lm-worker/build-polyfiller.js | 4 +-- common/web/lm-worker/build.sh | 34 +------------------ common/web/lm-worker/package.json | 6 ++-- common/web/sentry-manager/src/index.ts | 7 ++-- common/web/tslib/README.md | 15 -------- common/web/tslib/build.sh | 25 -------------- common/web/tslib/package.json | 28 --------------- common/web/tslib/src/index.ts | 3 -- common/web/tslib/tsconfig.json | 16 --------- common/web/types/src/deps/xml2js/parser.js | 2 +- common/web/types/src/util/util.ts | 6 ++-- common/web/utils/src/index.ts | 4 +-- common/web/utils/src/surrogates.ts | 27 --------------- package-lock.json | 16 --------- web/build.sh | 27 +++++++++++++++ web/package.json | 1 - web/src/app/browser/build.sh | 12 ------- web/src/app/webview/build.sh | 10 ------ .../outputTargetForElement.spec.html | 2 +- .../test/auto/dom/web-test-runner.config.mjs | 16 ++++----- .../integrated/web-test-runner.config.mjs | 2 +- web/src/test/auto/tsconfig.json | 6 +++- web/tsconfig.base.json | 2 +- 42 files changed, 111 insertions(+), 325 deletions(-) delete mode 100644 android/KMEA/app/src/main/assets/keyboard.es5.html delete mode 100644 common/web/tslib/README.md delete mode 100755 common/web/tslib/build.sh delete mode 100644 common/web/tslib/package.json delete mode 100644 common/web/tslib/src/index.ts delete mode 100644 common/web/tslib/tsconfig.json delete mode 100644 common/web/utils/src/surrogates.ts diff --git a/android/.gitignore b/android/.gitignore index 4f0c3bb5018..a5720bccc73 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -37,8 +37,6 @@ KMEA/**/assets/keymanandroid.js KMEA/**/assets/keyman.js.map KMEA/**/assets/keymanweb-webview.js KMEA/**/assets/keymanweb-webview.js.map -KMEA/**/assets/keymanweb-webview.es5.js -KMEA/**/assets/keymanweb-webview.es5.js.map KMEA/**/assets/map-polyfill.js KMEA/**/assets/sentry.min.js KMEA/**/assets/keyman-sentry.js diff --git a/android/KMEA/app/src/main/assets/keyboard.es5.html b/android/KMEA/app/src/main/assets/keyboard.es5.html deleted file mode 100644 index 6384235456b..00000000000 --- a/android/KMEA/app/src/main/assets/keyboard.es5.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - Keyman - - - - - - - - - - - - - diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index d1a40be69ae..aa1c43626a7 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -295,9 +295,7 @@ public String toString() { // Keyman files protected static final String KMFilename_KeyboardHtml = "keyboard.html"; - protected static final String KMFilename_KeyboardHtml_Legacy = "keyboard.es5.html"; protected static final String KMFilename_JSEngine = "keymanweb-webview.js"; - protected static final String KMFilename_JSLegacyEngine = "keymanweb-webview.es5.js"; protected static final String KMFilename_JSSentry = "sentry.min.js"; protected static final String KMFilename_JSSentryInit = "keyman-sentry.js"; protected static final String KMFilename_AndroidHost = "android-host.js"; @@ -858,25 +856,11 @@ public static boolean copyHTMLBannerAssets(Context context, String path) { private static void copyAssets(Context context) { AssetManager assetManager = context.getAssets(); - // Will build a temp WebView in order to check Chrome version internally. - boolean legacyMode = WebViewUtils.getEngineWebViewVersionStatus(context, null, null) != WebViewUtils.EngineWebViewVersionStatus.FULL; - try { // Copy KMW files - if(legacyMode) { - // Replaces the standard ES6-friendly version of the host page with a legacy one that - // includes polyfill requests and that links the legacy, ES5-compatible version of KMW. - copyAssetWithRename(context, KMFilename_KeyboardHtml_Legacy, KMFilename_KeyboardHtml, "", true); - - copyAsset(context, KMFilename_JSLegacyEngine, "", true); - } else { - copyAsset(context, KMFilename_KeyboardHtml, "", true); - - // For versions of Chrome with full ES6 support, we use the ES6 artifact. - copyAsset(context, KMFilename_JSEngine, "", true); - } + copyAsset(context, KMFilename_KeyboardHtml, "", true); - // Is still built targeting ES5. + copyAsset(context, KMFilename_JSEngine, "", true); copyAsset(context, KMFilename_JSSentry, "", true); copyAsset(context, KMFilename_JSSentryInit, "", true); copyAsset(context, KMFilename_AndroidHost, "", true); @@ -887,12 +871,6 @@ private static void copyAssets(Context context) { // Copy default keyboard font copyAsset(context, KMDefault_KeyboardFont, "", true); - if(legacyMode) { - copyAsset(context, KMFilename_JSPolyfill, "", true); - copyAsset(context, KMFilename_JSPolyfill2, "", true); - copyAsset(context, KMFilename_JSPolyfill3, "", true); - } - // Keyboard packages directory File packagesDir = new File(getPackagesDir()); if (!packagesDir.exists()) { @@ -1638,7 +1616,7 @@ public static boolean removeKeyboard(Context context, int position) { public static boolean isDefaultKey(String key) { return ( - key != null && + key != null && key.equals(KMString.format("%s_%s", KMDefault_LanguageID, KMDefault_KeyboardID))); } @@ -2084,11 +2062,11 @@ public static Point getWindowSize(Context context) { wm.getDefaultDisplay().getSize(size); return size; } - + WindowMetrics windowMetrics = wm.getCurrentWindowMetrics(); return new Point( windowMetrics.getBounds().width(), - windowMetrics.getBounds().height()); + windowMetrics.getBounds().height()); } public static float getWindowDensity(Context context) { diff --git a/android/KMEA/build.sh b/android/KMEA/build.sh index ccf7c92887b..878b54797dc 100755 --- a/android/KMEA/build.sh +++ b/android/KMEA/build.sh @@ -77,8 +77,6 @@ if builder_start_action build:engine; then echo "Copying Keyman Web artifacts" cp "$KEYMAN_WEB_ROOT/build/app/webview/$CONFIG/keymanweb-webview.js" "$ENGINE_ASSETS/keymanweb-webview.js" cp "$KEYMAN_WEB_ROOT/build/app/webview/$CONFIG/keymanweb-webview.js.map" "$ENGINE_ASSETS/keymanweb-webview.js.map" - cp "$KEYMAN_WEB_ROOT/build/app/webview/$CONFIG/keymanweb-webview.es5.js" "$ENGINE_ASSETS/keymanweb-webview.es5.js" - cp "$KEYMAN_WEB_ROOT/build/app/webview/$CONFIG/keymanweb-webview.es5.js.map" "$ENGINE_ASSETS/keymanweb-webview.es5.js.map" cp "$KEYMAN_WEB_ROOT/build/app/webview/$CONFIG/map-polyfill.js" "$ENGINE_ASSETS/map-polyfill.js" cp "$KEYMAN_WEB_ROOT/build/app/resources/osk/ajax-loader.gif" "$ENGINE_ASSETS/ajax-loader.gif" cp "$KEYMAN_WEB_ROOT/build/app/resources/osk/kmwosk.css" "$ENGINE_ASSETS/kmwosk.css" diff --git a/common/tools/sourcemap-path-remapper/tsconfig.json b/common/tools/sourcemap-path-remapper/tsconfig.json index e207097f614..35744ee9887 100644 --- a/common/tools/sourcemap-path-remapper/tsconfig.json +++ b/common/tools/sourcemap-path-remapper/tsconfig.json @@ -10,7 +10,7 @@ "inlineSources": true, "sourceRoot": "/common/tools/sourcemap-path-remapper/src", "lib": ["dom", "es6"], - "target": "es5", + "target": "es6", "types": ["node"], "downlevelIteration": true, "baseUrl": "./", diff --git a/common/web/es-bundling/build.sh b/common/web/es-bundling/build.sh index cd6b975255a..768f41fa2fd 100755 --- a/common/web/es-bundling/build.sh +++ b/common/web/es-bundling/build.sh @@ -11,7 +11,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" ################################ Main script ################################ builder_describe "Builds KMW's esbuild-oriented common configuration & tooling" \ - "@/common/web/tslib" \ "clean" \ "configure" \ "build" @@ -24,4 +23,4 @@ builder_parse "$@" builder_run_action configure verify_npm_setup builder_run_action clean rm -rf build/ -builder_run_action build tsc -b tsconfig.json \ No newline at end of file +builder_run_action build tsc -b tsconfig.json diff --git a/common/web/es-bundling/src/common-bundle.mts b/common/web/es-bundling/src/common-bundle.mts index d99a7bfc644..fb3dfb95a44 100644 --- a/common/web/es-bundling/src/common-bundle.mts +++ b/common/web/es-bundling/src/common-bundle.mts @@ -12,7 +12,7 @@ let profilePath; let sourceRoot; let platform; -let jsVersionTarget='es5'; +let jsVersionTarget='es6'; function doHelp(errCode?: number) { console.log(` @@ -141,4 +141,4 @@ const results = await esbuild.build(config); if(results.metafile) { let filesizeProfile = await esbuild.analyzeMetafile(results.metafile, { verbose: true }); fs.writeFileSync(profilePath, filesizeProfile); -} \ No newline at end of file +} diff --git a/common/web/es-bundling/src/configuration.mts b/common/web/es-bundling/src/configuration.mts index 4978aa73c77..0c7a724a416 100644 --- a/common/web/es-bundling/src/configuration.mts +++ b/common/web/es-bundling/src/configuration.mts @@ -2,16 +2,13 @@ import type * as esbuild from 'esbuild'; import { pluginForDowncompiledClassTreeshaking } from './classTreeshaker.mjs'; export const esmConfiguration: esbuild.BuildOptions = { - alias: { - 'tslib': '@keymanapp/tslib' - }, bundle: true, format: "esm", outExtension: { '.js': '.mjs'}, plugins: [ pluginForDowncompiledClassTreeshaking ], sourcemap: true, sourcesContent: true, - target: "es5" + target: "es6" }; export const iifeConfiguration: esbuild.BuildOptions = { @@ -70,4 +67,4 @@ export function bundleObjEntryPoints(configFolder: 'lib' | 'debug' | 'release', entryPoints: path, outdir: mappedRoot }; -} \ No newline at end of file +} diff --git a/common/web/keyboard-processor/build.sh b/common/web/keyboard-processor/build.sh index 85be0c09980..3455f924fc6 100755 --- a/common/web/keyboard-processor/build.sh +++ b/common/web/keyboard-processor/build.sh @@ -45,21 +45,26 @@ function do_build() { tsc --build "$THIS_SCRIPT_PATH/tsconfig.all.json" # Base product - the main keyboard processor - $BUNDLE_CMD "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/index.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/index.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/index.mjs" \ --format esm # The DOM-oriented keyboard loader - $BUNDLE_CMD "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/keyboards/loaders/dom-keyboard-loader.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/dom-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/dom-keyboard-loader.mjs" \ --format esm # The Node-oriented keyboard loader - $BUNDLE_CMD "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/keyboards/loaders/node-keyboard-loader.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/node-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/node-keyboard-loader.mjs" \ --format esm \ --platform node + # Tests + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/tests/dom/cases/domKeyboardLoader.spec.js" \ + --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/ndomKeyboardLoader.spec.mjs" \ + --format esm + # Declaration bundling. tsc --emitDeclarationOnly --outFile ./build/lib/index.d.ts tsc --emitDeclarationOnly --outFile ./build/lib/dom-keyboard-loader.d.ts -p src/keyboards/loaders/tsconfig.dom.json @@ -82,4 +87,4 @@ function do_test() { builder_run_action configure do_configure builder_run_action clean rm -rf ./build builder_run_action build do_build -builder_run_action test do_test \ No newline at end of file +builder_run_action test do_test diff --git a/common/web/keyboard-processor/package.json b/common/web/keyboard-processor/package.json index 3f0a5958970..d26126388fe 100644 --- a/common/web/keyboard-processor/package.json +++ b/common/web/keyboard-processor/package.json @@ -35,22 +35,22 @@ "@keymanapp/web-utils": "*" }, "type": "module", - "main": "./build/obj/index.js", - "types": "./build/obj/index.d.ts", + "main": "./build/obj/src/index.js", + "types": "./build/obj/src/index.d.ts", "exports": { ".": { "es6-bundling": "./src/index.ts", - "default": "./build/obj/index.js" + "default": "./build/obj/src/index.js" }, "./node-keyboard-loader": { "es6-bundling": "./src/keyboards/loaders/node-keyboard-loader.ts", - "types": "./build/obj/keyboards/loaders/node-keyboard-loader.d.ts", - "import": "./build/obj/keyboards/loaders/node-keyboard-loader.js" + "types": "./build/obj/src/keyboards/loaders/node-keyboard-loader.d.ts", + "import": "./build/obj/src/keyboards/loaders/node-keyboard-loader.js" }, "./dom-keyboard-loader": { "es6-bundling": "./src/keyboards/loaders/dom-keyboard-loader.ts", - "types": "./build/obj/keyboards/loaders/dom-keyboard-loader.d.ts", - "import": "./build/obj/keyboards/loaders/dom-keyboard-loader.js" + "types": "./build/obj/src/keyboards/loaders/dom-keyboard-loader.d.ts", + "import": "./build/obj/src/keyboards/loaders/dom-keyboard-loader.js" }, "./lib": { "types": "./build/lib/index.d.ts", @@ -64,6 +64,6 @@ "types": "./build/lib/dom-keyboard-loader.d.ts", "import": "./build/lib/dom-keyboard-loader.mjs" }, - "./obj/*.js": "./build/obj/*.js" + "./obj/*.js": "./build/obj/src/*.js" } } diff --git a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json index 7ba2abe026a..ac48667fd70 100644 --- a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json +++ b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json @@ -2,8 +2,8 @@ "extends": "../../../../tsconfig.kmw-main-base.json", "compilerOptions": { "baseUrl": "../../../", - "outDir": "../../../build/obj/keyboards/loaders/", - "tsBuildInfoFile": "../../../build/obj/keyboards/loaders/tsconfig.dom.tsbuildinfo", + "outDir": "../../../build/obj/src/keyboards/loaders/", + "tsBuildInfoFile": "../../../build/obj/src/keyboards/loaders/tsconfig.dom.tsbuildinfo", "rootDir": "." }, "references": [ diff --git a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json index 0be3f169ad3..0e15eea6b00 100644 --- a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json +++ b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json @@ -3,8 +3,8 @@ "compilerOptions": { "types": [ "node" ], "baseUrl": "../../../", - "outDir": "../../../build/obj/keyboards/loaders/", - "tsBuildInfoFile": "../../../build/obj/keyboards/loaders/tsconfig.node.tsbuildinfo", + "outDir": "../../../build/obj/src/keyboards/loaders/", + "tsBuildInfoFile": "../../../build/obj/src/keyboards/loaders/tsconfig.node.tsbuildinfo", "rootDir": "." }, "references": [ diff --git a/common/web/keyboard-processor/src/text/stringDivergence.ts b/common/web/keyboard-processor/src/text/stringDivergence.ts index e3461e129a4..31a94d8bdb9 100644 --- a/common/web/keyboard-processor/src/text/stringDivergence.ts +++ b/common/web/keyboard-processor/src/text/stringDivergence.ts @@ -1,5 +1,4 @@ -// Future TODO: import from @keymanapp/common-types... once we no longer need to support ES5. -import { Uni_IsSurrogate1, Uni_IsSurrogate2 } from '@keymanapp/web-utils'; +import { util } from '@keymanapp/common-types'; /** * Returns the index for the code point divergence point between two strings, as measured in code @@ -73,8 +72,8 @@ export function findCommonSubstringEndIndex(str1: string, str2: string, commonSu const divergentChar1 = str1.charCodeAt(index); const divergentChar2 = str2.charCodeAt(index + offset); - const commonSurrogateChecker = commonSuffix ? Uni_IsSurrogate2 : Uni_IsSurrogate1; - const divergentSurrogateChecker = commonSuffix ? Uni_IsSurrogate1 : Uni_IsSurrogate2; + const commonSurrogateChecker = commonSuffix ? util.Uni_IsSurrogate2 : util.Uni_IsSurrogate1; + const divergentSurrogateChecker = commonSuffix ? util.Uni_IsSurrogate1 : util.Uni_IsSurrogate2; // If the last common character if of the direction-appropriate surrogate type (for // comprising a potential split surrogate pair representing a non-BMP char)... @@ -90,4 +89,4 @@ export function findCommonSubstringEndIndex(str1: string, str2: string, commonSu } return index; -} \ No newline at end of file +} diff --git a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts index a1f6a31c679..0254b6a4c0f 100644 --- a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts +++ b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts @@ -15,8 +15,8 @@ const device: DeviceSpec = { describe('Keyboard loading in DOM', function() { afterEach(() => { - if(window['KeymanWeb']) { - window['KeymanWeb'].uninstall(); + if(window['KeymanWeb' as any]) { + (window['KeymanWeb' as any] as any).uninstall(); } }) @@ -29,8 +29,8 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window['KeymanWeb']); - assert.isOk(window['keyman']); + assert.isOk(window['KeymanWeb' as any]); + assert.isOk(window['keyman' as any]); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); @@ -46,8 +46,8 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window['KeymanWeb']); - assert.isOk(window['keyman']); + assert.isOk(window['KeymanWeb' as any]); + assert.isOk(window['keyman' as any]); // TODO: verify actual rule processing. const nullKeyEvent = keyboard.constructNullKeyEvent(device); @@ -55,8 +55,8 @@ describe('Keyboard loading in DOM', function() { const result = harness.processKeystroke(mock, nullKeyEvent); assert.isOk(result); - assert.isOk(window['KeymanWeb']); - assert.isOk(window['keyman']); + assert.isOk(window['KeymanWeb' as any]); + assert.isOk(window['keyman' as any]); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); @@ -95,4 +95,4 @@ describe('Keyboard loading in DOM', function() { harness.activeKeyboard = lao_keyboard; }); -}); \ No newline at end of file +}); diff --git a/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs b/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs index c16759b5090..9fd8f1344ba 100644 --- a/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs +++ b/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs @@ -21,7 +21,7 @@ export default { concurrency: 10, nodeResolve: true, files: [ - '**/*.spec.ts' + 'build/lib/**/*.spec.mjs' ], middleware: [ // Rewrites short-hand paths for test resources, making them fully relative to the repo root. @@ -59,4 +59,4 @@ export default { // open: true, // manual: true, rootDir: KEYMAN_ROOT -} \ No newline at end of file +} diff --git a/common/web/keyboard-processor/tsconfig.all.json b/common/web/keyboard-processor/tsconfig.all.json index 3325d965e05..40a93648668 100644 --- a/common/web/keyboard-processor/tsconfig.all.json +++ b/common/web/keyboard-processor/tsconfig.all.json @@ -4,7 +4,7 @@ "baseUrl": "./", "outDir": "build/obj/", "tsBuildInfoFile": "build/obj/tsconfig.all.tsbuildinfo", - "rootDir": "./src" + "rootDir": "." }, "references": [ { "path": "./src/keyboards/loaders/tsconfig.dom.json" }, diff --git a/common/web/keyboard-processor/tsconfig.json b/common/web/keyboard-processor/tsconfig.json index d4c06e2aaa6..d83a2043485 100644 --- a/common/web/keyboard-processor/tsconfig.json +++ b/common/web/keyboard-processor/tsconfig.json @@ -4,8 +4,8 @@ "compilerOptions": { "baseUrl": "./", "outDir": "build/obj/", - "tsBuildInfoFile": "build/obj/tsconfig.tsbuildinfo", - "rootDir": "./src" + "tsBuildInfoFile": "build/obj/src/tsconfig.tsbuildinfo", + "rootDir": "." }, "references": [ { "path": "../types" }, @@ -13,6 +13,9 @@ { "path": "../keyman-version/" }, { "path": "../utils/" } ], - "include": ["./src/**/*.ts"], + "include": [ + "./src/**/*.ts", + "./tests/dom/**/*.ts", + ], "exclude": ["./src/keyboards/loaders/**/*.ts"] } diff --git a/common/web/keyman-version/tsconfig.json b/common/web/keyman-version/tsconfig.json index a5808c432ee..6fc1db1b8d1 100644 --- a/common/web/keyman-version/tsconfig.json +++ b/common/web/keyman-version/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "./build", - "target": "es5", + "target": "es6", "rootDir": "." }, diff --git a/common/web/lm-message-types/tsconfig.json b/common/web/lm-message-types/tsconfig.json index cc5fb2f861d..559b764980e 100644 --- a/common/web/lm-message-types/tsconfig.json +++ b/common/web/lm-message-types/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "build/", "sourceMap": true, "lib": ["es6"], - "target": "es5" + "target": "es6" }, "include": ["./*.ts"], "exclude": ["test.ts"] diff --git a/common/web/lm-worker/build-polyfiller.js b/common/web/lm-worker/build-polyfiller.js index 19780388363..41cec75ce7d 100644 --- a/common/web/lm-worker/build-polyfiller.js +++ b/common/web/lm-worker/build-polyfiller.js @@ -191,6 +191,6 @@ await esbuild.build({ // Do NOT enable - will break under Android 5.0 / Chrome 35 environments, likely through Chrome 42. // https://caniuse.com/mdn-javascript_builtins_function_name_configurable_true keepNames: false, - target: 'es5', + target: 'es6', outfile: minDestFile -}); \ No newline at end of file +}); diff --git a/common/web/lm-worker/build.sh b/common/web/lm-worker/build.sh index 0383a6fe3cb..5a07a49911f 100755 --- a/common/web/lm-worker/build.sh +++ b/common/web/lm-worker/build.sh @@ -47,29 +47,6 @@ function do_configure() { } function do_build() { - # Build worker with tsc first - tsc -b $builder_verbose || builder_die "Could not build worker." - - $bundle_cmd build/obj/worker-main.js \ - --out $INTERMEDIATE/worker-main.es5.js \ - --sourceRoot '@keymanapp/keyman/common/web/lm-worker/src/main' - - $SRCMAP_CLEANER \ - $INTERMEDIATE/worker-main.es5.js.map \ - $INTERMEDIATE/worker-main.es5.js.map \ - --clean - - $bundle_cmd build/obj/worker-main.js \ - --out $INTERMEDIATE/worker-main.min.es5.js \ - --minify \ - --profile build/filesize-profile.es5.log \ - --sourceRoot '@keymanapp/keyman/common/web/lm-worker/src/main' - - $SRCMAP_CLEANER \ - $INTERMEDIATE/worker-main.min.es5.js.map \ - $INTERMEDIATE/worker-main.min.es5.js.map \ - --clean - EXT_FLAGS= if builder_has_option --ci; then EXT_FLAGS=--ci @@ -78,16 +55,7 @@ function do_build() { # Declaration bundling. tsc --emitDeclarationOnly --outFile $INTERMEDIATE/worker-main.d.ts - echo "Preparing the polyfills + worker for script-embedding" - node build-polyfiller.js $INTERMEDIATE/worker-main.es5.js \ - --out $INTERMEDIATE/worker-main.polyfilled.es5.js - mkdir -p $LIB - node build-wrapper.js $INTERMEDIATE/worker-main.polyfilled.es5.js \ - --out $LIB/worker-main.wrapped.es5.js \ - --sourceMap - node build-wrapper.js $INTERMEDIATE/worker-main.polyfilled.es5.min.js \ - --out $LIB/worker-main.wrapped.es5.min.js # The ES6 target needs no polyfills - we go straight to the wrapped version. @@ -142,4 +110,4 @@ function do_test() { builder_run_action configure do_configure builder_run_action clean rm -rf build/ intermediate/ builder_run_action build do_build -builder_run_action test do_test \ No newline at end of file +builder_run_action test do_test diff --git a/common/web/lm-worker/package.json b/common/web/lm-worker/package.json index 1402fe5828b..9ebc26a4eb3 100644 --- a/common/web/lm-worker/package.json +++ b/common/web/lm-worker/package.json @@ -4,14 +4,12 @@ "main": "./build/lib/worker-main.wrapped.js", "exports": { "./worker-main.wrapped.js": { - "es6-bundling": "./build/lib/worker-main.wrapped.js", "types": "./build/lib/worker-main.wrapped.d.ts", - "default": "./build/lib/worker-main.wrapped.es5.js" + "default": "./build/lib/worker-main.wrapped.js" }, "./worker-main.wrapped.min.js": { - "es6-bundling": "./build/lib/worker-main.wrapped.min.js", "types": "./build/lib/worker-main.wrapped.d.ts", - "default": "./build/lib/worker-main.wrapped.es5.min.js" + "default": "./build/lib/worker-main.wrapped.min.js" } }, "imports": { diff --git a/common/web/sentry-manager/src/index.ts b/common/web/sentry-manager/src/index.ts index f85b116bd3b..9d3b000b97c 100644 --- a/common/web/sentry-manager/src/index.ts +++ b/common/web/sentry-manager/src/index.ts @@ -28,8 +28,6 @@ export class KeymanSentryManager { static STANDARD_ALIASABLE_FILES = { 'keymanweb.js': 'keymanweb.js', 'keymanweb-webview.js': 'keymanweb-webview.js', - 'keymanweb.es5.js': 'keymanweb.es5.js', - 'keymanweb-webview.es5.js': 'keymanweb-webview.es5.js', 'kmwuibutton.js': 'kmwuibutton.js', 'kmwuifloat.js': 'kmwuifloat.js', 'kmwuitoggle.js': 'kmwuitoggle.js', @@ -186,8 +184,7 @@ export class KeymanSentryManager { * Capture errors and warnings logged to Console in order to get * stack traces. We can't use CaptureConsole integration until we * upgrade to a newer version of Sentry, which has a bit of a cascade - * of changes required, in particular a change of module type and - * transpiling down to ES5. + * of changes required, in particular a change of module type. * * https://stackoverflow.com/a/53214615/1836776 */ @@ -262,4 +259,4 @@ export class KeymanSentryManager { // Publish to the window. // @ts-ignore -window['KeymanSentryManager'] = KeymanSentryManager; \ No newline at end of file +window['KeymanSentryManager'] = KeymanSentryManager; diff --git a/common/web/tslib/README.md b/common/web/tslib/README.md deleted file mode 100644 index 4c87474f627..00000000000 --- a/common/web/tslib/README.md +++ /dev/null @@ -1,15 +0,0 @@ -The default import setup for the `tslib` package is unfortunately incompatible with `esbuild` when in ES5 mode. But... -with a little elbow grease, we can fix that with _this_ package by importing its ES5-compatible file and exporting it -as _this_ package's default export for use in anything looking to `"importHelpers"`. - -To utilize this with `esbuild` while enabling the `"importHelpers"` compilation option in your tsconfig.json, you'll want -to set the following in your `esbuild` config: - -```javascript - alias: { - 'tslib': '@keymanapp/tslib' - }, -``` - -Note that esbuild 0.15.16 is the minimum required version to utilize the 'alias' feature necessary to replace `tslib` for -`tsc`-generated `import { /* */ } from 'tslib'` statements that result from enabling `"importHelpers"` in a tsconfig. \ No newline at end of file diff --git a/common/web/tslib/build.sh b/common/web/tslib/build.sh deleted file mode 100755 index 30a770a0ddc..00000000000 --- a/common/web/tslib/build.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -## START STANDARD BUILD SCRIPT INCLUDE -# adjust relative paths as necessary -THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" -. "${THIS_SCRIPT%/*}/../../../resources/build/builder.inc.sh" -## END STANDARD BUILD SCRIPT INCLUDE - -. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" - -################################ Main script ################################ - -builder_describe \ - "A ES5 + esbuild compatibility wrapper for the 'tslib' package." \ - clean configure build - -builder_describe_outputs \ - configure "/node_modules" \ - build "/common/web/tslib/build/index.js" - -builder_parse "$@" - -builder_run_action configure verify_npm_setup -builder_run_action clean rm -rf build/ -builder_run_action build tsc --build \ No newline at end of file diff --git a/common/web/tslib/package.json b/common/web/tslib/package.json deleted file mode 100644 index 37516c730f6..00000000000 --- a/common/web/tslib/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@keymanapp/tslib", - "description": "An ES5 + esbuild-compatible wrapper for the 'tslib' library", - "main": "./build/index.js", - "exports": { - ".": { - "types": "./build/index.d.ts", - "import": "./build/index.js" - }, - "./esbuild-tools": { - "types": "./build/esbuild-tools.d.ts", - "import": "./build/esbuild-tools.js" - } - }, - "scripts": { - "build": "gosh ./build.sh build", - "clean": "gosh ./build.sh clean" - }, - "dependencies": { - "tslib": "^2.5.2", - "typescript": "^5.4.5" - }, - "devDependencies": { - "@keymanapp/resources-gosh": "*", - "esbuild": "^0.18.9" - }, - "type": "module" -} diff --git a/common/web/tslib/src/index.ts b/common/web/tslib/src/index.ts deleted file mode 100644 index 2f173ad83fa..00000000000 --- a/common/web/tslib/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from '../../../../node_modules/tslib/tslib.js'; - -export * as tslib from '../../../../node_modules/tslib/tslib.js'; \ No newline at end of file diff --git a/common/web/tslib/tsconfig.json b/common/web/tslib/tsconfig.json deleted file mode 100644 index c7528861ae4..00000000000 --- a/common/web/tslib/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../tsconfig.kmw-main-base.json", - "compilerOptions": { - "allowJs": true, - "importHelpers": false, // This project exists to help define the helpers for the other KMW components. - "tsBuildInfoFile": "./build/tsconfig.tsbuildinfo", - "lib": ["es6", "DOM"], // The latter is b/c esbuild expects the type. - - "baseUrl": "./src", - "outDir": "./build/", - "rootDir": "./src" - }, - "include": [ - "./src/*.ts" - ] -} diff --git a/common/web/types/src/deps/xml2js/parser.js b/common/web/types/src/deps/xml2js/parser.js index aa0101ea7d2..e7ca0e6cdc6 100644 --- a/common/web/types/src/deps/xml2js/parser.js +++ b/common/web/types/src/deps/xml2js/parser.js @@ -4,7 +4,7 @@ hasProp = {}.hasOwnProperty; import sax from 'sax'; -import { EventEmitter } from 'events'; +import { EventEmitter } from 'eventemitter3'; import * as bom from './bom.js'; import * as processors from './processors.js'; import { setImmediate } from 'timers'; diff --git a/common/web/types/src/util/util.ts b/common/web/types/src/util/util.ts index 5a0e6600a2a..7835743e62e 100644 --- a/common/web/types/src/util/util.ts +++ b/common/web/types/src/util/util.ts @@ -249,14 +249,14 @@ const Uni_PUA_16_END = 0x10FFFD; * @brief True if a lead surrogate * \def Uni_IsSurrogate1 */ -function Uni_IsSurrogate1(ch : number) { +export function Uni_IsSurrogate1(ch : number) { return ((ch) >= Uni_LEAD_SURROGATE_START && (ch) <= Uni_LEAD_SURROGATE_END); } /** * @brief True if a trail surrogate * \def Uni_IsSurrogate2 */ -function Uni_IsSurrogate2(ch : number) { +export function Uni_IsSurrogate2(ch : number) { return ((ch) >= Uni_TRAIL_SURROGATE_START && (ch) <= Uni_TRAIL_SURROGATE_END); } @@ -264,7 +264,7 @@ function Uni_IsSurrogate2(ch : number) { * @brief True if any surrogate * \def UniIsSurrogate */ -function Uni_IsSurrogate(ch : number) { +export function Uni_IsSurrogate(ch : number) { return (Uni_IsSurrogate1(ch) || Uni_IsSurrogate2(ch)); } diff --git a/common/web/utils/src/index.ts b/common/web/utils/src/index.ts index 1d1e540a80f..80ab33b1f52 100644 --- a/common/web/utils/src/index.ts +++ b/common/web/utils/src/index.ts @@ -21,8 +21,6 @@ export { default as extendString } from "./kmwstring.js"; export { default as ManagedPromise } from "./managedPromise.js"; export { default as TimeoutPromise, timedPromise } from "./timeoutPromise.js"; -export { Uni_IsSurrogate1, Uni_IsSurrogate2 } from "./surrogates.js"; - // // Uncomment the following line and run the bundled output to verify successful // // esbuild bundling of this submodule: -// console.log(Version.CURRENT.toString()); \ No newline at end of file +// console.log(Version.CURRENT.toString()); diff --git a/common/web/utils/src/surrogates.ts b/common/web/utils/src/surrogates.ts deleted file mode 100644 index 53c1a1e3fae..00000000000 --- a/common/web/utils/src/surrogates.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * The definitions below are duplicated from common/web/types/util/util.ts; - * we can't downcompile the originals to ES5 when bundling with esbuild. - * `import type` stuff is fine, but not non-type `import` statements. - * - * TODO: Use those instead, once we're no longer building ES5 versions of Web. - */ - -export const Uni_LEAD_SURROGATE_START = 0xD800; -export const Uni_LEAD_SURROGATE_END = 0xDBFF; -export const Uni_TRAIL_SURROGATE_START = 0xDC00; -export const Uni_TRAIL_SURROGATE_END = 0xDFFF; - -/** - * @brief True if a lead surrogate - * \def Uni_IsSurrogate1 - */ -export function Uni_IsSurrogate1(ch : number) { - return ((ch) >= Uni_LEAD_SURROGATE_START && (ch) <= Uni_LEAD_SURROGATE_END); -} -/** - * @brief True if a trail surrogate - * \def Uni_IsSurrogate2 - */ -export function Uni_IsSurrogate2(ch : number) { - return ((ch) >= Uni_TRAIL_SURROGATE_START && (ch) <= Uni_TRAIL_SURROGATE_END); -} diff --git a/package-lock.json b/package-lock.json index ecc6d702eb3..b11f71cd41e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -288,17 +288,6 @@ "typescript": "^5.4.5" } }, - "common/web/tslib": { - "name": "@keymanapp/tslib", - "dependencies": { - "tslib": "^2.5.2", - "typescript": "^5.4.5" - }, - "devDependencies": { - "@keymanapp/resources-gosh": "*", - "esbuild": "^0.18.9" - } - }, "common/web/types": { "name": "@keymanapp/common-types", "license": "MIT", @@ -2896,10 +2885,6 @@ "resolved": "common/tools/sourcemap-path-remapper", "link": true }, - "node_modules/@keymanapp/tslib": { - "resolved": "common/web/tslib", - "link": true - }, "node_modules/@keymanapp/web-sentry-manager": { "resolved": "common/web/sentry-manager", "link": true @@ -14391,7 +14376,6 @@ "@keymanapp/lexical-model-layer": "*", "@keymanapp/models-types": "*", "@keymanapp/recorder-core": "*", - "@keymanapp/tslib": "*", "@keymanapp/web-utils": "*", "core-js": "^3.34.0", "eventemitter3": "^5.0.0", diff --git a/web/build.sh b/web/build.sh index 2dd37a87adf..6739f5e5e9e 100755 --- a/web/build.sh +++ b/web/build.sh @@ -44,6 +44,8 @@ builder_describe_outputs \ builder_parse "$@" +BUNDLE_CMD="node ${KEYMAN_ROOT}/common/web/es-bundling/build/common-bundle.mjs" + #### Build action definitions #### ##################### TODO: call child action, verify things work as expected! @@ -62,8 +64,33 @@ builder_run_child_actions configure ## Build actions +precompile() { + local DIR + DIR="$1" + + # pre-compile bundle for use in DOM testing. When running in the browser several + # types built-in to Node aren't available, and @web/test-runner doesn't do + # treeshaking when loading the imports. We work around by pre-compiling. + for f in "${DIR}"/*.js; do + ${BUNDLE_CMD} "${f}" \ + --out "${f%.js}".mjs \ + --format esm + done +} + build_action() { tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json" + + for dir in \ + "${KEYMAN_ROOT}/web/build/test/dom/cases"/*/ \ + "${KEYMAN_ROOT}/web/build/test/integrated/" \ + "${KEYMAN_ROOT}/web/build/test/integrated/cases/"; + do + precompile "${dir}" + done + + cp "${KEYMAN_ROOT}/web/src/test/auto/dom/cases/attachment/outputTargetForElement.spec.html" \ + "${KEYMAN_ROOT}/web/build/test/dom/cases/attachment/" } test_action() { diff --git a/web/package.json b/web/package.json index 932aa226404..79ded888a4a 100644 --- a/web/package.json +++ b/web/package.json @@ -105,7 +105,6 @@ "@keymanapp/lexical-model-layer": "*", "@keymanapp/models-types": "*", "@keymanapp/recorder-core": "*", - "@keymanapp/tslib": "*", "@keymanapp/web-utils": "*", "core-js": "^3.34.0", "eventemitter3": "^5.0.0", diff --git a/web/src/app/browser/build.sh b/web/src/app/browser/build.sh index 03f533fa3c8..049bc056b5e 100755 --- a/web/src/app/browser/build.sh +++ b/web/src/app/browser/build.sh @@ -53,16 +53,6 @@ compile_and_copy() { BUILD_ROOT="${KEYMAN_ROOT}/web/build/app/browser" SRC_ROOT="${KEYMAN_ROOT}/web/src/app/browser/src" - $BUNDLE_CMD "${BUILD_ROOT}/obj/debug-main.js" \ - --out "${BUILD_ROOT}/debug/keymanweb.es5.js" \ - --sourceRoot "@keymanapp/keyman/web/build/app/browser/debug" - - $BUNDLE_CMD "${BUILD_ROOT}/obj/release-main.js" \ - --out "${BUILD_ROOT}/release/keymanweb.es5.js" \ - --profile "${BUILD_ROOT}/filesize-profile.es5.log" \ - --sourceRoot "@keymanapp/keyman/web/build/app/browser/release" \ - --minify - $BUNDLE_CMD "${SRC_ROOT}/debug-main.js" \ --out "${BUILD_ROOT}/debug/keymanweb.js" \ --sourceRoot "@keymanapp/keyman/web/build/app/browser/debug" \ @@ -89,9 +79,7 @@ compile_and_copy() { local PROFILE_DEST="$KEYMAN_ROOT/web/build/profiling/" mkdir -p "$PROFILE_DEST" cp "${BUILD_ROOT}/filesize-profile.log" "$PROFILE_DEST/web-engine-filesize.log" - cp "${BUILD_ROOT}/filesize-profile.es5.log" "$PROFILE_DEST/web-engine-filesize.es5.log" cp "$KEYMAN_ROOT/common/web/lm-worker/build/filesize-profile.log" "$PROFILE_DEST/lm-worker-filesize.log" - cp "$KEYMAN_ROOT/common/web/lm-worker/build/filesize-profile.es5.log" "$PROFILE_DEST/lm-worker-filesize.es5.log" } builder_run_action configure verify_npm_setup diff --git a/web/src/app/webview/build.sh b/web/src/app/webview/build.sh index 4ee541884a2..e22e1b470ef 100755 --- a/web/src/app/webview/build.sh +++ b/web/src/app/webview/build.sh @@ -43,16 +43,6 @@ compile_and_copy() { BUILD_ROOT="${KEYMAN_ROOT}/web/build/app/webview" SRC_ROOT="${KEYMAN_ROOT}/web/src/app/webview/src" - $BUNDLE_CMD "${BUILD_ROOT}/obj/debug-main.js" \ - --out "${BUILD_ROOT}/debug/keymanweb-webview.es5.js" \ - --sourceRoot "@keymanapp/keyman/web/build/app/webview/debug" - - $BUNDLE_CMD "${BUILD_ROOT}/obj/release-main.js" \ - --out "${BUILD_ROOT}/release/keymanweb-webview.es5.js" \ - --profile "${BUILD_ROOT}/filesize-profile.es5.log" \ - --sourceRoot "@keymanapp/keyman/web/build/app/webview/release" \ - --minify - $BUNDLE_CMD "${SRC_ROOT}/debug-main.js" \ --out "${BUILD_ROOT}/debug/keymanweb-webview.js" \ --sourceRoot "@keymanapp/keyman/web/build/app/webview/debug" \ diff --git a/web/src/test/auto/dom/cases/attachment/outputTargetForElement.spec.html b/web/src/test/auto/dom/cases/attachment/outputTargetForElement.spec.html index 2915969cbd7..c58095bb426 100644 --- a/web/src/test/auto/dom/cases/attachment/outputTargetForElement.spec.html +++ b/web/src/test/auto/dom/cases/attachment/outputTargetForElement.spec.html @@ -4,7 +4,7 @@ import { runTests } from '@web/test-runner-mocha'; runTests(async() => { - await import('./outputTargetForElement.def.ts'); + await import('./outputTargetForElement.def.mjs'); }); diff --git a/web/src/test/auto/dom/web-test-runner.config.mjs b/web/src/test/auto/dom/web-test-runner.config.mjs index f3355431fee..1cd8ed0ca29 100644 --- a/web/src/test/auto/dom/web-test-runner.config.mjs +++ b/web/src/test/auto/dom/web-test-runner.config.mjs @@ -21,7 +21,7 @@ export default { ], concurrency: 10, nodeResolve: true, - // // Top-level, implicit 'default' group + // Top-level, implicit 'default' group files: [ 'src/test/auto/dom/test_init_check.spec.ts', // '**/*.spec.html' @@ -31,34 +31,34 @@ export default { name: 'engine/attachment', // Relative, from the containing package.json files: [ - 'src/test/auto/dom/cases/attachment/**/*.spec.html', - 'src/test/auto/dom/cases/attachment/**/*.spec.ts' + 'build/test/dom/cases/attachment/**/*.spec.html', + 'build/test/dom/cases/attachment/**/*.spec.mjs' ] }, { name: 'app/browser', // Relative, from the containing package.json - files: ['src/test/auto/dom/cases/browser/**/*.spec.ts'] + files: ['build/test/dom/cases/browser/**/*.spec.mjs'] }, { name: 'engine/dom-utils', // Relative, from the containing package.json - files: ['src/test/auto/dom/cases/dom-utils/**/*.spec.ts'] + files: ['build/test/dom/cases/dom-utils/**/*.spec.mjs'] }, { name: 'engine/element-wrappers', // Relative, from the containing package.json - files: ['src/test/auto/dom/cases/element-wrappers/**/*.spec.ts'] + files: ['build/test/dom/cases/element-wrappers/**/*.spec.mjs'] }, { name: 'engine/osk', // Relative, from the containing package.json - files: ['src/test/auto/dom/cases/osk/**/*.spec.ts'] + files: ['build/test/dom/cases/osk/**/*.spec.mjs'] }, { name: 'engine/package-cache', // Relative, from the containing package.json - files: ['src/test/auto/dom/cases/packages/**/*.spec.ts'] + files: ['build/test/dom/cases/packages/**/*.spec.mjs'] } ], middleware: [ diff --git a/web/src/test/auto/integrated/web-test-runner.config.mjs b/web/src/test/auto/integrated/web-test-runner.config.mjs index 2c769d20131..1637ea82d60 100644 --- a/web/src/test/auto/integrated/web-test-runner.config.mjs +++ b/web/src/test/auto/integrated/web-test-runner.config.mjs @@ -24,7 +24,7 @@ export default { concurrency: 10, nodeResolve: true, files: [ - 'src/test/auto/integrated/**/*.spec.ts', + 'build/test/integrated//**/*.spec.mjs', // '**/*.spec.html' ], middleware: [ diff --git a/web/src/test/auto/tsconfig.json b/web/src/test/auto/tsconfig.json index 43ac6a10762..f61a4f23a86 100644 --- a/web/src/test/auto/tsconfig.json +++ b/web/src/test/auto/tsconfig.json @@ -8,5 +8,9 @@ "rootDir": "." }, - "include": [ "headless/**/*.ts" ] + "include": [ + "dom/**/*.ts", + "headless/**/*.ts", + "integrated/**/*.ts" + ] } diff --git a/web/tsconfig.base.json b/web/tsconfig.base.json index e17b4deece9..d1deafecb60 100644 --- a/web/tsconfig.base.json +++ b/web/tsconfig.base.json @@ -8,7 +8,7 @@ "allowSyntheticDefaultImports": true, "lib": ["es6"], - "target": "es5", + "target": "es6", // Other settings - declaration files, sourcemapping, and other miscellaneous bits. "declaration": true, From 877cd9767d866f4bb4533a2124fa280f75444c01 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Thu, 4 Jul 2024 11:05:34 +0700 Subject: [PATCH 02/14] fix(common): add workaround for divergence of EventEmitter3 from node's version Node's version has special behavior for events named 'error' - if no handler, it auto-throws. EventEmitter3 does not include this. --- common/web/types/src/deps/xml2js/parser.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/web/types/src/deps/xml2js/parser.js b/common/web/types/src/deps/xml2js/parser.js index e7ca0e6cdc6..1c7f148d906 100644 --- a/common/web/types/src/deps/xml2js/parser.js +++ b/common/web/types/src/deps/xml2js/parser.js @@ -323,7 +323,11 @@ export class Parser extends EventEmitter { } catch (error1) { err = error1; if (!(this.saxParser.errThrown || this.saxParser.ended)) { - this.emit('error', err); + if(this.listenerCount('error') > 0) { + this.emit('error', err); + } else { + throw err; + } return this.saxParser.errThrown = true; } else if (this.saxParser.ended) { throw err; From 2d9d84773f3f493cad523d036f8519ac1786d275 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 4 Jul 2024 18:40:21 +0200 Subject: [PATCH 03/14] fix(web): add dependency output This fixes building all dependencies, e.g. when running `./build.sh test` which previously failed because it didn't build all necessary targets. --- web/build.sh | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/web/build.sh b/web/build.sh index 6739f5e5e9e..5f6c6b6c545 100755 --- a/web/build.sh +++ b/web/build.sh @@ -39,11 +39,32 @@ builder_describe "Builds engine modules for Keyman Engine for Web (KMW)." \ # Possible TODO? # "upload-symbols Uploads build product to Sentry for error report symbolification. Only defined for $DOC_BUILD_EMBED_WEB" \ -builder_describe_outputs \ - configure /node_modules - builder_parse "$@" +config=release +if builder_is_debug_build; then + config=debug +fi + +builder_describe_outputs \ + configure "/node_modules" \ + build "/web/build/test/dom/cases/attachment/outputTargetForElement.spec.html" \ + build:app/browser "/web/build/app/browser/lib/index.mjs" \ + build:app/WebViews "/web/build/app/webview/${config}/keymanweb-webview.js" \ + build:app/ui "/web/build/app/ui/${config}/kmwuitoggle.js" \ + build:engine/attachment "/web/build/engine/attachment/lib/index.mjs" \ + build:engine/device-detect "/web/build/engine/device-detect/lib/index.mjs" \ + build:engine/dom-utils "/web/build/engine/dom-utils/obj/index.js" \ + build:engine/events "/web/build/engine/events/lib/index.mjs" \ + build:engine/element-wrappers "/web/build/engine/element-wrappers/lib/index.mjs" \ + build:engine/main "/web/build/engine/main/lib/index.mjs" \ + build:engine/osk "/web/build/engine/osk/lib/index.mjs" \ + build:engine/package-cache "/web/build/engine/package-cache/lib/index.mjs" \ + build:engine/paths "/web/build/engine/paths/lib/index.mjs" \ + build:samples "/web/src/samples/simplest/keymanweb.js" \ + build:tools "/web/build/tools/building/sourcemap-root/index.js" \ + build:test-pages "/web/build/test-resources/sentry-manager.js" + BUNDLE_CMD="node ${KEYMAN_ROOT}/common/web/es-bundling/build/common-bundle.mjs" #### Build action definitions #### @@ -68,6 +89,8 @@ precompile() { local DIR DIR="$1" + builder_echo "Pre-compiling ${DIR}..." + # pre-compile bundle for use in DOM testing. When running in the browser several # types built-in to Node aren't available, and @web/test-runner doesn't do # treeshaking when loading the imports. We work around by pre-compiling. @@ -79,6 +102,7 @@ precompile() { } build_action() { + builder_echo "Building auto tests..." tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json" for dir in \ From 918b7ab233069df6102f3c1948d2d6528d811b28 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 22 Jul 2024 17:52:16 +0200 Subject: [PATCH 04/14] Update web/build.sh Co-authored-by: Joshua Horton --- web/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/build.sh b/web/build.sh index 5f6c6b6c545..179ac250dc9 100755 --- a/web/build.sh +++ b/web/build.sh @@ -50,7 +50,7 @@ builder_describe_outputs \ configure "/node_modules" \ build "/web/build/test/dom/cases/attachment/outputTargetForElement.spec.html" \ build:app/browser "/web/build/app/browser/lib/index.mjs" \ - build:app/WebViews "/web/build/app/webview/${config}/keymanweb-webview.js" \ + build:app/webview "/web/build/app/webview/${config}/keymanweb-webview.js" \ build:app/ui "/web/build/app/ui/${config}/kmwuitoggle.js" \ build:engine/attachment "/web/build/engine/attachment/lib/index.mjs" \ build:engine/device-detect "/web/build/engine/device-detect/lib/index.mjs" \ From 9de6818ed58d3e4afac45012db6aa9801170bec8 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 25 Jun 2024 19:12:52 +0200 Subject: [PATCH 05/14] chore(web): output different build steps for keyboard-processor This makes it easier to see which part of the build fails. --- common/web/keyboard-processor/build.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/common/web/keyboard-processor/build.sh b/common/web/keyboard-processor/build.sh index 3455f924fc6..3cc0db75cfb 100755 --- a/common/web/keyboard-processor/build.sh +++ b/common/web/keyboard-processor/build.sh @@ -8,9 +8,9 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../../../resources/build/builder.inc.sh" ## END STANDARD BUILD SCRIPT INCLUDE -. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +. "${KEYMAN_ROOT}/resources/shellHelperFunctions.sh" -BUNDLE_CMD="node $KEYMAN_ROOT/common/web/es-bundling/build/common-bundle.mjs" +BUNDLE_CMD="node ${KEYMAN_ROOT}/common/web/es-bundling/build/common-bundle.mjs" ################################ Main script ################################ @@ -42,20 +42,23 @@ function do_configure() { } function do_build() { - tsc --build "$THIS_SCRIPT_PATH/tsconfig.all.json" + tsc --build "${THIS_SCRIPT_PATH}/tsconfig.all.json" # Base product - the main keyboard processor - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/index.js" \ + builder_echo "Bundle base product - the main keyboard processor" + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/index.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/index.mjs" \ --format esm # The DOM-oriented keyboard loader - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/dom-keyboard-loader.js" \ + builder_echo "Bundle the DOM-oriented keyboard loader" + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/dom-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/dom-keyboard-loader.mjs" \ --format esm # The Node-oriented keyboard loader - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/node-keyboard-loader.js" \ + builder_echo "Bundle the Node-oriented keyboard loader" + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/node-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/node-keyboard-loader.mjs" \ --format esm \ --platform node @@ -66,6 +69,7 @@ function do_build() { --format esm # Declaration bundling. + builder_echo "Declaration bundling" tsc --emitDeclarationOnly --outFile ./build/lib/index.d.ts tsc --emitDeclarationOnly --outFile ./build/lib/dom-keyboard-loader.d.ts -p src/keyboards/loaders/tsconfig.dom.json tsc --emitDeclarationOnly --outFile ./build/lib/node-keyboard-loader.d.ts -p src/keyboards/loaders/tsconfig.node.json From 6e41faec52ef5fa2e194ab2e0437aaa167fe8d34 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 22 Jul 2024 17:58:33 +0200 Subject: [PATCH 06/14] change(web): use different output directory for tests Put production module and test modules in different output subdirectories. This addresses code review comments. --- common/web/keyboard-processor/build.sh | 11 ++++++----- common/web/keyboard-processor/package.json | 16 ++++++++-------- .../src/keyboards/loaders/tsconfig.dom.json | 4 ++-- .../src/keyboards/loaders/tsconfig.node.json | 4 ++-- .../tests/dom/web-test-runner.config.mjs | 2 +- .../web/keyboard-processor/tests/tsconfig.json | 11 +++++++++++ common/web/keyboard-processor/tsconfig.all.json | 5 +++-- common/web/keyboard-processor/tsconfig.json | 9 +++------ 8 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 common/web/keyboard-processor/tests/tsconfig.json diff --git a/common/web/keyboard-processor/build.sh b/common/web/keyboard-processor/build.sh index 3cc0db75cfb..a7647983f9c 100755 --- a/common/web/keyboard-processor/build.sh +++ b/common/web/keyboard-processor/build.sh @@ -46,26 +46,27 @@ function do_build() { # Base product - the main keyboard processor builder_echo "Bundle base product - the main keyboard processor" - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/index.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/index.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/index.mjs" \ --format esm # The DOM-oriented keyboard loader builder_echo "Bundle the DOM-oriented keyboard loader" - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/dom-keyboard-loader.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/keyboards/loaders/dom-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/dom-keyboard-loader.mjs" \ --format esm # The Node-oriented keyboard loader builder_echo "Bundle the Node-oriented keyboard loader" - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/src/keyboards/loaders/node-keyboard-loader.js" \ + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/keyboards/loaders/node-keyboard-loader.js" \ --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/node-keyboard-loader.mjs" \ --format esm \ --platform node # Tests - ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/obj/tests/dom/cases/domKeyboardLoader.spec.js" \ - --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/lib/ndomKeyboardLoader.spec.mjs" \ + builder_echo "Bundle tests" + ${BUNDLE_CMD} "${KEYMAN_ROOT}/common/web/keyboard-processor/build/tests/dom/cases/domKeyboardLoader.spec.js" \ + --out "${KEYMAN_ROOT}/common/web/keyboard-processor/build/tests/dom/domKeyboardLoader.spec.mjs" \ --format esm # Declaration bundling. diff --git a/common/web/keyboard-processor/package.json b/common/web/keyboard-processor/package.json index d26126388fe..3f0a5958970 100644 --- a/common/web/keyboard-processor/package.json +++ b/common/web/keyboard-processor/package.json @@ -35,22 +35,22 @@ "@keymanapp/web-utils": "*" }, "type": "module", - "main": "./build/obj/src/index.js", - "types": "./build/obj/src/index.d.ts", + "main": "./build/obj/index.js", + "types": "./build/obj/index.d.ts", "exports": { ".": { "es6-bundling": "./src/index.ts", - "default": "./build/obj/src/index.js" + "default": "./build/obj/index.js" }, "./node-keyboard-loader": { "es6-bundling": "./src/keyboards/loaders/node-keyboard-loader.ts", - "types": "./build/obj/src/keyboards/loaders/node-keyboard-loader.d.ts", - "import": "./build/obj/src/keyboards/loaders/node-keyboard-loader.js" + "types": "./build/obj/keyboards/loaders/node-keyboard-loader.d.ts", + "import": "./build/obj/keyboards/loaders/node-keyboard-loader.js" }, "./dom-keyboard-loader": { "es6-bundling": "./src/keyboards/loaders/dom-keyboard-loader.ts", - "types": "./build/obj/src/keyboards/loaders/dom-keyboard-loader.d.ts", - "import": "./build/obj/src/keyboards/loaders/dom-keyboard-loader.js" + "types": "./build/obj/keyboards/loaders/dom-keyboard-loader.d.ts", + "import": "./build/obj/keyboards/loaders/dom-keyboard-loader.js" }, "./lib": { "types": "./build/lib/index.d.ts", @@ -64,6 +64,6 @@ "types": "./build/lib/dom-keyboard-loader.d.ts", "import": "./build/lib/dom-keyboard-loader.mjs" }, - "./obj/*.js": "./build/obj/src/*.js" + "./obj/*.js": "./build/obj/*.js" } } diff --git a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json index ac48667fd70..7ba2abe026a 100644 --- a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json +++ b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.dom.json @@ -2,8 +2,8 @@ "extends": "../../../../tsconfig.kmw-main-base.json", "compilerOptions": { "baseUrl": "../../../", - "outDir": "../../../build/obj/src/keyboards/loaders/", - "tsBuildInfoFile": "../../../build/obj/src/keyboards/loaders/tsconfig.dom.tsbuildinfo", + "outDir": "../../../build/obj/keyboards/loaders/", + "tsBuildInfoFile": "../../../build/obj/keyboards/loaders/tsconfig.dom.tsbuildinfo", "rootDir": "." }, "references": [ diff --git a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json index 0e15eea6b00..0be3f169ad3 100644 --- a/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json +++ b/common/web/keyboard-processor/src/keyboards/loaders/tsconfig.node.json @@ -3,8 +3,8 @@ "compilerOptions": { "types": [ "node" ], "baseUrl": "../../../", - "outDir": "../../../build/obj/src/keyboards/loaders/", - "tsBuildInfoFile": "../../../build/obj/src/keyboards/loaders/tsconfig.node.tsbuildinfo", + "outDir": "../../../build/obj/keyboards/loaders/", + "tsBuildInfoFile": "../../../build/obj/keyboards/loaders/tsconfig.node.tsbuildinfo", "rootDir": "." }, "references": [ diff --git a/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs b/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs index 9fd8f1344ba..76651182acb 100644 --- a/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs +++ b/common/web/keyboard-processor/tests/dom/web-test-runner.config.mjs @@ -21,7 +21,7 @@ export default { concurrency: 10, nodeResolve: true, files: [ - 'build/lib/**/*.spec.mjs' + 'build/tests/dom/**/*.spec.mjs' ], middleware: [ // Rewrites short-hand paths for test resources, making them fully relative to the repo root. diff --git a/common/web/keyboard-processor/tests/tsconfig.json b/common/web/keyboard-processor/tests/tsconfig.json new file mode 100644 index 00000000000..0e978545b81 --- /dev/null +++ b/common/web/keyboard-processor/tests/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "baseUrl": "../", + "outDir": "../build/tests/", + "tsBuildInfoFile": "../build/tests/tsconfig.tsbuildinfo", + "rootDir": "./" + }, + "include": [ "./dom/**/*.ts"], + "exclude": [] +} diff --git a/common/web/keyboard-processor/tsconfig.all.json b/common/web/keyboard-processor/tsconfig.all.json index 40a93648668..dabb262d9cb 100644 --- a/common/web/keyboard-processor/tsconfig.all.json +++ b/common/web/keyboard-processor/tsconfig.all.json @@ -4,11 +4,12 @@ "baseUrl": "./", "outDir": "build/obj/", "tsBuildInfoFile": "build/obj/tsconfig.all.tsbuildinfo", - "rootDir": "." + "rootDir": "./src/" }, "references": [ { "path": "./src/keyboards/loaders/tsconfig.dom.json" }, - { "path": "./src/keyboards/loaders/tsconfig.node.json" } + { "path": "./src/keyboards/loaders/tsconfig.node.json" }, + { "path": "./tests/tsconfig.json" }, ], // Actual main-body compilation is in tsconfig.json. This config is just a wrapper // to trigger all three components at once. diff --git a/common/web/keyboard-processor/tsconfig.json b/common/web/keyboard-processor/tsconfig.json index d83a2043485..728935b74f6 100644 --- a/common/web/keyboard-processor/tsconfig.json +++ b/common/web/keyboard-processor/tsconfig.json @@ -4,8 +4,8 @@ "compilerOptions": { "baseUrl": "./", "outDir": "build/obj/", - "tsBuildInfoFile": "build/obj/src/tsconfig.tsbuildinfo", - "rootDir": "." + "tsBuildInfoFile": "build/obj/tsconfig.tsbuildinfo", + "rootDir": "./src/" }, "references": [ { "path": "../types" }, @@ -13,9 +13,6 @@ { "path": "../keyman-version/" }, { "path": "../utils/" } ], - "include": [ - "./src/**/*.ts", - "./tests/dom/**/*.ts", - ], + "include": [ "./src/**/*.ts"], "exclude": ["./src/keyboards/loaders/**/*.ts"] } From 98691e5759bd5d1d44a68c269aa7e8bfdf6b3974 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 22 Jul 2024 19:29:19 +0200 Subject: [PATCH 07/14] change(web): improve casts Addresses code review comment. --- .../tests/dom/cases/domKeyboardLoader.spec.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts index 0254b6a4c0f..560608504d9 100644 --- a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts +++ b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts @@ -3,6 +3,10 @@ import { assert } from 'chai'; import { DOMKeyboardLoader } from '@keymanapp/keyboard-processor/dom-keyboard-loader'; import { extendString, KeyboardHarness, Keyboard, KeyboardInterface, MinimalKeymanGlobal, Mock, DeviceSpec } from '@keymanapp/keyboard-processor'; +type WindowKey = keyof typeof window; +const keyman_window = 'keyman' as WindowKey; +const KeymanWeb = 'KeymanWeb' as WindowKey; + // Note: rule processing tests will fail if string extensions are not established beforehand. extendString(); @@ -15,8 +19,8 @@ const device: DeviceSpec = { describe('Keyboard loading in DOM', function() { afterEach(() => { - if(window['KeymanWeb' as any]) { - (window['KeymanWeb' as any] as any).uninstall(); + if (window[KeymanWeb]) { + (window[KeymanWeb] as KeyboardInterface).uninstall(); } }) @@ -29,8 +33,8 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window['KeymanWeb' as any]); - assert.isOk(window['keyman' as any]); + assert.isOk(window[KeymanWeb]); + assert.isOk(window[keyman_window]); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); @@ -46,8 +50,8 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window['KeymanWeb' as any]); - assert.isOk(window['keyman' as any]); + assert.isOk(window[KeymanWeb]); + assert.isOk(window[keyman_window]); // TODO: verify actual rule processing. const nullKeyEvent = keyboard.constructNullKeyEvent(device); @@ -55,8 +59,8 @@ describe('Keyboard loading in DOM', function() { const result = harness.processKeystroke(mock, nullKeyEvent); assert.isOk(result); - assert.isOk(window['KeymanWeb' as any]); - assert.isOk(window['keyman' as any]); + assert.isOk(window[KeymanWeb]); + assert.isOk(window[keyman_window]); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); From 852b8e83f4c2877a5bb2f2b46589e6b662346e09 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 23 Jul 2024 08:23:31 +0700 Subject: [PATCH 08/14] chore(web): improve auto-test references to globals in #11881 --- .../tests/dom/cases/domKeyboardLoader.spec.ts | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts index 560608504d9..9570f747b8f 100644 --- a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts +++ b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts @@ -1,11 +1,13 @@ import { assert } from 'chai'; import { DOMKeyboardLoader } from '@keymanapp/keyboard-processor/dom-keyboard-loader'; -import { extendString, KeyboardHarness, Keyboard, KeyboardInterface, MinimalKeymanGlobal, Mock, DeviceSpec } from '@keymanapp/keyboard-processor'; +import { extendString, KeyboardHarness, Keyboard, KeyboardInterface, MinimalKeymanGlobal, Mock, DeviceSpec, KeyboardKeymanGlobal } from '@keymanapp/keyboard-processor'; -type WindowKey = keyof typeof window; -const keyman_window = 'keyman' as WindowKey; -const KeymanWeb = 'KeymanWeb' as WindowKey; +declare let window: typeof globalThis; +// KeymanEngine from the web/ folder... when available. +// At this level, though... we just mock it. +declare let keyman: KeyboardKeymanGlobal; +declare let KeymanWeb: KeyboardInterface; // Note: rule processing tests will fail if string extensions are not established beforehand. extendString(); @@ -19,8 +21,8 @@ const device: DeviceSpec = { describe('Keyboard loading in DOM', function() { afterEach(() => { - if (window[KeymanWeb]) { - (window[KeymanWeb] as KeyboardInterface).uninstall(); + if (KeymanWeb) { + (KeymanWeb as KeyboardInterface).uninstall(); } }) @@ -33,8 +35,10 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window[KeymanWeb]); - assert.isOk(window[keyman_window]); + assert.isOk(KeymanWeb); + assert.isOk(keyman); + assert.isOk(keyman.osk); + assert.isOk(keyman.osk.keyCodes); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); @@ -50,8 +54,10 @@ describe('Keyboard loading in DOM', function() { assert.equal(keyboard.id, 'Keyboard_khmer_angkor'); assert.isTrue(keyboard.isChiral); assert.isFalse(keyboard.isCJK); - assert.isOk(window[KeymanWeb]); - assert.isOk(window[keyman_window]); + assert.isOk(KeymanWeb); + assert.isOk(keyman); + assert.isOk(keyman.osk); + assert.isOk(keyman.osk.keyCodes); // TODO: verify actual rule processing. const nullKeyEvent = keyboard.constructNullKeyEvent(device); @@ -59,8 +65,10 @@ describe('Keyboard loading in DOM', function() { const result = harness.processKeystroke(mock, nullKeyEvent); assert.isOk(result); - assert.isOk(window[KeymanWeb]); - assert.isOk(window[keyman_window]); + assert.isOk(KeymanWeb); + assert.isOk(keyman); + assert.isOk(keyman.osk); + assert.isOk(keyman.osk.keyCodes); // Should be cleared post-keyboard-load. assert.isNotOk(harness.loadedKeyboard); From 1945965d8adaa91f63fdd51d2a7a850dd8d907b2 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Tue, 23 Jul 2024 12:24:22 +0700 Subject: [PATCH 09/14] chore(web): apply suggestion Co-authored-by: Marc Durdin --- .../tests/dom/cases/domKeyboardLoader.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts index 9570f747b8f..1965adc8534 100644 --- a/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts +++ b/common/web/keyboard-processor/tests/dom/cases/domKeyboardLoader.spec.ts @@ -22,7 +22,7 @@ const device: DeviceSpec = { describe('Keyboard loading in DOM', function() { afterEach(() => { if (KeymanWeb) { - (KeymanWeb as KeyboardInterface).uninstall(); + KeymanWeb.uninstall(); } }) From 5552fdd5adea94c63fb231595519f0c8416944ef Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 24 Jul 2024 15:52:50 +0200 Subject: [PATCH 10/14] chore(web): expose `util.ts` as separate sub-export The exports of the `util.ts` can now be imported as `@keymanapp/common-types/utils`. Those methods are used by developer. We still export the `Uni_IsSurrogate*` methods in `main.js` because they are needed by the keyboard-processor, but exporting everything would increase the size of the resulting `keymanweb.js`. Doing it this way keeps the size the same. --- .../keyboard-processor/src/text/stringDivergence.ts | 6 +++--- common/web/types/package.json | 4 ++++ common/web/types/src/kmx/element-string.ts | 3 ++- .../web/types/src/ldml-keyboard/pattern-parser.ts | 3 ++- common/web/types/src/main.ts | 2 +- common/web/types/src/util/consts.ts | 12 ++++++++++++ common/web/types/src/util/index.ts | 2 ++ common/web/types/src/util/util.ts | 13 +------------ .../src/kmc-ldml/src/compiler/empty-compiler.ts | 3 ++- developer/src/kmc-ldml/src/compiler/messages.ts | 3 ++- developer/src/kmc-ldml/src/compiler/tran.ts | 3 ++- 11 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 common/web/types/src/util/consts.ts create mode 100644 common/web/types/src/util/index.ts diff --git a/common/web/keyboard-processor/src/text/stringDivergence.ts b/common/web/keyboard-processor/src/text/stringDivergence.ts index 31a94d8bdb9..f45ea9f3dfa 100644 --- a/common/web/keyboard-processor/src/text/stringDivergence.ts +++ b/common/web/keyboard-processor/src/text/stringDivergence.ts @@ -1,4 +1,4 @@ -import { util } from '@keymanapp/common-types'; +import { Uni_IsSurrogate1, Uni_IsSurrogate2 } from '@keymanapp/common-types'; /** * Returns the index for the code point divergence point between two strings, as measured in code @@ -72,8 +72,8 @@ export function findCommonSubstringEndIndex(str1: string, str2: string, commonSu const divergentChar1 = str1.charCodeAt(index); const divergentChar2 = str2.charCodeAt(index + offset); - const commonSurrogateChecker = commonSuffix ? util.Uni_IsSurrogate2 : util.Uni_IsSurrogate1; - const divergentSurrogateChecker = commonSuffix ? util.Uni_IsSurrogate1 : util.Uni_IsSurrogate2; + const commonSurrogateChecker = commonSuffix ? Uni_IsSurrogate2 : Uni_IsSurrogate1; + const divergentSurrogateChecker = commonSuffix ? Uni_IsSurrogate1 : Uni_IsSurrogate2; // If the last common character if of the direction-appropriate surrogate type (for // comprising a potential split surrogate pair representing a non-BMP char)... diff --git a/common/web/types/package.json b/common/web/types/package.json index 9327e485900..4d41b42e6e1 100644 --- a/common/web/types/package.json +++ b/common/web/types/package.json @@ -12,6 +12,10 @@ ".": { "es6-bundling": "./src/main.ts", "default": "./build/src/main.js" + }, + "./utils": { + "es6-bundling": "./src/util/index.ts", + "default": "./build/src/util/index.js" } }, "files": [ diff --git a/common/web/types/src/kmx/element-string.ts b/common/web/types/src/kmx/element-string.ts index b26878f459e..1b24c3eb450 100644 --- a/common/web/types/src/kmx/element-string.ts +++ b/common/web/types/src/kmx/element-string.ts @@ -1,7 +1,8 @@ import { constants } from '@keymanapp/ldml-keyboard-constants'; import { DependencySections, StrsItem, UsetItem } from './kmx-plus.js'; import { ElementParser, ElementSegment, ElementType } from '../ldml-keyboard/pattern-parser.js'; -import { MATCH_HEX_ESCAPE, unescapeOneQuadString } from '../util/util.js'; +import { MATCH_HEX_ESCAPE } from '../util/consts.js'; +import { unescapeOneQuadString } from '../util/util.js'; export enum ElemElementFlags { none = 0, diff --git a/common/web/types/src/ldml-keyboard/pattern-parser.ts b/common/web/types/src/ldml-keyboard/pattern-parser.ts index 8901de6dddf..3e56096ec67 100644 --- a/common/web/types/src/ldml-keyboard/pattern-parser.ts +++ b/common/web/types/src/ldml-keyboard/pattern-parser.ts @@ -3,7 +3,8 @@ */ import { constants } from "@keymanapp/ldml-keyboard-constants"; -import { MATCH_QUAD_ESCAPE, isOneChar, unescapeOneQuadString, unescapeString, hexQuad } from "../util/util.js"; +import { MATCH_QUAD_ESCAPE } from "../util/consts.js"; +import { isOneChar, unescapeOneQuadString, unescapeString, hexQuad } from "../util/util.js"; /** * Helper function for extracting matched items diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 3d18812876c..92e3397c486 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -50,7 +50,7 @@ export { KeymanDeveloperProject, KeymanDeveloperProjectFile, KeymanDeveloperProj export * as KpsFile from './package/kps-file.js'; export * as KmpJsonFile from './package/kmp-json-file.js'; -export * as util from './util/util.js'; +export { Uni_IsSurrogate1, Uni_IsSurrogate2 } from './util/util.js'; export * as KeymanFileTypes from './util/file-types.js'; diff --git a/common/web/types/src/util/consts.ts b/common/web/types/src/util/consts.ts new file mode 100644 index 00000000000..271b3aa6bc7 --- /dev/null +++ b/common/web/types/src/util/consts.ts @@ -0,0 +1,12 @@ +// TODO-LDML: #7569 the below regex works, but captures more than it should +// (it would include \u{fffffffffffffffff } which +// is overlong and has a space at the end.) The second regex does not work yet. +export const MATCH_HEX_ESCAPE = /\\u{([0-9a-fA-F ]{1,})}/g; +// const MATCH_HEX_ESCAPE = /\\u{((?:(?:[0-9a-fA-F]{1,5})|(?:10[0-9a-fA-F]{4})(?: (?!}))?)+)}/g; + +/** regex for single quad escape such as \u0127 or \U00000000 */ +export const CONTAINS_QUAD_ESCAPE = /(?:\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{8}))/; + +/** regex for single quad escape such as \u0127 */ +export const MATCH_QUAD_ESCAPE = new RegExp(CONTAINS_QUAD_ESCAPE, 'g'); + diff --git a/common/web/types/src/util/index.ts b/common/web/types/src/util/index.ts new file mode 100644 index 00000000000..0833d3dd06d --- /dev/null +++ b/common/web/types/src/util/index.ts @@ -0,0 +1,2 @@ +export * from './consts.js'; +export * from './util.js'; diff --git a/common/web/types/src/util/util.ts b/common/web/types/src/util/util.ts index 7835743e62e..c5f082328a7 100644 --- a/common/web/types/src/util/util.ts +++ b/common/web/types/src/util/util.ts @@ -1,3 +1,4 @@ +import { MATCH_HEX_ESCAPE, MATCH_QUAD_ESCAPE } from './consts.js'; /** * xml2js will not place single-entry objects into arrays. Easiest way to fix * this is to box them ourselves as needed. Ensures that o.x is an array. @@ -16,18 +17,6 @@ export function boxXmlArray(o: any, x: string): void { } } -// TODO-LDML: #7569 the below regex works, but captures more than it should -// (it would include \u{fffffffffffffffff } which -// is overlong and has a space at the end.) The second regex does not work yet. -export const MATCH_HEX_ESCAPE = /\\u{([0-9a-fA-F ]{1,})}/g; -// const MATCH_HEX_ESCAPE = /\\u{((?:(?:[0-9a-fA-F]{1,5})|(?:10[0-9a-fA-F]{4})(?: (?!}))?)+)}/g; - -/** regex for single quad escape such as \u0127 or \U00000000 */ -export const CONTAINS_QUAD_ESCAPE = /(?:\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{8}))/; - -/** regex for single quad escape such as \u0127 */ -export const MATCH_QUAD_ESCAPE = new RegExp(CONTAINS_QUAD_ESCAPE, 'g'); - export class UnescapeError extends Error { } diff --git a/developer/src/kmc-ldml/src/compiler/empty-compiler.ts b/developer/src/kmc-ldml/src/compiler/empty-compiler.ts index 911e56d8961..7d39545ce30 100644 --- a/developer/src/kmc-ldml/src/compiler/empty-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/empty-compiler.ts @@ -1,6 +1,7 @@ import { SectionIdent, constants } from '@keymanapp/ldml-keyboard-constants'; import { SectionCompiler } from "./section-compiler.js"; -import { LDMLKeyboard, KMXPlus, CompilerCallbacks, util, MarkerParser } from "@keymanapp/common-types"; +import { LDMLKeyboard, KMXPlus, CompilerCallbacks, MarkerParser } from "@keymanapp/common-types"; +import * as util from '@keymanapp/common-types/utils'; import { VarsCompiler } from './vars.js'; import { CompilerMessages } from './messages.js'; diff --git a/developer/src/kmc-ldml/src/compiler/messages.ts b/developer/src/kmc-ldml/src/compiler/messages.ts index aefd106ae44..4e1794dae45 100644 --- a/developer/src/kmc-ldml/src/compiler/messages.ts +++ b/developer/src/kmc-ldml/src/compiler/messages.ts @@ -1,4 +1,5 @@ -import { util, CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from "@keymanapp/common-types"; +import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from "@keymanapp/common-types"; +import * as util from '@keymanapp/common-types/utils'; // const SevInfo = CompilerErrorSeverity.Info | CompilerErrorNamespace.LdmlKeyboardCompiler; const SevHint = CompilerErrorSeverity.Hint | CompilerErrorNamespace.LdmlKeyboardCompiler; const SevWarn = CompilerErrorSeverity.Warn | CompilerErrorNamespace.LdmlKeyboardCompiler; diff --git a/developer/src/kmc-ldml/src/compiler/tran.ts b/developer/src/kmc-ldml/src/compiler/tran.ts index 7ddffd47471..64bc7a7c397 100644 --- a/developer/src/kmc-ldml/src/compiler/tran.ts +++ b/developer/src/kmc-ldml/src/compiler/tran.ts @@ -1,5 +1,6 @@ import { constants, SectionIdent } from "@keymanapp/ldml-keyboard-constants"; -import { KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser, MarkerParser, util } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser, MarkerParser } from '@keymanapp/common-types'; +import * as util from '@keymanapp/common-types/utils'; import { SectionCompiler } from "./section-compiler.js"; import Bksp = KMXPlus.Bksp; From eb9205f46e26a6b41a279fd1c5e8d41c026f249e Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 24 Jul 2024 18:42:53 +0200 Subject: [PATCH 11/14] chore(web): fix build Missed one occurrence of `util`... --- developer/src/kmc-ldml/test/helpers/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index 2e9e16ff6af..3b4a23116e0 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -5,7 +5,8 @@ import 'mocha'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler, SectionCompilerNew } from '../../src/compiler/section-compiler.js'; -import { util, KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, compilerEventFormat, LDMLKeyboard, UnicodeSetParser, CompilerCallbacks } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, compilerEventFormat, LDMLKeyboard, UnicodeSetParser, CompilerCallbacks } from '@keymanapp/common-types'; +import * as util from '@keymanapp/common-types/utils'; import { LdmlKeyboardCompiler } from '../../src/main.js'; // make sure main.js compiles import { assert } from 'chai'; import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; From 02170dd0625763c5e3f4a89f19e26ff9dc8a654f Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 25 Jul 2024 12:28:11 +0200 Subject: [PATCH 12/14] chore(web): update common/web/types/src/main.ts Co-authored-by: Joshua Horton --- common/web/types/src/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 92e3397c486..0ddee928c29 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -51,6 +51,7 @@ export * as KpsFile from './package/kps-file.js'; export * as KmpJsonFile from './package/kmp-json-file.js'; export { Uni_IsSurrogate1, Uni_IsSurrogate2 } from './util/util.js'; +export * as util from './util/util.js'; export * as KeymanFileTypes from './util/file-types.js'; From fd8ffb5efce0279b93dec473de2966254715db65 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 29 Jul 2024 17:43:34 +0200 Subject: [PATCH 13/14] chore(web): don't deep import and remove sub-export of util Addresses code review comments and reverts eb9205f46e and partially reverts 5552fdd5ad. --- common/web/types/package.json | 4 ---- common/web/types/src/util/index.ts | 2 -- developer/src/kmc-ldml/src/compiler/empty-compiler.ts | 3 +-- developer/src/kmc-ldml/src/compiler/messages.ts | 3 +-- developer/src/kmc-ldml/src/compiler/tran.ts | 3 +-- developer/src/kmc-ldml/test/helpers/index.ts | 3 +-- 6 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 common/web/types/src/util/index.ts diff --git a/common/web/types/package.json b/common/web/types/package.json index 4d41b42e6e1..9327e485900 100644 --- a/common/web/types/package.json +++ b/common/web/types/package.json @@ -12,10 +12,6 @@ ".": { "es6-bundling": "./src/main.ts", "default": "./build/src/main.js" - }, - "./utils": { - "es6-bundling": "./src/util/index.ts", - "default": "./build/src/util/index.js" } }, "files": [ diff --git a/common/web/types/src/util/index.ts b/common/web/types/src/util/index.ts deleted file mode 100644 index 0833d3dd06d..00000000000 --- a/common/web/types/src/util/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './consts.js'; -export * from './util.js'; diff --git a/developer/src/kmc-ldml/src/compiler/empty-compiler.ts b/developer/src/kmc-ldml/src/compiler/empty-compiler.ts index 7d39545ce30..71d0278ef5b 100644 --- a/developer/src/kmc-ldml/src/compiler/empty-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/empty-compiler.ts @@ -1,7 +1,6 @@ import { SectionIdent, constants } from '@keymanapp/ldml-keyboard-constants'; import { SectionCompiler } from "./section-compiler.js"; -import { LDMLKeyboard, KMXPlus, CompilerCallbacks, MarkerParser } from "@keymanapp/common-types"; -import * as util from '@keymanapp/common-types/utils'; +import { util, LDMLKeyboard, KMXPlus, CompilerCallbacks, MarkerParser } from "@keymanapp/common-types"; import { VarsCompiler } from './vars.js'; import { CompilerMessages } from './messages.js'; diff --git a/developer/src/kmc-ldml/src/compiler/messages.ts b/developer/src/kmc-ldml/src/compiler/messages.ts index 4e1794dae45..aefd106ae44 100644 --- a/developer/src/kmc-ldml/src/compiler/messages.ts +++ b/developer/src/kmc-ldml/src/compiler/messages.ts @@ -1,5 +1,4 @@ -import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from "@keymanapp/common-types"; -import * as util from '@keymanapp/common-types/utils'; +import { util, CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from "@keymanapp/common-types"; // const SevInfo = CompilerErrorSeverity.Info | CompilerErrorNamespace.LdmlKeyboardCompiler; const SevHint = CompilerErrorSeverity.Hint | CompilerErrorNamespace.LdmlKeyboardCompiler; const SevWarn = CompilerErrorSeverity.Warn | CompilerErrorNamespace.LdmlKeyboardCompiler; diff --git a/developer/src/kmc-ldml/src/compiler/tran.ts b/developer/src/kmc-ldml/src/compiler/tran.ts index 64bc7a7c397..75805dc2f98 100644 --- a/developer/src/kmc-ldml/src/compiler/tran.ts +++ b/developer/src/kmc-ldml/src/compiler/tran.ts @@ -1,6 +1,5 @@ import { constants, SectionIdent } from "@keymanapp/ldml-keyboard-constants"; -import { KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser, MarkerParser } from '@keymanapp/common-types'; -import * as util from '@keymanapp/common-types/utils'; +import { util, KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser, MarkerParser } from '@keymanapp/common-types'; import { SectionCompiler } from "./section-compiler.js"; import Bksp = KMXPlus.Bksp; diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index 3b4a23116e0..2e9e16ff6af 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -5,8 +5,7 @@ import 'mocha'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler, SectionCompilerNew } from '../../src/compiler/section-compiler.js'; -import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, compilerEventFormat, LDMLKeyboard, UnicodeSetParser, CompilerCallbacks } from '@keymanapp/common-types'; -import * as util from '@keymanapp/common-types/utils'; +import { util, KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, compilerEventFormat, LDMLKeyboard, UnicodeSetParser, CompilerCallbacks } from '@keymanapp/common-types'; import { LdmlKeyboardCompiler } from '../../src/main.js'; // make sure main.js compiles import { assert } from 'chai'; import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; From e42a89597728179fa07c8f6453f8f3fec492b0a0 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 Jul 2024 09:47:02 +0200 Subject: [PATCH 14/14] fix(web): export consts --- common/web/types/src/util/util.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/web/types/src/util/util.ts b/common/web/types/src/util/util.ts index c5f082328a7..0d13505cfc9 100644 --- a/common/web/types/src/util/util.ts +++ b/common/web/types/src/util/util.ts @@ -1,4 +1,6 @@ -import { MATCH_HEX_ESCAPE, MATCH_QUAD_ESCAPE } from './consts.js'; +import { MATCH_HEX_ESCAPE, CONTAINS_QUAD_ESCAPE, MATCH_QUAD_ESCAPE } from './consts.js'; +export { MATCH_HEX_ESCAPE, CONTAINS_QUAD_ESCAPE, MATCH_QUAD_ESCAPE }; + /** * xml2js will not place single-entry objects into arrays. Easiest way to fix * this is to box them ourselves as needed. Ensures that o.x is an array.