From df7bb2497403aa2b0e81ad191b0f5b3fdfab9f6f Mon Sep 17 00:00:00 2001 From: AnnAngela Date: Tue, 23 Jan 2024 10:01:19 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E8=B0=83=E6=95=B4=20polyfill=20=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.js | 12 +++- .../library/crypto.randomUUID/raw.js | 55 +++++++++++++++++++ .../generatePolyfill/customPolyfill/main.json | 30 ++++++++++ .../customPolyfill/package.json | 3 + scripts/generatePolyfill/index.js | 47 +++++++++++----- scripts/modules/getUpstream.js | 6 +- tsconfig.json | 4 +- tsconfig.production.json | 6 ++ 8 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 scripts/generatePolyfill/customPolyfill/library/crypto.randomUUID/raw.js create mode 100644 scripts/generatePolyfill/customPolyfill/main.json create mode 100644 scripts/generatePolyfill/customPolyfill/package.json diff --git a/eslint.config.js b/eslint.config.js index 28fd66a1..f3ee7f7e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,7 +11,7 @@ const ignores = [ "**/dist/**", "**/.*/**", "node_modules", - "src/gadgets/libPolyfill/MediaWiki:Gadget-libPolyfill.*.js", + "src/gadgets/libPolyfill/*", ]; const srcESlintrcFiles = (await readDir("./src")).filter((n) => path.basename(n) === ".eslintrc.yaml"); @@ -35,15 +35,21 @@ const fileSpec = { browser: { files: [ "src/**/*", + "scripts/generatePolyfill/customPolyfills/**/*", + ], + ignores: [ + ...ignores, ], - ignores, }, node: { files: [ "scripts/**/*", "eslint.config.js", ], - ignores, + ignores: [ + ...ignores, + "scripts/generatePolyfill/customPolyfills/**/*", + ], }, }; diff --git a/scripts/generatePolyfill/customPolyfill/library/crypto.randomUUID/raw.js b/scripts/generatePolyfill/customPolyfill/library/crypto.randomUUID/raw.js new file mode 100644 index 00000000..7004a5a1 --- /dev/null +++ b/scripts/generatePolyfill/customPolyfill/library/crypto.randomUUID/raw.js @@ -0,0 +1,55 @@ +/** + * 引自 uuid@9.0.0 + */ + +/** + * @source https://github.com/uuidjs/uuid/blob/v9.0.0/src/regex.js + */ +const REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + +/** + * @source https://github.com/uuidjs/uuid/blob/v9.0.0/src/validate.js + */ +const validate = (uuid) => "string" === typeof uuid && REGEX.test(uuid); + +/** + * @source https://github.com/uuidjs/uuid/blob/v9.0.0/src/rng-browser.js + */ +const rnds8 = new Uint8Array(16); +const rng = () => crypto.getRandomValues(rnds8); + +/** + * @source https://github.com/uuidjs/uuid/blob/v9.0.0/src/stringify.js + */ +const byteToHex = []; +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 256).toString(16).substring(1)); +} +const unsafeStringify = (arr, offset = 0) => `${byteToHex[arr[offset + 0]]}${byteToHex[arr[offset + 1]]}${byteToHex[arr[offset + 2]]}${byteToHex[arr[offset + 3]]}-${byteToHex[arr[offset + 4]]}${byteToHex[arr[offset + 5]]}-${byteToHex[arr[offset + 6]]}${byteToHex[arr[offset + 7]]}-${byteToHex[arr[offset + 8]]}${byteToHex[arr[offset + 9]]}-${byteToHex[arr[offset + 10]]}${byteToHex[arr[offset + 11]]}${byteToHex[arr[offset + 12]]}${byteToHex[arr[offset + 13]]}${byteToHex[arr[offset + 14]]}${byteToHex[arr[offset + 15]]}`.toLowerCase(); + +/** + * @source https://github.com/uuidjs/uuid/blob/v9.0.0/src/v4.js + */ +const v4 = (options = {}, buf, offset = 0) => { + const rnds = options.random || (options.rng || rng)(); + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; + if (buf) { + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + return buf; + } + return unsafeStringify(rnds); +}; + +/** + * main polyfill + */ +try { + if (!validate(crypto.randomUUID())) { + throw void 0; + } +} catch { + crypto.randomUUID = () => v4(); +} diff --git a/scripts/generatePolyfill/customPolyfill/main.json b/scripts/generatePolyfill/customPolyfill/main.json new file mode 100644 index 00000000..b5ebe5e0 --- /dev/null +++ b/scripts/generatePolyfill/customPolyfill/main.json @@ -0,0 +1,30 @@ +{ + "crypto.randomUUID": { + "aliases": [ + "default" + ], + "spec": "https://w3c.github.io/webcrypto/#Crypto-method-randomUUID", + "docs": "https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID", + "notes": [ + "In polyfill.io@3.111.0, there is no polyfill for this feature." + ], + "browsers": { + "android": "<92", + "chrome": "<92", + "edge": "<92", + "edge_mob": "<92", + "firefox": "<95", + "firefox_mob": "<95", + "ios_saf": "<15.4", + "op_mini": "<65", + "opera": "<78", + "safari": "<15.4", + "samsung_mob": "<16.0" + }, + "baseDir": "crypto.randomUUID", + "hasTests": false, + "isTestable": false, + "isPublic": true, + "size": 2063 + } +} diff --git a/scripts/generatePolyfill/customPolyfill/package.json b/scripts/generatePolyfill/customPolyfill/package.json new file mode 100644 index 00000000..1cd945a3 --- /dev/null +++ b/scripts/generatePolyfill/customPolyfill/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/scripts/generatePolyfill/index.js b/scripts/generatePolyfill/index.js index 9d3f60d8..e19f181b 100644 --- a/scripts/generatePolyfill/index.js +++ b/scripts/generatePolyfill/index.js @@ -10,7 +10,7 @@ import createCommit from "../modules/createCommit.js"; const polyfillGadgetDefinitionPath = "src/gadgets/libPolyfill/definition.yaml"; const polyfillGadgetDefinition = await yamlModule.readFile(polyfillGadgetDefinitionPath); -const getPolyfillGadgetFiles = async () => (await fs.promises.readdir("src/gadgets/libPolyfill/")).filter((file) => file.startsWith("MediaWiki:Gadget-libPolyfill") && file.endsWith(".js")); +const getPolyfillGadgetFiles = async () => (await fs.promises.readdir("src/gadgets/libPolyfill/")).filter((file) => path.extname(file) === ".js"); /** * @type { { TARGET_CHROMIUM_VERSION: string | number, TARGET_ALIASES: string[] } } @@ -33,7 +33,9 @@ endGroup(); const polyfillGadgetFiles = await getPolyfillGadgetFiles(); const polyfillMainJSONPath = path.join(POLYFILL_PATH, "main.json"); +const customPolyfillMainJSONPath = "./scripts/generatePolyfill/customPolyfill/main.json"; const polyfillLibraryPath = path.join(POLYFILL_PATH, "library"); +const customPolyfillLibraryPath = "./scripts/generatePolyfill/customPolyfill/library"; console.info("Start to delete old polyfill files:"); for (const file of polyfillGadgetFiles) { @@ -48,10 +50,20 @@ for (const file of polyfillGadgetFiles) { console.info("\tDeleteting", file, "done."); } console.info("Start to read polyfill JSON..."); -const polyfillMainJSONArray = Object.entries(await jsonModule.readFile(polyfillMainJSONPath)).map(([id, v]) => ({ - id, - ...JSON.parse(v), -})); +const polyfillMainJSONArray = [ + ...Object.entries(await jsonModule.readFile(polyfillMainJSONPath)).map(([id, v]) => ({ + id, + ...JSON.parse(v), + })), + ...Object.entries(await jsonModule.readFile(customPolyfillMainJSONPath)).map(([id, v]) => ({ + id, + ...v, + })), +]; +console.info("Start to merge custom polyfill..."); +for (const dir of await fs.promises.readdir(customPolyfillLibraryPath)) { + await fs.promises.cp(path.join(customPolyfillLibraryPath, dir), path.join(polyfillLibraryPath, dir), { recursive: true }); +} const polyfillMainJSON = Object.fromEntries(polyfillMainJSONArray.map((v) => [v.id, v])); console.info("Get", polyfillMainJSONArray.length, "polyfill entries."); const polyfillList = polyfillMainJSONArray.filter(({ aliases }) => Array.isArray(aliases) && TARGET_ALIASES.some((targetAliases) => aliases.includes(targetAliases))); @@ -60,13 +72,13 @@ const polyfillListAllowed = polyfillList.filter(({ browsers }) => browsers?.chro console.info("Get", polyfillListAllowed.length, "polyfill entries with aliases and target browsers."); const readPolyfillRawJS = async (dir) => { - console.info("\t[readPolyfillRawJS]", "Testing", dir); - if (await fs.promises.access(dir).then(() => true).catch(() => false)) { - console.info("\t[readPolyfillRawJS]", dir, "exist, reading raw js."); - return (await fs.promises.readFile(path.join(dir, "raw.js"), { encoding: "utf-8" })).split("\n"); + const rawJSPath = path.join(dir, "raw.js"); + try { + return (await fs.promises.readFile(rawJSPath, { encoding: "utf-8" })).trim().split("\n"); + } catch (e) { + console.info("\t[readPolyfillRawJS]", rawJSPath, "not exist, return false:", e); + return false; } - console.info("\t[readPolyfillRawJS]", dir, "not exist, return false."); - return false; }; const polyfillAlreadyInjected = {}; const getPolyfillContent = async (polyfill, _rootPolyfillID = false) => { @@ -80,7 +92,11 @@ const getPolyfillContent = async (polyfill, _rootPolyfillID = false) => { } polyfillAlreadyInjected[rootPolyfillID].push(polyfill.id); console.info("\t[getPolyfillContent]", `[${polyfill.id}@${rootPolyfillID}]`, "Processing", polyfill.id); - const content = []; + const content = [ + "", + `// Polyfill ${polyfill.id} start`, + "", + ]; const detectSource = polyfill.detectSource?.trim(); console.info("\t[getPolyfillContent]", `[${polyfill.id}@${rootPolyfillID}]`, "detectSource:", detectSource); if (detectSource) { @@ -108,6 +124,11 @@ const getPolyfillContent = async (polyfill, _rootPolyfillID = false) => { if (detectSource) { content.push("}"); } + content.push( + "", + `// Polyfill ${polyfill.id} end`, + "", + ); console.info("\t[getPolyfillContent]", `[${polyfill.id}@${rootPolyfillID}]`, "Done."); return content; }; @@ -127,7 +148,7 @@ for (const polyfill of polyfillListAllowed) { ...await getPolyfillContent(polyfill), "})();", ]; - const gadgetFilePath = path.join("src/gadgets/libPolyfill/", `MediaWiki:Gadget-libPolyfill.${polyfill.id}.js`); + const gadgetFilePath = path.join("src/gadgets/libPolyfill/", `MediaWiki:Gadget-libPolyfill-${polyfill.id}.js`); console.info("Start to write polyfill file:", polyfill.id, "@", gadgetFilePath); await fs.promises.writeFile(gadgetFilePath, content.join("\n")); console.info("Done."); diff --git a/scripts/modules/getUpstream.js b/scripts/modules/getUpstream.js index cbefed06..41c75ada 100644 --- a/scripts/modules/getUpstream.js +++ b/scripts/modules/getUpstream.js @@ -1,10 +1,6 @@ import console from "./console.js"; import git from "./git.js"; -import { isInGithubActions } from "./octokit.js"; -if (!isInGithubActions) { - console.info("Not running in github actions, exit."); - process.exit(0); -} + /** * @type { string | false } when false, it means the HEAD does not point to a branch. */ diff --git a/tsconfig.json b/tsconfig.json index df71252c..5ae8c18d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,8 @@ "./node_modules/@annangela/eslint-config/dist/tsconfigs/tsconfig.browser.json" ], "compilerOptions": { - "outDir": "dist/", + "outDir": "./dist/", + "baseUrl": ".", "lib": [ "ESNext", "DOM" @@ -12,6 +13,7 @@ }, "include": [ "src", + "scripts", ], "exclude": [ "dist", diff --git a/tsconfig.production.json b/tsconfig.production.json index 3f2dc61c..429312ca 100644 --- a/tsconfig.production.json +++ b/tsconfig.production.json @@ -1,7 +1,13 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "outDir": "./dist/", + "baseUrl": "./", + "rootDir": "./src/", "target": "ES3", "ignoreDeprecations": "5.0", }, + "exclude": [ + "scripts", + ], }