From 7903ef8d0e8702e0e4dfa351ad754acf2f2ed6b9 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 30 Nov 2023 14:39:28 +0100 Subject: [PATCH] MOBILE-3947 ng: Update polyfills The check-es-compat patch can be removed if the following PR is resolved: https://github.com/robatwilliams/es-compat/pull/86 --- .github/workflows/testing.yml | 6 +- angular.json | 5 +- package-lock.json | 103 ++++++++++++++++++++++------ package.json | 2 + patches/check-es-compat+3.1.0.patch | 65 ++++++++++++++++++ src/polyfills.ts | 7 ++ 6 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 patches/check-es-compat+3.1.0.patch diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index d2d76f27f0..5d18f894db 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -59,4 +59,8 @@ jobs: npm run build:prod npm run prod --prefix cordova-plugin-moodleapp - name: JavaScript code compatibility - run: result=$(npx check-es-compat www/*.js 2> /dev/null | grep -v -E "Array\.prototype\.includes|Promise\.prototype\.finally|String\.prototype\.(matchAll|trimRight)|globalThis" | grep -Po "(?<=error).*?(?=\s+ecmascript)" | wc -l); test $result -eq 1 + # 6 BigInt usage errors are expected, they are fine without polyfill because they are only used if available. + # See https://github.com/videojs/mpd-parser/blob/v0.22.1/src/segment/urlType.js + run: | + result=$(npx check-es-compat www/*.js --polyfills="{Array,String,TypedArray}.prototype.at,Array.prototype.flatMap,Array.prototype.flat,Array.prototype.includes,globalThis,Object.fromEntries,Object.hasOwn,Promise.prototype.finally,String.prototype.matchAll,String.prototype.trimRight" | grep "6 problems (6 errors, 0 warnings)" | wc -l); test $result -eq 1 + npx check-es-compat cordova-plugin-moodleapp/www/*.js diff --git a/angular.json b/angular.json index 363e9e66c8..09d2314ffc 100644 --- a/angular.json +++ b/angular.json @@ -11,8 +11,11 @@ "schematics": {}, "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-builders/custom-webpack:browser", "options": { + "customWebpackConfig": { + "path": "./webpack.config.js" + }, "allowedCommonJsDependencies":[ "chart.js" ], diff --git a/package-lock.json b/package-lock.json index 71595c9648..068fd848c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,6 +99,7 @@ "zone.js": "~0.13.0" }, "devDependencies": { + "@angular-builders/custom-webpack": "^16.0.1", "@angular-devkit/build-angular": "^16.2.10", "@angular-eslint/builder": "^16.2.0", "@angular-eslint/eslint-plugin": "^16.2.0", @@ -144,6 +145,7 @@ "minimatch": "^9.0.3", "native-run": "^2.0.0", "patch-package": "^6.5.0", + "terser-webpack-plugin": "^5.3.9", "ts-jest": "^29.1.1", "ts-node": "^8.3.0", "typescript": "~5.1.3" @@ -183,6 +185,79 @@ "node": ">=6.0.0" } }, + "node_modules/@angular-builders/custom-webpack": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-16.0.1.tgz", + "integrity": "sha512-C6INC8UOYDcp8LJwNhE0m66yp+nZX50JdgGI8oRn7fqw3gO58qhDgXrR/8BCrSeC8eOx8WxSuvBJ6u+9dozhyw==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": ">=0.1600.0 < 0.1700.0", + "@angular-devkit/build-angular": "^16.0.0", + "@angular-devkit/core": "^16.0.0", + "lodash": "^4.17.15", + "ts-node": "^10.0.0", + "tsconfig-paths": "^4.1.0", + "webpack-merge": "^5.7.3" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/@angular-devkit/architect": { "version": "0.1602.10", "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.10.tgz", @@ -2787,8 +2862,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2801,8 +2874,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -5995,33 +6066,25 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tufjs/canonical-json": { "version": "1.0.0", @@ -11347,9 +11410,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/critters": { "version": "0.0.20", @@ -28183,9 +28244,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.2.0", diff --git a/package.json b/package.json index cdf914c8b3..311343d577 100644 --- a/package.json +++ b/package.json @@ -134,6 +134,7 @@ "zone.js": "~0.13.0" }, "devDependencies": { + "@angular-builders/custom-webpack": "^16.0.1", "@angular-devkit/build-angular": "^16.2.10", "@angular-eslint/builder": "^16.2.0", "@angular-eslint/eslint-plugin": "^16.2.0", @@ -179,6 +180,7 @@ "minimatch": "^9.0.3", "native-run": "^2.0.0", "patch-package": "^6.5.0", + "terser-webpack-plugin": "^5.3.9", "ts-jest": "^29.1.1", "ts-node": "^8.3.0", "typescript": "~5.1.3" diff --git a/patches/check-es-compat+3.1.0.patch b/patches/check-es-compat+3.1.0.patch new file mode 100644 index 0000000000..37bab9c96e --- /dev/null +++ b/patches/check-es-compat+3.1.0.patch @@ -0,0 +1,65 @@ +diff --git a/node_modules/check-es-compat/bin/cli.mjs b/node_modules/check-es-compat/bin/cli.mjs +index 25c53f5..26ce475 100755 +--- a/node_modules/check-es-compat/bin/cli.mjs ++++ b/node_modules/check-es-compat/bin/cli.mjs +@@ -17,7 +17,8 @@ if (args.length === 0) { + } + } + +-async function execute(files) { ++async function execute(args) { ++ const { files, polyfills } = parseArguments(args); + const eslint = new ESLint({ + // Ignore any config files + useEslintrc: false, +@@ -34,7 +35,7 @@ async function execute(files) { + es2021: true, + }, + rules: { +- 'ecmascript-compat/compat': 'error', ++ 'ecmascript-compat/compat': ['error', { polyfills }], + }, + }, + }); +@@ -46,3 +47,41 @@ async function execute(files) { + + return { hasErrors: results.some((result) => result.errorCount > 0) }; + } ++ ++function parseArguments(args) { ++ const files = []; ++ const polyfills = []; ++ let nextArgIsPolyfills = false; ++ ++ for (const arg of args) { ++ if (nextArgIsPolyfills) { ++ nextArgIsPolyfills = false; ++ polyfills.push(...splitPolyfillsArgument(arg)); ++ continue; ++ } ++ ++ if (arg.startsWith('--polyfills')) { ++ if (arg.startsWith('--polyfills=')) { ++ polyfills.push(...splitPolyfillsArgument(arg.slice(12))); ++ } else { ++ nextArgIsPolyfills = true; ++ } ++ ++ continue; ++ } ++ ++ files.push(arg); ++ } ++ ++ return { files, polyfills }; ++} ++ ++function splitPolyfillsArgument(polyfills) { ++ const prototypeAtPolyfill = '{Array,String,TypedArray}.prototype.at'; ++ const prototypeAtPlaceholder = '{{PROTOTYPEAT}}'; ++ ++ return polyfills ++ .replace(prototypeAtPolyfill, prototypeAtPlaceholder) ++ .split(',') ++ .map(polyfill => polyfill === prototypeAtPlaceholder ? prototypeAtPolyfill : polyfill); ++} diff --git a/src/polyfills.ts b/src/polyfills.ts index 315b2cf5fe..8debdd9b3a 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -19,11 +19,18 @@ window.__Zone_disable_customElements = true; import 'zone.js'; // Platform polyfills +import 'core-js/es/array/at'; +import 'core-js/es/array/flat-map'; +import 'core-js/es/array/flat'; import 'core-js/es/array/includes'; import 'core-js/es/global-this'; +import 'core-js/es/object/from-entries'; +import 'core-js/es/object/has-own'; import 'core-js/es/promise/finally'; +import 'core-js/es/string/at'; import 'core-js/es/string/match-all'; import 'core-js/es/string/trim-right'; +import 'core-js/es/typed-array/at'; polyfillEventComposedPath();