From 16a4541691d41868e0ef1ae9311096596c2ab4a3 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 14:44:13 +0100 Subject: [PATCH 01/28] refactor: Move test files to `__tests__` directory Moves test files from the `src/handlers` directory to the `src/__tests__` directory for better organization and separation of concerns. This change improves the project structure and makes it easier to locate and manage test files. Also, updates import paths in test files. --- src/{handlers => __tests__}/css.test.ts | 2 +- src/{handlers => __tests__}/html.test.ts | 2 +- src/{handlers => __tests__}/js-ast.test.ts | 2 +- src/{handlers => __tests__}/js.test.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/{handlers => __tests__}/css.test.ts (99%) rename src/{handlers => __tests__}/html.test.ts (99%) rename src/{handlers => __tests__}/js-ast.test.ts (99%) rename src/{handlers => __tests__}/js.test.ts (99%) diff --git a/src/handlers/css.test.ts b/src/__tests__/css.test.ts similarity index 99% rename from src/handlers/css.test.ts rename to src/__tests__/css.test.ts index 0d908b0..0697f9b 100644 --- a/src/handlers/css.test.ts +++ b/src/__tests__/css.test.ts @@ -7,7 +7,7 @@ import { copyCssData, renameCssSelector, extractClassFromSelector, -} from "./css"; +} from "../handlers/css"; const testCss = ` .s0-1 { diff --git a/src/handlers/html.test.ts b/src/__tests__/html.test.ts similarity index 99% rename from src/handlers/html.test.ts rename to src/__tests__/html.test.ts index 58982b4..5319c8e 100644 --- a/src/handlers/html.test.ts +++ b/src/__tests__/html.test.ts @@ -5,7 +5,7 @@ import { describe, it, expect } from "vitest"; import { findHtmlTagContentsByClass, obfuscateHtmlClassNames, -} from "./html"; +} from "../handlers/html"; //! ================================ diff --git a/src/handlers/js-ast.test.ts b/src/__tests__/js-ast.test.ts similarity index 99% rename from src/handlers/js-ast.test.ts rename to src/__tests__/js-ast.test.ts index 38449ea..4e5a0aa 100644 --- a/src/handlers/js-ast.test.ts +++ b/src/__tests__/js-ast.test.ts @@ -3,7 +3,7 @@ import traverse, { NodePath } from "@babel/traverse"; import * as t from "@babel/types"; import * as parser from "@babel/parser"; import generator from "@babel/generator"; -import { searchStringLiterals, obfuscateJsWithAst } from "./js-ast"; +import { searchStringLiterals, obfuscateJsWithAst } from "../handlers/js-ast"; function stripCode(code: string) { return code.replace(/\s/g, ""); diff --git a/src/handlers/js.test.ts b/src/__tests__/js.test.ts similarity index 99% rename from src/handlers/js.test.ts rename to src/__tests__/js.test.ts index 6e33ffc..3fea976 100644 --- a/src/handlers/js.test.ts +++ b/src/__tests__/js.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, test } from "vitest"; import { searchForwardComponent, -} from "./js"; +} from "../handlers/js"; //! ================================ //! searchForwardComponent From 6b5f0002eaead4c56118eae82f0db4f5bf3c7023 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 18:39:29 +0100 Subject: [PATCH 02/28] refactor(test): Moves test file to the `__tests__` directory Moves the test file from the `src` directory to the `__tests__` directory for better organization and separation of concerns. This change improves the project structure and makes it easier to locate test files. --- src/{ => __tests__}/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{ => __tests__}/utils.test.ts (99%) diff --git a/src/utils.test.ts b/src/__tests__/utils.test.ts similarity index 99% rename from src/utils.test.ts rename to src/__tests__/utils.test.ts index 54505ee..f921647 100644 --- a/src/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -6,7 +6,7 @@ import { seedableSimplifyString, duplicationCheck, simplifyString, -} from "./utils"; +} from "../utils"; import NumberGenerator from "recoverable-random"; From d38b38fdf51fbe3e5f68e49ba1f239adf480bf91 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:21:13 +0100 Subject: [PATCH 03/28] chore: Migrates from Prettier to Biome Migrates the project's code formatting and linting from Prettier to Biome. This change removes the existing Prettier configuration and implements Biome. The Biome configuration enforces consistent code style and catches potential issues, improving code quality and maintainability. --- .prettierignore | 5 ---- .prettierrc | 7 ----- biome.json | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 biome.json diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 7605e7f..0000000 --- a/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -build -coverage -dist -node_modules -*.test.* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index cf7c9eb..0000000 --- a/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "semi": true, - "trailingComma": "all", - "singleQuote": false, - "printWidth": 100, - "tabWidth": 2 -} diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..03fb901 --- /dev/null +++ b/biome.json @@ -0,0 +1,69 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [] + }, + "formatter": { + "ignore": ["node_modules", ".next"], + "enabled": true, + "indentStyle": "space", + "lineWidth": 80, + "indentWidth": 2, + "lineEnding": "lf" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "ignore": ["node_modules", ".next", "packages/tsconfig"], + "enabled": true, + "rules": { + "recommended": true, + + "complexity": { + "noUselessTypeConstraint": "error", + "useLiteralKeys": "error", + "useOptionalChain": "error", + "noForEach": "off", + }, + "correctness": { + "noUnusedVariables": "info", + "useArrayLiterals": "error" + }, + "style": { + "noInferrableTypes": "error", + "noNamespace": "error", + "useAsConstAssertion": "error", + "useBlockStatements": "error", + "useConsistentArrayType": "error", + "useForOf": "error", + "useShorthandFunctionType": "error", + "useImportType": "error" + }, + "suspicious": { + "noDebugger": "info", + "noConsoleLog": "info", + "noEmptyBlockStatements": "error", + "noExplicitAny": "error", + "noExtraNonNullAssertion": "error", + "noMisleadingInstantiator": "error", + "noUnsafeDeclarationMerging": "error", + "useAwait": "warn", + "useNamespaceKeyword": "error" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "always", + "trailingCommas": "all" + } + } +} From 0afd7808b2c6405b5fbedb4b8ff0e34f813ccd82 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:22:26 +0100 Subject: [PATCH 04/28] feat: Upgrades to v3 with new CSS transformation Upgrades the core CSS transformation engine to `css-seasoning` and `lightningcss-wasm`. - Replaces PostCSS with `css-seasoning` for CSS parsing and transformation. - Integrates `lightningcss-wasm` for CSS minification and optimization. - Introduces a new `obfuscateCssFiles` function for processing CSS files. - Removes the deprecated `classLength` option. - Improves the way of css obfuscation with new logic and features. This change significantly enhances the performance and flexibility of the CSS obfuscation process. --- README.md | 3 + package-lock.json | 235 +++++++++++++++++++ package.json | 5 +- src/config.ts | 4 + src/handlers/css.ts | 543 +++++++++++++++++++++++++++++--------------- src/index.ts | 60 +++-- src/types.ts | 8 +- src/utils.ts | 177 +++++++++------ 8 files changed, 765 insertions(+), 270 deletions(-) diff --git a/README.md b/README.md index 138fe9a..3e6ede2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + + + # NEXT-CSS-OBFUSCATOR Project starts on 30-10-2023 diff --git a/package-lock.json b/package-lock.json index 7f52229..50d0aea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,10 @@ "@babel/parser": "^7.23.9", "@babel/traverse": "^7.23.9", "css-parse": "^2.0.0", + "css-seasoning": "^1.3.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", + "lightningcss-wasm": "^1.29.3", "recoverable-random": "^1.0.5", "yargs": "^17.7.2" }, @@ -22,6 +24,7 @@ "next-css-obfuscator": "bin/cli.mjs" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", "@types/html-escaper": "^3.0.4", @@ -341,6 +344,197 @@ "node": ">=18" } }, + "node_modules/@biomejs/biome": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", + "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "dev": true, + "hasInstallScript": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.9.4", + "@biomejs/cli-darwin-x64": "1.9.4", + "@biomejs/cli-linux-arm64": "1.9.4", + "@biomejs/cli-linux-arm64-musl": "1.9.4", + "@biomejs/cli-linux-x64": "1.9.4", + "@biomejs/cli-linux-x64-musl": "1.9.4", + "@biomejs/cli-win32-arm64": "1.9.4", + "@biomejs/cli-win32-x64": "1.9.4" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", + "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", + "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", + "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", + "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", + "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", + "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", + "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", + "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@deno/shim-deno": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@deno/shim-deno/-/shim-deno-0.18.2.tgz", + "integrity": "sha512-oQ0CVmOio63wlhwQF75zA4ioolPvOwAoK0yuzcS5bDC1JUvH3y1GS8xPh8EOpcoDQRU4FTG8OQfxhpR+c6DrzA==", + "dependencies": { + "@deno/shim-deno-test": "^0.5.0", + "which": "^4.0.0" + } + }, + "node_modules/@deno/shim-deno-test": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@deno/shim-deno-test/-/shim-deno-test-0.5.0.tgz", + "integrity": "sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w==" + }, + "node_modules/@deno/shim-deno/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/@deno/shim-deno/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", @@ -1539,6 +1733,19 @@ "css": "^2.0.0" } }, + "node_modules/css-seasoning": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/css-seasoning/-/css-seasoning-1.3.0.tgz", + "integrity": "sha512-D/Th17IefXLulL4AKphSN1uaclv+UV8eyY83GRVRxfsOzwreNwy4VA2ksmVRQoDKDUlJw2XpCO6HabFgPX5PlA==", + "dependencies": { + "@deno/shim-deno": "~0.18.0", + "lightningcss-wasm": "^1.29.1", + "xxhash-wasm": "^1.1.0" + }, + "bin": { + "css-seasoning": "bin/cli.mjs" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -1939,6 +2146,29 @@ "node": ">=4" } }, + "node_modules/lightningcss-wasm": { + "version": "1.29.3", + "resolved": "https://registry.npmjs.org/lightningcss-wasm/-/lightningcss-wasm-1.29.3.tgz", + "integrity": "sha512-j02QNSRVBKxsSBinpSCgx3x8XwwOoO50ekDO1O5rBf+dS0j46qSojv+3BDzMNCaGFJ18EjcnXGDkG3ImIbU/PQ==", + "bundleDependencies": [ + "napi-wasm" + ], + "dependencies": { + "napi-wasm": "^1.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-wasm/node_modules/napi-wasm": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT" + }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", @@ -2678,6 +2908,11 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 07ca11f..c2f462b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-css-obfuscator", - "version": "2.2.19", + "version": "3.0.0-b1", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", @@ -27,12 +27,15 @@ "@babel/parser": "^7.23.9", "@babel/traverse": "^7.23.9", "css-parse": "^2.0.0", + "css-seasoning": "^1.3.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", + "lightningcss-wasm": "^1.29.3", "recoverable-random": "^1.0.5", "yargs": "^17.7.2" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", "@types/html-escaper": "^3.0.4", diff --git a/src/config.ts b/src/config.ts index 0f7f17e..15409dd 100644 --- a/src/config.ts +++ b/src/config.ts @@ -7,7 +7,11 @@ const defaultOptions: Options = { classConversionJsonFolderPath: "./css-obfuscator", // The folder path to store the before obfuscate and after obfuscated classes conversion table. refreshClassConversionJson: false, // Refresh the class conversion JSON file. + /** + * @deprecated Not longer used from v3.0.0 + */ classLength: 5, // Length of the obfuscated class name. + classPrefix: "", // Prefix of the obfuscated class name. classSuffix: "", // Suffix of the obfuscated class name. classIgnore: [], // The class names to be ignored during obfuscation. diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 0758d08..95d3ea4 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -1,8 +1,12 @@ -import path from "path"; -import fs from "fs"; +import type { obfuscateMode, SelectorConversion } from "../types"; + +import path from "node:path"; +import fs from "node:fs"; // @ts-ignore -import css from 'css'; +import css from "css"; import NumberGenerator from "recoverable-random"; +import { initTransform, transform, ConversionTable, cssEscape, type ConversionTables, type TransformProps } from "css-seasoning"; +import lightningcssInit, { transform as lightningcssTransform } from "lightningcss-wasm"; import { log, @@ -16,8 +20,9 @@ import { duplicationCheck, createKey, decodeKey, + stringToNumber, + loadConversionTables, } from "../utils"; -import { obfuscateMode, SelectorConversion } from "../types"; let randomStringGeneraterStateCode: string | undefined = undefined; let currentAlphabetPoistion = 1; @@ -44,9 +49,9 @@ function createNewClassName( case "random": ({ rngStateCode, randomString } = getRandomString(classNameLength, seed, undefined, className)); break; - case "simplify-seedable": - ({ rngStateCode, randomString } = seedableSimplifyString(className, seed, seed + NumberGenerator.stringToSeed(className).toString())); - break; + // case "simplify-seedable": + // ({ rngStateCode, randomString } = seedableSimplifyString(className, seed, seed + NumberGenerator.stringToSeed(className).toString())); + // break; case "simplify": randomString = simplifyString(currentAlphabetPoistion); currentAlphabetPoistion++; @@ -90,7 +95,7 @@ const findActionSelectorsRegex = /(?)/g * // Returns: [] * extractClassFromSelector("div"); */ -function extractClassFromSelector(selector: string, replacementClassNames?: (string | undefined)[]) { +export function extractClassFromSelector(selector: string, replacementClassNames?: (string | undefined)[]) { //? "\\[\w\%\:\.\!\*\<\>\/]" handle escaped characters //? "(?:\\\[(?:[^\[\]\s])*\\\]))+)" handle [attribute / Tailwind CSS custom parameter] selector const extractClassRegex = /(?<=[.:!]|(?\/]|(?:\\\[(?:[^\[\]\s])*\\\]))+)(?![\w\-]*\()/g; @@ -152,7 +157,11 @@ function getAllSelector(cssObj: any): any[] { return selectors; } -function createSelectorConversionJson( +/** + * + * @deprecated will be replaced by new css transformer + */ +export function createSelectorConversionJson( { selectorConversionJsonFolderPath, buildFolderPath, @@ -178,114 +187,114 @@ function createSelectorConversionJson( enableObfuscateMarkerClasses?: boolean, generatorSeed?: string, }) { - if (!fs.existsSync(selectorConversionJsonFolderPath)) { - fs.mkdirSync(selectorConversionJsonFolderPath); - } - - const selectorConversion: SelectorConversion = loadAndMergeJsonFiles(selectorConversionJsonFolderPath); - - // pre-defined ".dark", mainly for tailwindcss dark mode - if (enableObfuscateMarkerClasses) { - selectorConversion[".dark"] = ".dark"; - } - - // get all css selectors - const cssPaths = findAllFilesWithExt(".css", buildFolderPath); - const selectors: string[] = []; - cssPaths.forEach((cssPath) => { - const cssContent = fs.readFileSync(cssPath, "utf-8"); - const cssObj = css.parse(cssContent); - selectors.push(...getAllSelector(cssObj)); - }); - - // remove duplicated selectors - const uniqueSelectors = [...new Set(selectors)]; - - const allowClassStartWith = [".", "#", ":is(", ":where(", ":not(" - , ":matches(", ":nth-child(", ":nth-last-child(" - , ":nth-of-type(", ":nth-last-of-type(", ":first-child(" - , ":last-child(", ":first-of-type(", ":last-of-type(" - , ":only-child(", ":only-of-type(", ":empty(", ":link(" - , ":visited(", ":active(", ":hover(", ":focus(", ":target(" - , ":lang(", ":enabled(", ":disabled(", ":checked(", ":default(" - , ":indeterminate(", ":root(", ":before(" - , ":after(", ":first-letter(", ":first-line(", ":selection(" - , ":read-only(", ":read-write(", ":fullscreen(", ":optional(" - , ":required(", ":valid(", ":invalid(", ":in-range(", ":out-of-range(" - , ":placeholder-shown(" - ]; - - const selectorClassPair: { [key: string]: string[] } = {}; - - for (let i = 0; i < uniqueSelectors.length; i++) { - const originalSelector = uniqueSelectors[i]; - const { extractedClasses } = extractClassFromSelector(originalSelector) || []; - selectorClassPair[originalSelector] = extractedClasses; - } - - //? since a multi part selector normally grouped by multiple basic selectors - //? so we need to obfuscate the basic selector first - //? eg. ":is(.class1 .class2)" grouped by ".class1" and ".class2" - // sort the selectorClassPair by the number of classes in the selector (from least to most) - // and remove the selector with no class - const sortedSelectorClassPair = Object.entries(selectorClassPair) - .sort((a, b) => a[1].length - b[1].length) - .filter((pair) => pair[1].length > 0); - - for (let i = 0; i < sortedSelectorClassPair.length; i++) { - const [originalSelector, selectorClasses] = sortedSelectorClassPair[i]; - if (selectorClasses.length == 0) { - continue; - } - - let selector = originalSelector; - let classes = selectorClasses; - - if (classes && allowClassStartWith.some((start) => selector.startsWith(start))) { - classes = classes.map((className) => { - - // apply ignore list - if (classIgnore.some(regex => { - if (typeof regex === "string") { - return className === regex; - } - return new RegExp(regex).test(className) - })) { - return className; - } - - // try to get the obfuscated selector from the selectorConversion - // if not found, create a new one - let obfuscatedSelector = selectorConversion[`.${className}`]; - if (!obfuscatedSelector) { - const obfuscatedClass = createNewClassName(mode, className, classPrefix, classSuffix, classNameLength, generatorSeed); - obfuscatedSelector = `.${obfuscatedClass}`; - selectorConversion[`.${className}`] = obfuscatedSelector; - } - - // return the obfuscated class - return obfuscatedSelector.slice(1) - }); - - // obfuscate the selector - const { selector: obfuscatedSelector } = extractClassFromSelector(originalSelector, classes); - - selectorConversion[originalSelector] = obfuscatedSelector; - } - } - - const jsonPath = path.join(process.cwd(), selectorConversionJsonFolderPath, "conversion.json"); - fs.writeFileSync(jsonPath, JSON.stringify(selectorConversion, null, 2)); - if (duplicationCheck(Object.keys(selectorConversion))) { - if (mode == "random") { - log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, try to increase the class name length / open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); - } else { - log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, please open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); - } - } + // if (!fs.existsSync(selectorConversionJsonFolderPath)) { + // fs.mkdirSync(selectorConversionJsonFolderPath); + // } + + // const selectorConversion = loadConversionTables(selectorConversionJsonFolderPath); + + // // pre-defined ".dark", mainly for tailwindcss dark mode + // if (enableObfuscateMarkerClasses) { + // selectorConversion[".dark"] = ".dark"; + // } + + // // get all css selectors + // const cssPaths = findAllFilesWithExt(".css", buildFolderPath); + // const selectors: string[] = []; + // cssPaths.forEach((cssPath) => { + // const cssContent = fs.readFileSync(cssPath, "utf-8"); + // const cssObj = css.parse(cssContent); + // selectors.push(...getAllSelector(cssObj)); + // }); + + // // remove duplicated selectors + // const uniqueSelectors = [...new Set(selectors)]; + + // const allowClassStartWith = [".", "#", ":is(", ":where(", ":not(" + // , ":matches(", ":nth-child(", ":nth-last-child(" + // , ":nth-of-type(", ":nth-last-of-type(", ":first-child(" + // , ":last-child(", ":first-of-type(", ":last-of-type(" + // , ":only-child(", ":only-of-type(", ":empty(", ":link(" + // , ":visited(", ":active(", ":hover(", ":focus(", ":target(" + // , ":lang(", ":enabled(", ":disabled(", ":checked(", ":default(" + // , ":indeterminate(", ":root(", ":before(" + // , ":after(", ":first-letter(", ":first-line(", ":selection(" + // , ":read-only(", ":read-write(", ":fullscreen(", ":optional(" + // , ":required(", ":valid(", ":invalid(", ":in-range(", ":out-of-range(" + // , ":placeholder-shown(" + // ]; + + // const selectorClassPair: { [key: string]: string[] } = {}; + + // for (let i = 0; i < uniqueSelectors.length; i++) { + // const originalSelector = uniqueSelectors[i]; + // const { extractedClasses } = extractClassFromSelector(originalSelector) || []; + // selectorClassPair[originalSelector] = extractedClasses; + // } + + // //? since a multi part selector normally grouped by multiple basic selectors + // //? so we need to obfuscate the basic selector first + // //? eg. ":is(.class1 .class2)" grouped by ".class1" and ".class2" + // // sort the selectorClassPair by the number of classes in the selector (from least to most) + // // and remove the selector with no class + // const sortedSelectorClassPair = Object.entries(selectorClassPair) + // .sort((a, b) => a[1].length - b[1].length) + // .filter((pair) => pair[1].length > 0); + + // for (let i = 0; i < sortedSelectorClassPair.length; i++) { + // const [originalSelector, selectorClasses] = sortedSelectorClassPair[i]; + // if (selectorClasses.length == 0) { + // continue; + // } + + // let selector = originalSelector; + // let classes = selectorClasses; + + // if (classes && allowClassStartWith.some((start) => selector.startsWith(start))) { + // classes = classes.map((className) => { + + // // apply ignore list + // if (classIgnore.some(regex => { + // if (typeof regex === "string") { + // return className === regex; + // } + // return new RegExp(regex).test(className) + // })) { + // return className; + // } + + // // try to get the obfuscated selector from the selectorConversion + // // if not found, create a new one + // let obfuscatedSelector = selectorConversion[`.${className}`]; + // if (!obfuscatedSelector) { + // const obfuscatedClass = createNewClassName(mode, className, classPrefix, classSuffix, classNameLength, generatorSeed); + // obfuscatedSelector = `.${obfuscatedClass}`; + // selectorConversion[`.${className}`] = obfuscatedSelector; + // } + + // // return the obfuscated class + // return obfuscatedSelector.slice(1) + // }); + + // // obfuscate the selector + // const { selector: obfuscatedSelector } = extractClassFromSelector(originalSelector, classes); + + // selectorConversion[originalSelector] = obfuscatedSelector; + // } + // } + + // const jsonPath = path.join(process.cwd(), selectorConversionJsonFolderPath, "conversion.json"); + // fs.writeFileSync(jsonPath, JSON.stringify(selectorConversion, null, 2)); + // if (duplicationCheck(Object.keys(selectorConversion))) { + // if (mode == "random") { + // log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, try to increase the class name length / open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); + // } else { + // log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, please open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); + // } + // } } -function copyCssData(targetSelector: string, newSelectorName: string, cssObj: any) { +export function copyCssData(targetSelector: string, newSelectorName: string, cssObj: any) { function recursive(rules: any[]): any[] { return rules.map((item: any) => { if (item.rules) { @@ -316,7 +325,7 @@ function copyCssData(targetSelector: string, newSelectorName: string, cssObj: an return cssObj; } -function renameCssSelector(oldSelector: string, newSelector: string, cssObj: any) { +export function renameCssSelector(oldSelector: string, newSelector: string, cssObj: any) { function recursive(rules: any[]): any[] { return rules.map((item: any) => { if (item.rules) { @@ -340,90 +349,266 @@ function renameCssSelector(oldSelector: string, newSelector: string, cssObj: any return cssObj; } -function obfuscateCss( - selectorConversion: SelectorConversion, +/** + * + * @deprecated WIP + */ +export const obfuscateCss = async ({ + cssPath, + removeOriginalCss, + isFullObfuscation, + outCssPath, + conversionTables, + + mode = "random", + prefix, + suffix, + classIgnore = [], + generatorSeed = Math.random().toString().slice(2, 10), // take 8 digits from the random number +}: { cssPath: string, - replaceOriginalSelector: boolean = false, - isFullObfuscation: boolean = false, + removeOriginalCss?: boolean, + isFullObfuscation?: boolean, outCssPath?: string, -) { + conversionTables?: ConversionTables, + + mode?: obfuscateMode, + prefix?: string, + suffix?: string, + classIgnore?: (string | RegExp)[], + generatorSeed?: string, +}) => { if (!outCssPath) { + // If no output path is provided, use the input path outCssPath = cssPath; } else if (!fs.existsSync(path.dirname(outCssPath))) { + // Create the output directory if it doesn't exist fs.mkdirSync(path.dirname(outCssPath)); } - let cssContent = fs.readFileSync(cssPath, "utf-8"); + const cssContent = fs.readFileSync(cssPath, "utf-8"); - let cssObj = css.parse(cssContent); - const cssRulesCount = cssObj.stylesheet.rules.length; + // TODO: use const instead of function + // TODO: this function is combined createSelectorConversionJson and obfuscateCss + // TODO: connect props to this function + // TODO: bc we updated conversion table, so other function using the table have to update to the new table - if (isFullObfuscation) { - Object.keys(selectorConversion).forEach((key) => { - usedKeyRegistery.add(key); - }); - } else { - // join all selectors start with ":" (eg. ":is") - Object.keys(selectorConversion).forEach((key) => { - if (key.startsWith(":")) { - usedKeyRegistery.add(key); - } - }); - - // join all selectors with action selectors - const actionSelectors = getAllSelector(cssObj).filter((selector) => selector.match(findActionSelectorsRegex)); - actionSelectors.forEach((actionSelector) => { - usedKeyRegistery.add(actionSelector); - }); - - // join all Tailwind CSS [child] selectors (eg. ".\[\&_\.side-box\]\:absolute .side-box") - const tailwindCssChildSelectors = getAllSelector(cssObj).filter((selector) => selector.startsWith(".\\[")); - tailwindCssChildSelectors.forEach((tailwindCssChildSelector) => { - usedKeyRegistery.add(tailwindCssChildSelector); - }); - - // join all child selectors (eg. ">*") - const universalSelectors = getAllSelector(cssObj).filter((selector) => selector.includes(">")); - universalSelectors.forEach((universalSelector) => { - usedKeyRegistery.add(universalSelector); - }); + let transformerMode: TransformProps["mode"] = mode === "simplify" ? "minimal" : "hash"; + if (!transformerMode) { + // @ts-expect-error - "simplify-seedable" is deprecated but for backward compatibility + if (mode === "simplify-seedable") { + log("warn", "CSS obfuscation", "The 'simplify-seedable' mode is deprecated, please use 'random' or 'simplify' instead. Now will fall back to 'random' mode."); + transformerMode = "hash"; + } + log("error", "CSS obfuscation", `Invalid mode: ${mode}`); + throw new Error(`Invalid mode: ${mode}`); } - // modify css rules - usedKeyRegistery.forEach((key) => { - const originalSelectorName = key; - const obfuscatedSelectorName = selectorConversion[key]; - if (obfuscatedSelectorName) { - if (replaceOriginalSelector) { - cssObj = renameCssSelector(originalSelectorName, selectorConversion[key], cssObj); - } else { - cssObj = copyCssData(originalSelectorName, selectorConversion[key], cssObj); - } + let finCss = ""; + const { css: obfuscatedCss, conversionTables: newConversionTables } = transform({ + css: cssContent, + conversionTables: conversionTables, + mode: transformerMode, + prefix: prefix, + suffix: suffix, + seed: stringToNumber(generatorSeed), + ignorePatterns: { + selector: classIgnore } }); - if (replaceOriginalSelector) { - log("info", "CSS rules:", `Modified ${usedKeyRegistery.size} CSS rules to ${getFilenameFromPath(cssPath)}`); + if (removeOriginalCss) { + finCss = obfuscatedCss; } else { - log("info", "CSS rules:", `Added ${cssObj.stylesheet.rules.length - cssRulesCount} new CSS rules to ${getFilenameFromPath(cssPath)}`); + // if keep original selector, we need to merge the original css with the obfuscated css + // then minify the css in order to marge the css + const mixedCss = cssContent + obfuscatedCss; + const { code } = lightningcssTransform({ + filename: "style.css", + code: new TextEncoder().encode(mixedCss), + minify: true, + }); + finCss = new TextDecoder().decode(code); } - const cssOptions = { - compress: true, - }; - const cssObfuscatedContent = css.stringify(cssObj, cssOptions); + const totalConversion = Object.keys(newConversionTables.selector).length + Object.keys(newConversionTables.ident).length; + if (removeOriginalCss) { + log("info", "CSS rules:", `Modified ${totalConversion} CSS rules to ${getFilenameFromPath(cssPath)}`); + } else { + const oldTotalConversion = conversionTables ? Object.keys(conversionTables.selector).length + Object.keys(conversionTables.ident).length : 0; + log("info", "CSS rules:", `Added ${totalConversion - oldTotalConversion} new CSS rules to ${getFilenameFromPath(cssPath)}`); + } + // Save the obfuscated CSS to the output path const sizeBefore = Buffer.byteLength(cssContent, "utf8"); - fs.writeFileSync(outCssPath, cssObfuscatedContent); - const sizeAfter = Buffer.byteLength(cssObfuscatedContent, "utf8"); + fs.writeFileSync(outCssPath, obfuscatedCss); + const sizeAfter = Buffer.byteLength(obfuscatedCss, "utf8"); const percentChange = Math.round(((sizeAfter) / sizeBefore) * 100); log("success", "CSS obfuscated:", `Size from ${sizeBefore} to ${sizeAfter} bytes (${percentChange}%) in ${getFilenameFromPath(cssPath)}`); + + return { + conversionTables: newConversionTables, + } } -export { - copyCssData, - renameCssSelector, - createSelectorConversionJson, - obfuscateCss, - extractClassFromSelector, -} \ No newline at end of file +// export const obfuscateCss = async ( +// selectorConversion: ConversionTable, +// cssPath: string, +// replaceOriginalSelector = false, +// isFullObfuscation = false, +// outCssPath?: string, +// ) => { +// if (!outCssPath) { +// outCssPath = cssPath; +// } else if (!fs.existsSync(path.dirname(outCssPath))) { +// fs.mkdirSync(path.dirname(outCssPath)); +// } + +// const cssContent = fs.readFileSync(cssPath, "utf-8"); + +// let cssObj = css.parse(cssContent); +// const cssRulesCount = cssObj.stylesheet.rules.length; + +// if (isFullObfuscation) { +// Object.keys(selectorConversion).forEach((key) => { +// usedKeyRegistery.add(key); +// }); +// } else { +// // join all selectors start with ":" (eg. ":is") +// Object.keys(selectorConversion).forEach((key) => { +// if (key.startsWith(":")) { +// usedKeyRegistery.add(key); +// } +// }); + +// // join all selectors with action selectors +// const actionSelectors = getAllSelector(cssObj).filter((selector) => selector.match(findActionSelectorsRegex)); +// actionSelectors.forEach((actionSelector) => { +// usedKeyRegistery.add(actionSelector); +// }); + +// // join all Tailwind CSS [child] selectors (eg. ".\[\&_\.side-box\]\:absolute .side-box") +// const tailwindCssChildSelectors = getAllSelector(cssObj).filter((selector) => selector.startsWith(".\\[")); +// tailwindCssChildSelectors.forEach((tailwindCssChildSelector) => { +// usedKeyRegistery.add(tailwindCssChildSelector); +// }); + +// // join all child selectors (eg. ">*") +// const universalSelectors = getAllSelector(cssObj).filter((selector) => selector.includes(">")); +// universalSelectors.forEach((universalSelector) => { +// usedKeyRegistery.add(universalSelector); +// }); +// } + +// // modify css rules +// usedKeyRegistery.forEach((key) => { +// const originalSelectorName = key; +// const obfuscatedSelectorName = selectorConversion[key]; +// if (obfuscatedSelectorName) { +// if (replaceOriginalSelector) { +// cssObj = renameCssSelector(originalSelectorName, selectorConversion[key], cssObj); +// } else { +// cssObj = copyCssData(originalSelectorName, selectorConversion[key], cssObj); +// } +// } +// }); + +// if (replaceOriginalSelector) { +// log("info", "CSS rules:", `Modified ${usedKeyRegistery.size} CSS rules to ${getFilenameFromPath(cssPath)}`); +// } else { +// log("info", "CSS rules:", `Added ${cssObj.stylesheet.rules.length - cssRulesCount} new CSS rules to ${getFilenameFromPath(cssPath)}`); +// } + +// const cssOptions = { +// compress: true, +// }; +// const cssObfuscatedContent = css.stringify(cssObj, cssOptions); + +// const sizeBefore = Buffer.byteLength(cssContent, "utf8"); +// fs.writeFileSync(outCssPath, cssObfuscatedContent); +// const sizeAfter = Buffer.byteLength(cssObfuscatedContent, "utf8"); +// const percentChange = Math.round(((sizeAfter) / sizeBefore) * 100); +// log("success", "CSS obfuscated:", `Size from ${sizeBefore} to ${sizeAfter} bytes (${percentChange}%) in ${getFilenameFromPath(cssPath)}`); +// } + +/** + * + */ +export const obfuscateCssFiles = async ({ + selectorConversionJsonFolderPath, + buildFolderPath, + whiteListedFolderPaths = [], + blackListedFolderPaths = [], + mode = "random", + prefix, + suffix, + classIgnore = [], + generatorSeed = new Date().getTime().toString(), + removeOriginalCss = false, +}: { + selectorConversionJsonFolderPath: string, + buildFolderPath: string, + whiteListedFolderPaths: (string | RegExp)[], + blackListedFolderPaths: (string | RegExp)[], + mode?: obfuscateMode, + prefix?: string, + suffix?: string, + classIgnore?: (string | RegExp)[], + generatorSeed?: string, + removeOriginalCss?: boolean, +}) => { + // Initialize nessesary modules + await Promise.all([ + initTransform(), + lightningcssInit(), + ]); + + // Create the selector conversion JSON folder if it doesn't exist + if (!fs.existsSync(selectorConversionJsonFolderPath)) { + fs.mkdirSync(selectorConversionJsonFolderPath); + } + + // Load and merge all JSON files in the selector conversion folder + const conversionTables = loadConversionTables(selectorConversionJsonFolderPath); + + // get all css selectors + const cssPaths = findAllFilesWithExt(".css", buildFolderPath, { + blackListedFolderPaths: blackListedFolderPaths, + whiteListedFolderPaths: whiteListedFolderPaths, + }); + const tables: ConversionTables = { + selector: {}, + ident: {}, + }; + cssPaths.forEach(async (cssPath) => { + const { conversionTables: newConversionTables } = await obfuscateCss({ + cssPath: cssPath, + conversionTables: conversionTables, + + prefix, + suffix, + mode, + classIgnore, + generatorSeed, + removeOriginalCss, + }); + + // Merge the conversion tables + Object.entries(newConversionTables.selector).forEach(([key, value]) => { + if (!tables.selector[key]) { + // If it doesn't exist, create a new entry + tables.selector[key] = value; + } + }); + Object.entries(newConversionTables.ident).forEach(([key, value]) => { + if (!tables.ident[key]) { + // If it doesn't exist, create a new entry + tables.ident[key] = value; + } + }); + }); + + return { + conversionTables: tables, + }; +} diff --git a/src/index.ts b/src/index.ts index c76898b..932442d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,19 @@ -import fs from "fs"; -import path from "path"; +import type { Options, OptionalOptions } from "./types"; + +import fs from "node:fs"; +import path from "node:path"; import yargs from "yargs"; import { log, replaceJsonKeysInFiles, setLogLevel, findAllFilesWithExt, + getFilenameFromPath, } from "./utils"; - -import { createSelectorConversionJson } from "./handlers/css"; - +import { createSelectorConversionJson, obfuscateCss, obfuscateCssFiles } from "./handlers/css"; import Config from "./config"; -import { Options, OptionalOptions } from "./types"; -function obfuscate(options: Options) { +const obfuscate = async (options: Options) => { setLogLevel(options.logLevel); if (!options.enable) { @@ -31,19 +31,42 @@ function obfuscate(options: Options) { } log("info", "Obfuscation", "Creating/Updating class conversion JSON"); - createSelectorConversionJson({ + + // Create conversion tables and obfuscate CSS files + const { conversionTables } = await obfuscateCssFiles({ selectorConversionJsonFolderPath: options.classConversionJsonFolderPath, buildFolderPath: options.buildFolderPath, + whiteListedFolderPaths: [...options.whiteListedFolderPaths, ...(options.includeAnyMatchRegexes || [])], + blackListedFolderPaths: [...options.blackListedFolderPaths, ...(options.excludeAnyMatchRegexes || [])], mode: options.mode, - classNameLength: options.classLength, - classPrefix: options.classPrefix, - classSuffix: options.classSuffix, + prefix: options.classPrefix, + suffix: options.classSuffix, classIgnore: options.classIgnore, - enableObfuscateMarkerClasses: options.enableMarkers, - generatorSeed: options.generatorSeed === "-1" ? undefined : options.generatorSeed, + generatorSeed: options.generatorSeed, + removeOriginalCss: options.removeOriginalCss, }); + + // Save the conversion table to a JSON file + const jsonPath = path.join(process.cwd(), options.classConversionJsonFolderPath, "conversion.json"); + console.log({ jsonPath }); + fs.writeFileSync(jsonPath, JSON.stringify(conversionTables, null, 2)); + log("success", "CSS obfuscation:", `Saved conversion table to ${getFilenameFromPath(jsonPath)}`); + + // createSelectorConversionJson({ + // selectorConversionJsonFolderPath: options.classConversionJsonFolderPath, + // buildFolderPath: options.buildFolderPath, + + // mode: options.mode, + // classNameLength: options.classLength, + // classPrefix: options.classPrefix, + // classSuffix: options.classSuffix, + // classIgnore: options.classIgnore, + + // enableObfuscateMarkerClasses: options.enableMarkers, + // generatorSeed: options.generatorSeed === "-1" ? undefined : options.generatorSeed, + // }); log("success", "Obfuscation", "Class conversion JSON created/updated"); if ((options.includeAnyMatchRegexes && options.includeAnyMatchRegexes.length > 0) @@ -52,9 +75,9 @@ function obfuscate(options: Options) { } replaceJsonKeysInFiles({ + conversionTables: conversionTables, targetFolder: options.buildFolderPath, allowExtensions: options.allowExtensions, - selectorConversionJsonFolderPath: options.classConversionJsonFolderPath, contentIgnoreRegexes: options.contentIgnoreRegexes, @@ -63,20 +86,19 @@ function obfuscate(options: Options) { enableObfuscateMarkerClasses: options.enableMarkers, obfuscateMarkerClasses: options.markers, removeObfuscateMarkerClassesAfterObfuscated: options.removeMarkersAfterObfuscated, - removeOriginalCss: options.removeOriginalCss, enableJsAst: options.enableJsAst, }); } -function obfuscateCli() { +export const obfuscateCli = async () => { const argv = yargs.option("config", { alias: "c", type: "string", description: "Path to the config file" }).argv; - let configPath; + let configPath: string | undefined = undefined; // @ts-ignore if (argv.config) { @@ -100,8 +122,8 @@ function obfuscateCli() { } const config = new Config(configPath ? require(configPath) : undefined).get(); - obfuscate(config); + await obfuscate(config); log("success", "Obfuscation", "Completed~"); } -export { obfuscateCli, type OptionalOptions as Options }; +export { type OptionalOptions as Options }; diff --git a/src/types.ts b/src/types.ts index a45bdf6..8d9387d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,8 @@ +import type { ConversionTables } from "css-seasoning"; + type LogLevel = "debug" | "info" | "warn" | "error" | "success"; -type obfuscateMode = "random" | "simplify" | "simplify-seedable"; -type SelectorConversion = { [key: string]: string }; +type obfuscateMode = "random" | "simplify"; +type SelectorConversion = ConversionTables["selector"]; type Options = { enable: boolean; @@ -73,7 +75,7 @@ type OptionalOptions = { interface HtmlCharacterEntityConversion { [key: string]: string; - } +} export { type LogLevel, diff --git a/src/utils.ts b/src/utils.ts index 510218a..721ce5f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -6,6 +6,7 @@ import type { SelectorConversion, HtmlCharacterEntityConversion } from "./types"; +import { cssEscape, type ConversionTables } from "css-seasoning"; import { obfuscateCss } from "./handlers/css"; import { obfuscateHtmlClassNames } from "./handlers/html"; @@ -75,12 +76,11 @@ function setLogLevel(level: LogLevel) { const usedKeyRegistery = new Set(); - -function replaceJsonKeysInFiles( +const replaceJsonKeysInFiles = ( { + conversionTables, targetFolder, allowExtensions, - selectorConversionJsonFolderPath, contentIgnoreRegexes, @@ -89,13 +89,12 @@ function replaceJsonKeysInFiles( enableObfuscateMarkerClasses, obfuscateMarkerClasses, removeObfuscateMarkerClassesAfterObfuscated, - removeOriginalCss, enableJsAst, }: { + conversionTables: ConversionTables, targetFolder: string, allowExtensions: string[], - selectorConversionJsonFolderPath: string, contentIgnoreRegexes: RegExp[], @@ -104,17 +103,14 @@ function replaceJsonKeysInFiles( enableObfuscateMarkerClasses: boolean, obfuscateMarkerClasses: string[], removeObfuscateMarkerClassesAfterObfuscated: boolean, - removeOriginalCss: boolean, enableJsAst: boolean, - }) { + }) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js - const classConversion: SelectorConversion = loadAndMergeJsonFiles(selectorConversionJsonFolderPath); - if (removeObfuscateMarkerClassesAfterObfuscated) { obfuscateMarkerClasses.forEach(obfuscateMarkerClass => { - classConversion[`.${obfuscateMarkerClass}`] = ""; + conversionTables.selector[cssEscape(`.${obfuscateMarkerClass}`)] = ""; }); } @@ -131,7 +127,6 @@ function replaceJsonKeysInFiles( } else if ( allowExtensions.includes(fileExt) ) { - let isTargetFile = true; if (whiteListedFolderPaths.length > 0) { isTargetFile = whiteListedFolderPaths.some((incloudPath) => { @@ -172,45 +167,9 @@ function replaceJsonKeysInFiles( const htmlMatch = fileContent.match(htmlRegex); if (htmlMatch) { const htmlOriginal = htmlMatch[0]; - // let html = htmlOriginal; - - //! rollback - // const tagContents = findHtmlTagContentsByClass(html, obfuscateMarkerClass); - // tagContents.forEach(tagContent => { - // const { obfuscatedContent, usedKeys } = obfuscateKeys(classConversion, tagContent, contentIgnoreRegexes); - // addKeysToRegistery(usedKeys); - // if (tagContent !== obfuscatedContent) { - // html = html.replace(tagContent, obfuscatedContent); - // log("debug", `Obscured keys under HTML tag in file:`, normalizePath(filePath)); - // } - // }); - - //! rollback - // const scriptTagContents = findHtmlTagContents(html, "script"); - // scriptTagContents.forEach(scriptTagContent => { - // const obfuscateScriptContent = obfuscateJs( - // scriptTagContent, - // obfuscateMarkerClass, - // classConversion, - // filePath, - // contentIgnoreRegexes, - // enableJsAst - // ); - // if (scriptTagContent !== obfuscateScriptContent) { - // html = html.replace(scriptTagContent, obfuscateScriptContent); - // log("debug", `Obscured keys under HTML script tag in file:`, normalizePath(filePath)); - // } - // }); - - //! rollback - // if (htmlOriginal !== html) { - // fileContent = fileContent.replace(htmlOriginal, html); - // } - - //! NEW const { obfuscatedContent, usedKeys } = obfuscateHtmlClassNames({ html: htmlOriginal, - selectorConversion: classConversion, + selectorConversion: conversionTables.selector, obfuscateMarkerClass: obfuscateMarkerClass, contentIgnoreRegexes: contentIgnoreRegexes, }); @@ -222,7 +181,7 @@ function replaceJsonKeysInFiles( } else { const obfuscateScriptContent = obfuscateJs(fileContent, obfuscateMarkerClass, - classConversion, + conversionTables.selector, filePath, contentIgnoreRegexes, enableJsAst @@ -241,7 +200,7 @@ function replaceJsonKeysInFiles( const obfuscateScriptContent = obfuscateJs( fileContent, enableJsAst ? "" : "jsx", - classConversion, + conversionTables.selector, filePath, contentIgnoreRegexes, enableJsAst @@ -254,7 +213,7 @@ function replaceJsonKeysInFiles( //! NEW const { obfuscatedContent, usedKeys } = obfuscateHtmlClassNames({ html: fileContent, - selectorConversion: classConversion, + selectorConversion: conversionTables.selector, contentIgnoreRegexes: contentIgnoreRegexes, }); @@ -262,7 +221,7 @@ function replaceJsonKeysInFiles( addKeysToRegistery(usedKeys); } else { const { obfuscatedContent, usedKeys } = obfuscateKeys( - classConversion, + conversionTables.selector, fileContent, contentIgnoreRegexes ); @@ -287,10 +246,9 @@ function replaceJsonKeysInFiles( replaceJsonKeysInFile(targetFolder); // Obfuscate CSS files - cssPaths.forEach((cssPath) => { - obfuscateCss(classConversion, cssPath, removeOriginalCss, !enableObfuscateMarkerClasses); - }); - + // cssPaths.forEach(async (cssPath) => { + // await obfuscateCss(classConversion, cssPath, removeOriginalCss, !enableObfuscateMarkerClasses); + // }); } function obfuscateKeys( @@ -468,34 +426,70 @@ function findContentBetweenMarker(content: string, targetStr: string, openMarker return truncatedContents; } -function addKeysToRegistery(usedKeys: Set | string[]) { +export function addKeysToRegistery(usedKeys: Set | string[]) { usedKeys.forEach((key) => { usedKeyRegistery.add(key); }); } /** - * Find all files with the specified extension in the build folder - * @param ext - the extension of the files to find (e.g. .css) "." is required - * @param targetFolderPath - the path to the folder to start searching from - * @returns - an array of file relative paths + * Find all files with the specified extension in the build folder. + * + * @param ext - the extension of the files to find (e.g. .css) "." is required. + * @param targetFolderPath - the path to the folder to start searching from. + * @param options - optional parameters. + * @param options.whiteListedFolderPaths - an array of folder paths to include in the search. + * @param options.blackListedFolderPaths - an array of folder paths to exclude from the search. Higher priority than whiteListedFolderPaths. + * @returns - an array of file relative paths. */ -function findAllFilesWithExt(ext: string, targetFolderPath: string): string[] { +const findAllFilesWithExt = ( + ext: string, targetFolderPath: string, + options?: { + whiteListedFolderPaths?: (string | RegExp)[], + blackListedFolderPaths?: (string | RegExp)[], + } +): string[] => { if (!fs.existsSync(targetFolderPath)) { return []; } const targetExtFiles: string[] = []; + const whiteList = options?.whiteListedFolderPaths || []; + const blackList = options?.blackListedFolderPaths || []; - function findCssFiles(dir: string) { + const findFiles = (dir: string) => { const files = fs.readdirSync(dir); files.forEach((file) => { const filePath = normalizePath(path.join(dir, file)); + // Check if the path is blacklisted (higher priority) + const isBlacklisted = blackList.some((excludePath) => { + if (typeof excludePath === "string") { + return filePath.includes(excludePath); + } + return excludePath.test(filePath); + }); + + if (isBlacklisted) { + return; // Skip this file/directory + } + + // Check if the path is whitelisted (if whitelist is not empty) + const isWhitelisted = whiteList.length === 0 || whiteList.some((includePath) => { + if (typeof includePath === "string") { + return filePath.includes(includePath); + } + return includePath.test(filePath); + }); + + if (!isWhitelisted) { + return; // Skip this file/directory + } + if (fs.statSync(filePath).isDirectory()) { - // if it's a directory, recursively search for CSS files - findCssFiles(filePath); + // if it's a directory, recursively search for files + findFiles(filePath); } else { // check if the file has the specified extension if (file.endsWith(ext)) { @@ -505,8 +499,8 @@ function findAllFilesWithExt(ext: string, targetFolderPath: string): string[] { }); } - // start searching for CSS files from the specified directory - findCssFiles(targetFolderPath); + // start searching for files from the specified directory + findFiles(targetFolderPath); return targetExtFiles; } @@ -637,10 +631,57 @@ function decodeKey(str: string) { return str; } +/** + * Convert a string to a number by summing the char codes of each character + * + * @param str - The string to convert + * @returns The sum of the char codes of each character in the string + * + * @example + * stringToNumber("abc") // returns 294 (97 + 98 + 99) + * stringToNumber("hello") // returns 532 (104 + 101 + 108 + 108 + 111) + */ +export const stringToNumber = (str: string) => { + return str.split("").reduce((acc, char) => { + return acc + char.charCodeAt(0); + }, 0); +} + + +/** + * Loads and merges all JSON files (Conversion Tables) in the specified folder. + * + * @param folderPath - The folder path to load the conversion tables from. + * @returns ConversionTables - The merged conversion tables. + */ +export const loadConversionTables = (folderPath: string): ConversionTables => { + const tables: ConversionTables = { + ident: {}, + selector: {}, + }; + + fs.readdirSync(folderPath).forEach((file: string) => { + const filePath = path.join(folderPath, file); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf-8")); + + if (Object.keys(fileData).includes("ident") && Object.keys(fileData).includes("selector")) { + Object.assign(tables.ident, fileData.ident); + Object.assign(tables.selector, fileData.selector); + } else { + // if the file doesn't have ident, it should be selector + //? For backward compatibility + Object.assign(tables.selector, fileData); + } + }); + + return tables; +} + + export { getFilenameFromPath, log, normalizePath, loadAndMergeJsonFiles , replaceJsonKeysInFiles, setLogLevel, findContentBetweenMarker, replaceFirstMatch , findAllFilesWithExt, getRandomString, seedableSimplifyString, usedKeyRegistery - , obfuscateKeys, findClosestSymbolPosition, addKeysToRegistery, duplicationCheck + , obfuscateKeys, findClosestSymbolPosition, duplicationCheck , createKey, decodeKey, simplifyString }; From 10e0ac1fb5c97de4fc277752bf5af6f434684e33 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:33:24 +0100 Subject: [PATCH 05/28] refactor: Remove deprecated functions and streamline path filtering logic --- src/handlers/css.ts | 232 ++------------------------------------------ src/index.ts | 31 ++---- src/types.ts | 38 ++------ src/utils.ts | 91 +++++++++-------- 4 files changed, 64 insertions(+), 328 deletions(-) diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 95d3ea4..138270c 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -157,143 +157,6 @@ function getAllSelector(cssObj: any): any[] { return selectors; } -/** - * - * @deprecated will be replaced by new css transformer - */ -export function createSelectorConversionJson( - { - selectorConversionJsonFolderPath, - buildFolderPath, - - mode = "random", - classNameLength = 5, - classPrefix = "", - classSuffix = "", - classIgnore = [], - - enableObfuscateMarkerClasses = false, - generatorSeed = Math.random().toString().slice(2, 10), // take 8 digits from the random number - }: { - selectorConversionJsonFolderPath: string, - buildFolderPath: string, - - mode?: obfuscateMode, - classNameLength?: number, - classPrefix?: string, - classSuffix?: string, - classIgnore?: (string | RegExp)[], - - enableObfuscateMarkerClasses?: boolean, - generatorSeed?: string, - }) { - // if (!fs.existsSync(selectorConversionJsonFolderPath)) { - // fs.mkdirSync(selectorConversionJsonFolderPath); - // } - - // const selectorConversion = loadConversionTables(selectorConversionJsonFolderPath); - - // // pre-defined ".dark", mainly for tailwindcss dark mode - // if (enableObfuscateMarkerClasses) { - // selectorConversion[".dark"] = ".dark"; - // } - - // // get all css selectors - // const cssPaths = findAllFilesWithExt(".css", buildFolderPath); - // const selectors: string[] = []; - // cssPaths.forEach((cssPath) => { - // const cssContent = fs.readFileSync(cssPath, "utf-8"); - // const cssObj = css.parse(cssContent); - // selectors.push(...getAllSelector(cssObj)); - // }); - - // // remove duplicated selectors - // const uniqueSelectors = [...new Set(selectors)]; - - // const allowClassStartWith = [".", "#", ":is(", ":where(", ":not(" - // , ":matches(", ":nth-child(", ":nth-last-child(" - // , ":nth-of-type(", ":nth-last-of-type(", ":first-child(" - // , ":last-child(", ":first-of-type(", ":last-of-type(" - // , ":only-child(", ":only-of-type(", ":empty(", ":link(" - // , ":visited(", ":active(", ":hover(", ":focus(", ":target(" - // , ":lang(", ":enabled(", ":disabled(", ":checked(", ":default(" - // , ":indeterminate(", ":root(", ":before(" - // , ":after(", ":first-letter(", ":first-line(", ":selection(" - // , ":read-only(", ":read-write(", ":fullscreen(", ":optional(" - // , ":required(", ":valid(", ":invalid(", ":in-range(", ":out-of-range(" - // , ":placeholder-shown(" - // ]; - - // const selectorClassPair: { [key: string]: string[] } = {}; - - // for (let i = 0; i < uniqueSelectors.length; i++) { - // const originalSelector = uniqueSelectors[i]; - // const { extractedClasses } = extractClassFromSelector(originalSelector) || []; - // selectorClassPair[originalSelector] = extractedClasses; - // } - - // //? since a multi part selector normally grouped by multiple basic selectors - // //? so we need to obfuscate the basic selector first - // //? eg. ":is(.class1 .class2)" grouped by ".class1" and ".class2" - // // sort the selectorClassPair by the number of classes in the selector (from least to most) - // // and remove the selector with no class - // const sortedSelectorClassPair = Object.entries(selectorClassPair) - // .sort((a, b) => a[1].length - b[1].length) - // .filter((pair) => pair[1].length > 0); - - // for (let i = 0; i < sortedSelectorClassPair.length; i++) { - // const [originalSelector, selectorClasses] = sortedSelectorClassPair[i]; - // if (selectorClasses.length == 0) { - // continue; - // } - - // let selector = originalSelector; - // let classes = selectorClasses; - - // if (classes && allowClassStartWith.some((start) => selector.startsWith(start))) { - // classes = classes.map((className) => { - - // // apply ignore list - // if (classIgnore.some(regex => { - // if (typeof regex === "string") { - // return className === regex; - // } - // return new RegExp(regex).test(className) - // })) { - // return className; - // } - - // // try to get the obfuscated selector from the selectorConversion - // // if not found, create a new one - // let obfuscatedSelector = selectorConversion[`.${className}`]; - // if (!obfuscatedSelector) { - // const obfuscatedClass = createNewClassName(mode, className, classPrefix, classSuffix, classNameLength, generatorSeed); - // obfuscatedSelector = `.${obfuscatedClass}`; - // selectorConversion[`.${className}`] = obfuscatedSelector; - // } - - // // return the obfuscated class - // return obfuscatedSelector.slice(1) - // }); - - // // obfuscate the selector - // const { selector: obfuscatedSelector } = extractClassFromSelector(originalSelector, classes); - - // selectorConversion[originalSelector] = obfuscatedSelector; - // } - // } - - // const jsonPath = path.join(process.cwd(), selectorConversionJsonFolderPath, "conversion.json"); - // fs.writeFileSync(jsonPath, JSON.stringify(selectorConversion, null, 2)); - // if (duplicationCheck(Object.keys(selectorConversion))) { - // if (mode == "random") { - // log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, try to increase the class name length / open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); - // } else { - // log("error", "Obfuscation", "Duplicated class names found in the conversion JSON, please open an issue on GitHub https://github.com/soranoo/next-css-obfuscator/issues"); - // } - // } -} - export function copyCssData(targetSelector: string, newSelectorName: string, cssObj: any) { function recursive(rules: any[]): any[] { return rules.map((item: any) => { @@ -349,11 +212,8 @@ export function renameCssSelector(oldSelector: string, newSelector: string, cssO return cssObj; } -/** - * - * @deprecated WIP - */ -export const obfuscateCss = async ({ + +const obfuscateCss = async ({ cssPath, removeOriginalCss, isFullObfuscation, @@ -451,86 +311,6 @@ export const obfuscateCss = async ({ } } -// export const obfuscateCss = async ( -// selectorConversion: ConversionTable, -// cssPath: string, -// replaceOriginalSelector = false, -// isFullObfuscation = false, -// outCssPath?: string, -// ) => { -// if (!outCssPath) { -// outCssPath = cssPath; -// } else if (!fs.existsSync(path.dirname(outCssPath))) { -// fs.mkdirSync(path.dirname(outCssPath)); -// } - -// const cssContent = fs.readFileSync(cssPath, "utf-8"); - -// let cssObj = css.parse(cssContent); -// const cssRulesCount = cssObj.stylesheet.rules.length; - -// if (isFullObfuscation) { -// Object.keys(selectorConversion).forEach((key) => { -// usedKeyRegistery.add(key); -// }); -// } else { -// // join all selectors start with ":" (eg. ":is") -// Object.keys(selectorConversion).forEach((key) => { -// if (key.startsWith(":")) { -// usedKeyRegistery.add(key); -// } -// }); - -// // join all selectors with action selectors -// const actionSelectors = getAllSelector(cssObj).filter((selector) => selector.match(findActionSelectorsRegex)); -// actionSelectors.forEach((actionSelector) => { -// usedKeyRegistery.add(actionSelector); -// }); - -// // join all Tailwind CSS [child] selectors (eg. ".\[\&_\.side-box\]\:absolute .side-box") -// const tailwindCssChildSelectors = getAllSelector(cssObj).filter((selector) => selector.startsWith(".\\[")); -// tailwindCssChildSelectors.forEach((tailwindCssChildSelector) => { -// usedKeyRegistery.add(tailwindCssChildSelector); -// }); - -// // join all child selectors (eg. ">*") -// const universalSelectors = getAllSelector(cssObj).filter((selector) => selector.includes(">")); -// universalSelectors.forEach((universalSelector) => { -// usedKeyRegistery.add(universalSelector); -// }); -// } - -// // modify css rules -// usedKeyRegistery.forEach((key) => { -// const originalSelectorName = key; -// const obfuscatedSelectorName = selectorConversion[key]; -// if (obfuscatedSelectorName) { -// if (replaceOriginalSelector) { -// cssObj = renameCssSelector(originalSelectorName, selectorConversion[key], cssObj); -// } else { -// cssObj = copyCssData(originalSelectorName, selectorConversion[key], cssObj); -// } -// } -// }); - -// if (replaceOriginalSelector) { -// log("info", "CSS rules:", `Modified ${usedKeyRegistery.size} CSS rules to ${getFilenameFromPath(cssPath)}`); -// } else { -// log("info", "CSS rules:", `Added ${cssObj.stylesheet.rules.length - cssRulesCount} new CSS rules to ${getFilenameFromPath(cssPath)}`); -// } - -// const cssOptions = { -// compress: true, -// }; -// const cssObfuscatedContent = css.stringify(cssObj, cssOptions); - -// const sizeBefore = Buffer.byteLength(cssContent, "utf8"); -// fs.writeFileSync(outCssPath, cssObfuscatedContent); -// const sizeAfter = Buffer.byteLength(cssObfuscatedContent, "utf8"); -// const percentChange = Math.round(((sizeAfter) / sizeBefore) * 100); -// log("success", "CSS obfuscated:", `Size from ${sizeBefore} to ${sizeAfter} bytes (${percentChange}%) in ${getFilenameFromPath(cssPath)}`); -// } - /** * */ @@ -571,15 +351,17 @@ export const obfuscateCssFiles = async ({ // Load and merge all JSON files in the selector conversion folder const conversionTables = loadConversionTables(selectorConversionJsonFolderPath); - // get all css selectors + // Get all CSS files using the unified path filtering function const cssPaths = findAllFilesWithExt(".css", buildFolderPath, { - blackListedFolderPaths: blackListedFolderPaths, - whiteListedFolderPaths: whiteListedFolderPaths, + whiteListedFolderPaths, + blackListedFolderPaths, }); + const tables: ConversionTables = { selector: {}, ident: {}, }; + cssPaths.forEach(async (cssPath) => { const { conversionTables: newConversionTables } = await obfuscateCss({ cssPath: cssPath, diff --git a/src/index.ts b/src/index.ts index 932442d..fe7e6ad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,7 @@ import { findAllFilesWithExt, getFilenameFromPath, } from "./utils"; -import { createSelectorConversionJson, obfuscateCss, obfuscateCssFiles } from "./handlers/css"; +import { obfuscateCssFiles } from "./handlers/css"; import Config from "./config"; const obfuscate = async (options: Options) => { @@ -36,8 +36,8 @@ const obfuscate = async (options: Options) => { const { conversionTables } = await obfuscateCssFiles({ selectorConversionJsonFolderPath: options.classConversionJsonFolderPath, buildFolderPath: options.buildFolderPath, - whiteListedFolderPaths: [...options.whiteListedFolderPaths, ...(options.includeAnyMatchRegexes || [])], - blackListedFolderPaths: [...options.blackListedFolderPaths, ...(options.excludeAnyMatchRegexes || [])], + whiteListedFolderPaths: options.whiteListedFolderPaths, + blackListedFolderPaths: options.blackListedFolderPaths, mode: options.mode, prefix: options.classPrefix, @@ -54,26 +54,7 @@ const obfuscate = async (options: Options) => { fs.writeFileSync(jsonPath, JSON.stringify(conversionTables, null, 2)); log("success", "CSS obfuscation:", `Saved conversion table to ${getFilenameFromPath(jsonPath)}`); - // createSelectorConversionJson({ - // selectorConversionJsonFolderPath: options.classConversionJsonFolderPath, - // buildFolderPath: options.buildFolderPath, - - // mode: options.mode, - // classNameLength: options.classLength, - // classPrefix: options.classPrefix, - // classSuffix: options.classSuffix, - // classIgnore: options.classIgnore, - - // enableObfuscateMarkerClasses: options.enableMarkers, - // generatorSeed: options.generatorSeed === "-1" ? undefined : options.generatorSeed, - // }); - log("success", "Obfuscation", "Class conversion JSON created/updated"); - - if ((options.includeAnyMatchRegexes && options.includeAnyMatchRegexes.length > 0) - || (options.excludeAnyMatchRegexes && options.excludeAnyMatchRegexes.length > 0)) { - log("warn", "Obfuscation", "'includeAnyMatchRegexes' and 'excludeAnyMatchRegexes' are deprecated, please use whiteListedFolderPaths and blackListedFolderPaths instead"); - } - + // Use the same unified paths for replacing JSON keys in files replaceJsonKeysInFiles({ conversionTables: conversionTables, targetFolder: options.buildFolderPath, @@ -81,8 +62,8 @@ const obfuscate = async (options: Options) => { contentIgnoreRegexes: options.contentIgnoreRegexes, - whiteListedFolderPaths: [...options.whiteListedFolderPaths, ...(options.includeAnyMatchRegexes || [])], - blackListedFolderPaths: [...options.blackListedFolderPaths, ...(options.excludeAnyMatchRegexes || [])], + whiteListedFolderPaths: options.whiteListedFolderPaths, + blackListedFolderPaths: options.blackListedFolderPaths, enableObfuscateMarkerClasses: options.enableMarkers, obfuscateMarkerClasses: options.markers, removeObfuscateMarkerClassesAfterObfuscated: options.removeMarkersAfterObfuscated, diff --git a/src/types.ts b/src/types.ts index 8d9387d..11bc364 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,10 +1,10 @@ import type { ConversionTables } from "css-seasoning"; -type LogLevel = "debug" | "info" | "warn" | "error" | "success"; -type obfuscateMode = "random" | "simplify"; -type SelectorConversion = ConversionTables["selector"]; +export type LogLevel = "debug" | "info" | "warn" | "error" | "success"; +export type obfuscateMode = "random" | "simplify"; +export type SelectorConversion = ConversionTables["selector"]; -type Options = { +export type Options = { enable: boolean; mode: obfuscateMode; buildFolderPath: string; @@ -20,14 +20,6 @@ type Options = { whiteListedFolderPaths: (string | RegExp)[]; blackListedFolderPaths: (string | RegExp)[]; - /** - * @deprecated - */ - includeAnyMatchRegexes?: RegExp[]; - /** - * @deprecated - */ - excludeAnyMatchRegexes?: RegExp[]; enableMarkers: boolean; markers: string[]; removeMarkersAfterObfuscated: boolean; @@ -38,7 +30,8 @@ type Options = { logLevel: LogLevel; } -type OptionalOptions = { + +export type OptionalOptions = { enable?: boolean; mode?: obfuscateMode; buildFolderPath?: string; @@ -54,14 +47,6 @@ type OptionalOptions = { whiteListedFolderPaths?: (string | RegExp)[]; blackListedFolderPaths?: (string | RegExp)[]; - /** - * @deprecated - */ - includeAnyMatchRegexes?: RegExp[]; - /** - * @deprecated - */ - excludeAnyMatchRegexes?: RegExp[]; enableMarkers?: boolean; markers?: string[]; removeMarkersAfterObfuscated?: boolean; @@ -73,15 +58,6 @@ type OptionalOptions = { logLevel?: LogLevel; } -interface HtmlCharacterEntityConversion { +export interface HtmlCharacterEntityConversion { [key: string]: string; } - -export { - type LogLevel, - type obfuscateMode, - type SelectorConversion, - type Options, - type OptionalOptions, - type HtmlCharacterEntityConversion -} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 721ce5f..77652fd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,14 +4,51 @@ import NumberGenerator from "recoverable-random"; import type { LogLevel, SelectorConversion, - HtmlCharacterEntityConversion } from "./types"; import { cssEscape, type ConversionTables } from "css-seasoning"; -import { obfuscateCss } from "./handlers/css"; import { obfuscateHtmlClassNames } from "./handlers/html"; import { obfuscateJs } from "./handlers/js"; +// Add a new function for path filtering +/** + * Checks if a path should be included based on whitelist and blacklist rules + * + * @param filePath - The file path to check + * @param whiteListedFolderPaths - Paths to include + * @param blackListedFolderPaths - Paths to exclude (higher priority than whitelist) + * @returns - True if the path should be included, false otherwise + */ +function shouldIncludePath( + filePath: string, + whiteListedFolderPaths: (string | RegExp)[] = [], + blackListedFolderPaths: (string | RegExp)[] = [] +): boolean { + const normalizedPath = normalizePath(filePath); + + // Check if the path is blacklisted (higher priority) + const isBlacklisted = blackListedFolderPaths.some((excludePath) => { + if (typeof excludePath === "string") { + return normalizedPath.includes(excludePath); + } + return excludePath.test(normalizedPath); + }); + + if (isBlacklisted) { + return false; // Skip this file/directory + } + + // Check if the path is whitelisted (if whitelist is not empty) + const isWhitelisted = whiteListedFolderPaths.length === 0 || whiteListedFolderPaths.some((includePath) => { + if (typeof includePath === "string") { + return normalizedPath.includes(includePath); + } + return includePath.test(normalizedPath); + }); + + return isWhitelisted; +} + //! ==================== //! Log //! ==================== @@ -127,29 +164,8 @@ const replaceJsonKeysInFiles = ( } else if ( allowExtensions.includes(fileExt) ) { - let isTargetFile = true; - if (whiteListedFolderPaths.length > 0) { - isTargetFile = whiteListedFolderPaths.some((incloudPath) => { - if (typeof incloudPath === "string") { - return normalizePath(filePath).includes(incloudPath); - } - const regex = new RegExp(incloudPath); - return regex.test(normalizePath(filePath)); - }); - } - if (blackListedFolderPaths.length > 0) { - const res = !blackListedFolderPaths.some((incloudPath) => { - if (typeof incloudPath === "string") { - return normalizePath(filePath).includes(incloudPath); - } - const regex = new RegExp(incloudPath); - return regex.test(normalizePath(filePath)); - }); - if (!res) { - isTargetFile = false; - } - } - if (!isTargetFile) { + // Use the unified path filtering function + if (!shouldIncludePath(filePath, whiteListedFolderPaths, blackListedFolderPaths)) { return; } @@ -461,29 +477,9 @@ const findAllFilesWithExt = ( const files = fs.readdirSync(dir); files.forEach((file) => { - const filePath = normalizePath(path.join(dir, file)); - - // Check if the path is blacklisted (higher priority) - const isBlacklisted = blackList.some((excludePath) => { - if (typeof excludePath === "string") { - return filePath.includes(excludePath); - } - return excludePath.test(filePath); - }); + const filePath = path.join(dir, file); - if (isBlacklisted) { - return; // Skip this file/directory - } - - // Check if the path is whitelisted (if whitelist is not empty) - const isWhitelisted = whiteList.length === 0 || whiteList.some((includePath) => { - if (typeof includePath === "string") { - return filePath.includes(includePath); - } - return includePath.test(filePath); - }); - - if (!isWhitelisted) { + if (!shouldIncludePath(filePath, whiteList, blackList)) { return; // Skip this file/directory } @@ -685,3 +681,4 @@ export { , obfuscateKeys, findClosestSymbolPosition, duplicationCheck , createKey, decodeKey, simplifyString }; + From 3c1ca32b4411e07f5f216904d579c94690c46f46 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:53:16 +0100 Subject: [PATCH 06/28] refactor(css): Refactor CSS obfuscation with css-seasoning Refactors the CSS obfuscation process to leverage the `css-seasoning` library, replacing custom CSS parsing and manipulation logic. This change improves maintainability and leverages a dedicated library for CSS transformations. Removes the old CSS test file as the functionality is now covered by `css-seasoning`. --- package-lock.json | 4 +- src/__tests__/css.test.ts | 529 -------------------------------------- src/handlers/css.ts | 205 +-------------- src/handlers/html.ts | 3 +- src/utils.ts | 4 +- 5 files changed, 10 insertions(+), 735 deletions(-) delete mode 100644 src/__tests__/css.test.ts diff --git a/package-lock.json b/package-lock.json index 50d0aea..539af01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "next-css-obfuscator", - "version": "2.2.19", + "version": "3.0.0-b1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "next-css-obfuscator", - "version": "2.2.19", + "version": "3.0.0-b1", "license": "MIT", "dependencies": { "@babel/generator": "^7.23.6", diff --git a/src/__tests__/css.test.ts b/src/__tests__/css.test.ts deleted file mode 100644 index 0697f9b..0000000 --- a/src/__tests__/css.test.ts +++ /dev/null @@ -1,529 +0,0 @@ -import { describe, it, expect, test } from "vitest"; - -// @ts-ignore -import css from "css"; - -import { - copyCssData, - renameCssSelector, - extractClassFromSelector, -} from "../handlers/css"; - -const testCss = ` -.s0-1 { - background: #181810; - color: #181811; -} - -@media (min-width: 640px) -{ - .s1-1 - { - background: #181812; - color: #181813; - } - - @media (min-width: 768px) - { - .s2-1, .s2-1-1 { - background: #181814; - color: #181815; - }, - .s2-1, .s2-1-1 { - background: #181814; - color: #181815; - }, - .s2-2, .s2-2-2 { - background: #181816; - color: #181817; - }, - .s2-3 { - background: #181818; - color: #181819; - } - } - - .s1-2 - { - background: #181820; - color: #181821; - } -} - -.s0-2 { - background: #181822; - color: #181823; -} -` - -// function getCssRulesIncludedSelector(selector: string, cssObj: any): any[] { -// function recursive(rules: any[]) { -// for (const item of rules) { -// if (item.rules) { -// const result: any = recursive(item.rules); -// if (result !== null) { -// return [{ ...item, rules: result }]; -// } -// } else if (item.selectors.includes(selector)) { -// // remove empty selectors -// item.selectors = item.selectors.filter((selector: any) => selector !== ""); - -// return [{ ...item, selectors: [selector] }]; -// } -// } -// return null; -// } -// return recursive(cssObj.stylesheet.rules) || []; -// } - -// describe("getCssRulesIncludedSelector", () => { -// it("should return the correct CSS rules (single selector, no nested rule)", () => { -// const cssObj = css.parse(testCss); - -// const selector = ".s0-1"; -// const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }]; - -// const result = getCssRulesIncludedSelector(selector, cssObj); -// expect(result).toEqual(expectedOutput); -// }); - -// it("should return the correct CSS rules (multiple nested rules)", () => { -// const cssObj = css.parse(testCss); - -// const selector = ".s2-3"; -// const expectedOutput = [{ "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 29, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 36, "column": 2 } } }]; - -// const result = getCssRulesIncludedSelector(selector, cssObj); -// expect(result).toEqual(expectedOutput); -// }); - -// it("should return the correct CSS rules (multiple selector in same rule)", () => { -// const cssObj = css.parse(testCss); - -// const selector = ".s2-2-2"; -// const expectedOutput = [{ "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 29, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 36, "column": 2 } } }]; - -// const result = getCssRulesIncludedSelector(selector, cssObj); -// expect(result).toEqual(expectedOutput); -// }); - -// it("should return the empty array", () => { -// const cssObj = css.parse(testCss); - -// const selector = ".s2-2-3"; -// const expectedOutput: [] = []; - -// const result = getCssRulesIncludedSelector(selector, cssObj); -// expect(result).toEqual(expectedOutput); -// }); -// }); - - -//! ================================ -//! renameCssSelector -//! ================================ - -describe("renameCssSelector", () => { - it("should rename the CSS selector (single selector, no nested rule)", () => { - const cssObj = css.parse(testCss); - - const oldSelector = ".s1-1"; - const newSelector = ".s1-1-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = renameCssSelector(oldSelector, newSelector, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); - - it("should rename the CSS selector (multiple nested media queries)", () => { - const cssObj = css.parse(testCss); - - const oldSelector = ".s2-2"; - const newSelector = ".s2-2-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2-new", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = renameCssSelector(oldSelector, newSelector, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); -}); - -//! ================================ -//! copyCssData -//! ================================ - -describe("copyCssData", () => { - it("should copy the CSS data (single selector, no nested rule)", () => { - const cssObj = css.parse(testCss); - - const targetSelector = ".s0-2"; - const newSelectorName = ".s0-2-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = copyCssData(targetSelector, newSelectorName, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); - - it("should copy the CSS data (multiple nested rules)", () => { - const cssObj = css.parse(testCss); - - const targetSelector = ".s2-3"; - const newSelectorName = ".s2-3-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = copyCssData(targetSelector, newSelectorName, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); - - it("should copy the CSS data (multiple selector in same rule)", () => { - const cssObj = css.parse(testCss); - - const targetSelector = ".s2-2-2"; - const newSelectorName = ".s2-2-2-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2-2-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = copyCssData(targetSelector, newSelectorName, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); - - it("should copy the CSS data (same selector with different declarations)", () => { - const cssObj = css.parse(testCss); - - const targetSelector = ".s2-1"; - const newSelectorName = ".s2-1-new"; - const expectedOutput = [{ "type": "rule", "selectors": [".s0-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181810", "position": { "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181811", "position": { "start": { "line": 4, "column": 5 }, "end": { "line": 4, "column": 19 } } }], "position": { "start": { "line": 2, "column": 1 }, "end": { "line": 5, "column": 2 } } }, { "type": "media", "media": "(min-width: 640px)", "rules": [{ "type": "rule", "selectors": [".s1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181812", "position": { "start": { "line": 11, "column": 9 }, "end": { "line": 11, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181813", "position": { "start": { "line": 12, "column": 9 }, "end": { "line": 12, "column": 23 } } }], "position": { "start": { "line": 9, "column": 5 }, "end": { "line": 13, "column": 6 } } }, { "type": "media", "media": "(min-width: 768px)", "rules": [{ "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 18, "column": 13 }, "end": { "line": 18, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 19, "column": 13 }, "end": { "line": 19, "column": 27 } } }], "position": { "start": { "line": 17, "column": 9 }, "end": { "line": 20, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1", ".s2-1-1"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-1-new"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181814", "position": { "start": { "line": 22, "column": 13 }, "end": { "line": 22, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181815", "position": { "start": { "line": 23, "column": 13 }, "end": { "line": 23, "column": 27 } } }], "position": { "start": { "line": 20, "column": 10 }, "end": { "line": 24, "column": 10 } } }, { "type": "rule", "selectors": [".s2-2", ".s2-2-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181816", "position": { "start": { "line": 26, "column": 13 }, "end": { "line": 26, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181817", "position": { "start": { "line": 27, "column": 13 }, "end": { "line": 27, "column": 27 } } }], "position": { "start": { "line": 24, "column": 10 }, "end": { "line": 28, "column": 10 } } }, { "type": "rule", "selectors": [".s2-3"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181818", "position": { "start": { "line": 30, "column": 13 }, "end": { "line": 30, "column": 32 } } }, { "type": "declaration", "property": "color", "value": "#181819", "position": { "start": { "line": 31, "column": 13 }, "end": { "line": 31, "column": 27 } } }], "position": { "start": { "line": 28, "column": 10 }, "end": { "line": 32, "column": 10 } } }], "position": { "start": { "line": 15, "column": 5 }, "end": { "line": 33, "column": 6 } } }, { "type": "rule", "selectors": [".s1-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181820", "position": { "start": { "line": 37, "column": 9 }, "end": { "line": 37, "column": 28 } } }, { "type": "declaration", "property": "color", "value": "#181821", "position": { "start": { "line": 38, "column": 9 }, "end": { "line": 38, "column": 23 } } }], "position": { "start": { "line": 35, "column": 5 }, "end": { "line": 39, "column": 6 } } }], "position": { "start": { "line": 7, "column": 1 }, "end": { "line": 40, "column": 2 } } }, { "type": "rule", "selectors": [".s0-2"], "declarations": [{ "type": "declaration", "property": "background", "value": "#181822", "position": { "start": { "line": 43, "column": 5 }, "end": { "line": 43, "column": 24 } } }, { "type": "declaration", "property": "color", "value": "#181823", "position": { "start": { "line": 44, "column": 5 }, "end": { "line": 44, "column": 19 } } }], "position": { "start": { "line": 42, "column": 1 }, "end": { "line": 45, "column": 2 } } }]; - - const result = copyCssData(targetSelector, newSelectorName, cssObj); - expect(result.stylesheet.rules).toEqual(expectedOutput); - }); -}); - -//! ================================ -//! extractClassFromSelector -//! ================================ - -describe("extractClassFromSelector", () => { - - it("should extract single class from simple selector", () => { - const sample = ".example htmlTag"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["example"] - }); - }); - - test("should extract multiple classes from complex selector", () => { - const sample = ":is(.some-class .some-class\\:bg-dark::-moz-placeholder)[data-active=\'true\']"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["some-class", "some-class\\:bg-dark"] - }); - }); - - test("should handle selector with no classes", () => { - const sample = "div"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: [] - }); - }); - - test("should handle selector with action pseudo-classes and not extract them", () => { - const sample = ".btn:hover .btn-active::after"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["btn", "btn-active"] - }); - }); - - test("should handle selector with vendor pseudo-classes and not extract them", () => { - const sample = ".btn-moz:-moz-focusring .btn-ms::-ms-placeholder .btn-webkit::-webkit-placeholder .btn-o::-o-placeholder"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["btn-moz", "btn-ms", "btn-webkit", "btn-o"] - }); - }); - - test("should handle selector with escaped characters", () => { - const sample = ".escaped\\:class:action"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["escaped\\:class"] - }); - }); - - test("should handle selector with multiple classes separated by spaces", () => { - const sample = ".class1 .class2 .class3"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1", "class2", "class3"] - }); - }); - - test("should handle selector with multiple classes separated by commas", () => { - const sample = ".class1, .class2, .class3"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1", "class2", "class3"] - }); - }); - - test("should handle selector with a combination of classes and ids", () => { - const sample = ".class1 #id .class2"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1", "class2"] - }); - }); - - test("should handle [attribute] selector", () => { - const sample = ".class1[data-attr=\"value\"] .class2[data-attr='value']"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1", "class2"] - }); - }); - - test("should handle action pseudo-class selector correctly", () => { - const sample = ".class1\\:hover\\:class2:after .class3\\:hover\\:class4:after:hover :is(.class5 .class6\\:hover\\:class7:hover:after) :is(.hover\\:class8\\:class9):after>:last-child"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1\\:hover\\:class2", "class3\\:hover\\:class4", "class5", "class6\\:hover\\:class7", "hover\\:class8\\:class9"] - }); - }); - - test("should ignore [attribute] selector that not in the same scope as class", () => { - const sample = ":is(.class1 .class2\\:class3\\:\\!class4)[aria-selected=\"true\"]"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1", "class2\\:class3\\:\\!class4"] - }); - }); - - test("should return null for invalid input types", () => { - // Act & Assert - // @ts-ignore - expect(() => extractClassFromSelector(null)).toThrow(TypeError); - // @ts-ignore - expect(() => extractClassFromSelector(undefined)).toThrow(TypeError); - expect(() => extractClassFromSelector(123 as any)).toThrow(TypeError); - }); - - - //? ********************* - //? Tailwind CSS - //? ********************* - test("should handle Tailwind CSS important selector '!'", () => { - const sample = ".\\!my-0 .some-class\\:\\!bg-white"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["\\!my-0", "some-class\\:\\!bg-white"] - }) - }); - - test("should handle Tailwind CSS selector with start with '-'", () => { - const sample = ".-class-1"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["-class-1"] - }) - }); - - test("should handle Tailwind CSS selector with '.' at the number", () => { - const sample = ".class-0\\.5 .class-1\\.125"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class-0\\.5", "class-1\\.125"] - }) - }); - - test("should handle Tailwind CSS selector with '/' at the number", () => { - const sample = ".class-1\\/2"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class-1\\/2"] - }) - }); - - test("should handle Tailwind CSS selector with '%' at the number", () => { - const sample = ".\\[\\.class1\\]\\:to-85\\%"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["\\[\\.class1\\]\\:to-85\\%"] - }) - }); - - test("should handle Tailwind CSS universal selector", () => { - const sample = ".\\*\\:class1 .class2\\*\\:class3 .class4\\*:.class5"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["\\*\\:class1", "class2\\*\\:class3", "class4\\*", "class5"] - }) - }); - - test("should handle Tailwind CSS [custom parameter] selector", () => { - const sample = ".class1\\[100\\] .class2-\\[200\\]"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1\\[100\\]", "class2-\\[200\\]"] - }) - }); - - test("should handle Tailwind CSS [custom parameter] selector with escaped characters", () => { - const sample = ".class1\\[1em\\] .class2-\\[2em\\] .class3\\[3\\%\\] .class4-\\[4\\%\\]"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1\\[1em\\]", "class2-\\[2em\\]", "class3\\[3\\%\\]", "class4-\\[4\\%\\]"] - }) - }); - - test("should handle complex Tailwind CSS [custom parameter] selector", () => { - const sample = ".w-\\[calc\\(10\\%\\+5px\\)\\]"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["w-\\[calc\\(10\\%\\+5px\\)\\]"] - }) - }); - - test("should ignore Tailwind CSS [custom parameter] selector that not in the same scope as class", () => { - const sample = ":is(.class1)[100]"; - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: ["class1"] - }) - }); - - test("should handle Tailwind CSS [custom selector] child elements selector", () => { - const sample = ` - .\\[\\&\\>\\class1\\]:after - .\\[\\&_class2\\]:hover - .\\[\\&_\\.class3\\]\\:class4 - .\\[\\&_\\#id1\\]::moz-placeholder - .\\[\\&_\\#id2\\]\\:class5.\\[\\&_\\#id\\]\\:class6 - `; - - // .\[\&_a\[class\]\]:hover <= will not work, (?:\\\[(?:[^\[\]\s]*|(?R))*\\\]))+) , javascript regex does not support recursive regex - - // Act - const result = extractClassFromSelector(sample); - - // Assert - expect(result).toEqual({ - selector: sample, - extractedClasses: [ - "\\[\\&\\>\\class1\\]", "\\[\\&_class2\\]", - "\\[\\&_\\.class3\\]\\:class4", "\\[\\&_\\#id1\\]", - "\\[\\&_\\#id2\\]\\:class5", "\\[\\&_\\#id\\]\\:class6" - ] - }) - }); -}); diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 138270c..0cef632 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -1,217 +1,20 @@ -import type { obfuscateMode, SelectorConversion } from "../types"; +import type { obfuscateMode } from "../types"; import path from "node:path"; import fs from "node:fs"; -// @ts-ignore -import css from "css"; -import NumberGenerator from "recoverable-random"; -import { initTransform, transform, ConversionTable, cssEscape, type ConversionTables, type TransformProps } from "css-seasoning"; +import { initTransform, transform, type ConversionTables, type TransformProps } from "css-seasoning"; import lightningcssInit, { transform as lightningcssTransform } from "lightningcss-wasm"; +// TODO: html failed with . + import { log, - getRandomString, - seedableSimplifyString, - simplifyString, - loadAndMergeJsonFiles, findAllFilesWithExt, - usedKeyRegistery, getFilenameFromPath, - duplicationCheck, - createKey, - decodeKey, stringToNumber, loadConversionTables, } from "../utils"; -let randomStringGeneraterStateCode: string | undefined = undefined; -let currentAlphabetPoistion = 1; -function createNewClassName( - mode: obfuscateMode, - className: string, - classPrefix: string = "", - classSuffix: string = "", - classNameLength: number = 5, - seed: string = Math.random().toString() -) { - let newClassName = className; - - let { rngStateCode, randomString }: { rngStateCode: string, randomString: string } = { rngStateCode: "", randomString: "" }; - - //? Based on the mechanism behind `recoverable-random` library - //? `stateCode` is directly equivalent to the `seed` - //? so recover the stateCode is the same as setting the seed - //? so the seed input `seedableSimplifyString` - //? in the following usage is meaningless - //? :) - - switch (mode) { - case "random": - ({ rngStateCode, randomString } = getRandomString(classNameLength, seed, undefined, className)); - break; - // case "simplify-seedable": - // ({ rngStateCode, randomString } = seedableSimplifyString(className, seed, seed + NumberGenerator.stringToSeed(className).toString())); - // break; - case "simplify": - randomString = simplifyString(currentAlphabetPoistion); - currentAlphabetPoistion++; - break; - default: - break; - } - - newClassName = randomString; - randomStringGeneraterStateCode = rngStateCode; - - if (classPrefix) { - newClassName = `${classPrefix}${newClassName}`; - } - if (classSuffix) { - newClassName = `${newClassName}${classSuffix}`; - } - - return newClassName; -} - -//? CSS action selectors always at the end of the selector -//? and they can be stacked, eg. "class:hover:active" -//? action selectors can start with ":" or "::" -const findActionSelectorsRegex = /(?)/g; - -/** - * Extracts classes from a CSS selector. - * - * @param selector - The CSS selector to extract classes from. - * @param replacementClassNames - The replacement class names. - * The position of the class name in the array should match the - * position of the class in the selector that you want to replece. - * @returns An array of extracted classes. - * - * @example - * // Returns: ["some-class", "some-class", "bg-white", "some-class", "bg-dark"] - * extractClassFromSelector(":is(.some-class .some-class\\:!bg-white .some-class\\:bg-dark::-moz-placeholder)[data-active=\'true\']"); - * - * @example - * // Returns: [] - * extractClassFromSelector("div"); - */ -export function extractClassFromSelector(selector: string, replacementClassNames?: (string | undefined)[]) { - //? "\\[\w\%\:\.\!\*\<\>\/]" handle escaped characters - //? "(?:\\\[(?:[^\[\]\s])*\\\]))+)" handle [attribute / Tailwind CSS custom parameter] selector - const extractClassRegex = /(?<=[.:!]|(?\/]|(?:\\\[(?:[^\[\]\s])*\\\]))+)(?![\w\-]*\()/g; - - const vendorPseudoClassRegexes = [ - /::?-moz-[\w-]+/g, // Firefox - /::?-ms-[\w-]+/g, // Internet Explorer, Edge - /::?-webkit-[\w-]+/g, // Safari, Chrome, and Opera - /::?-o-[\w-]+/g, // Opera (old ver) - ] - - // temporary remove action selectors - selector = selector.replace(findActionSelectorsRegex, (match) => { - return createKey(match); - }); - - // temporary remove vendor pseudo classes - vendorPseudoClassRegexes.forEach((regex, i) => { - selector = selector.replace(regex, (match) => { - return createKey(match); - }); - }); - - // extract classes - let classes = selector.match(extractClassRegex) as string[] | undefined; - - // replace classes with replacementClassNames - if (replacementClassNames !== undefined) { - selector = selector.replace(extractClassRegex, (originalClassName) => { - return replacementClassNames.shift() || originalClassName; - }); - } - - // place back the pseudo classes - selector = decodeKey(selector); - - return { - selector: selector, - extractedClasses: classes || [] - }; -} - -function getAllSelector(cssObj: any): any[] { - const selectors: string[] = []; - function recursive(rules: any[]) { - for (const item of rules) { - if (item.rules) { - recursive(item.rules); - } else if (item.selectors) { - // remove empty selectors - item.selectors = item.selectors.filter((selector: any) => selector !== ""); - - selectors.push(...item.selectors); - } - } - return null; - } - recursive(cssObj.stylesheet.rules); - return selectors; -} - -export function copyCssData(targetSelector: string, newSelectorName: string, cssObj: any) { - function recursive(rules: any[]): any[] { - return rules.map((item: any) => { - if (item.rules) { - let newRules = recursive(item.rules); - if (Array.isArray(newRules)) { - newRules = newRules.flat(); - } - return { ...item, rules: newRules }; - } else if (item.selectors) { - // remove empty selectors - item.selectors = item.selectors.filter((selector: any) => selector !== ""); - - // check if the selector is the target selector - if (item.selectors.includes(targetSelector)) { - const newRule = JSON.parse(JSON.stringify(item)); - newRule.selectors = [newSelectorName]; - - return [item, newRule]; - } else { - return item; - } - } else { - return item; - } - }); - } - cssObj.stylesheet.rules = recursive(cssObj.stylesheet.rules).flat(); - return cssObj; -} - -export function renameCssSelector(oldSelector: string, newSelector: string, cssObj: any) { - function recursive(rules: any[]): any[] { - return rules.map((item: any) => { - if (item.rules) { - return { ...item, rules: recursive(item.rules) }; - } else if (item.selectors) { - // remove empty selectors - item.selectors = item.selectors.filter((selector: any) => selector !== ""); - - let updatedSelectors = item.selectors.map((selector: any) => - selector === oldSelector ? newSelector : selector - ); - - return { ...item, selectors: updatedSelectors }; - } else { - return item; - } - }); - } - - cssObj.stylesheet.rules = recursive(cssObj.stylesheet.rules); - return cssObj; -} - const obfuscateCss = async ({ cssPath, diff --git a/src/handlers/html.ts b/src/handlers/html.ts index 3b32b82..4463138 100644 --- a/src/handlers/html.ts +++ b/src/handlers/html.ts @@ -4,6 +4,7 @@ import * as htmlparser2 from "htmlparser2"; import { escape as htmlEscape } from "html-escaper"; import { log, obfuscateKeys } from "../utils"; import { obfuscateJs } from "./js"; +import { cssUnescape } from "css-seasoning"; /** * @deprecated @@ -257,7 +258,7 @@ function obfuscateHtmlClassNames({ isScriptTag = false; let obfuscatedScriptContent = scriptContent; Object.keys(selectorConversion).forEach((key) => { - const className = key.slice(1); + const className = cssUnescape(key).slice(1); const obfuscatedJs = obfuscateJs( obfuscatedScriptContent, className, diff --git a/src/utils.ts b/src/utils.ts index 77652fd..5564549 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ import type { LogLevel, SelectorConversion, } from "./types"; -import { cssEscape, type ConversionTables } from "css-seasoning"; +import { cssEscape, cssUnescape, type ConversionTables } from "css-seasoning"; import { obfuscateHtmlClassNames } from "./handlers/html"; import { obfuscateJs } from "./handlers/js"; @@ -279,7 +279,7 @@ function obfuscateKeys( Object.keys(selectorConversion).forEach((key) => { const fileContentOriginal = fileContent; // let keyUse = escapeRegExp(key.slice(1).replace(/\\/g, "")); - let keyUse = key.slice(1); + let keyUse = cssUnescape(key).slice(1); //! deprecated // if (useHtmlEntity) { From 7cb985d4c424a4458e2a72db9e76da899c44da63 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 20:56:58 +0100 Subject: [PATCH 07/28] fix(html): fix incorrect html class name truncation --- src/__tests__/html.test.ts | 31 -------- src/handlers/html.ts | 154 +------------------------------------ src/utils.ts | 15 +--- 3 files changed, 7 insertions(+), 193 deletions(-) diff --git a/src/__tests__/html.test.ts b/src/__tests__/html.test.ts index 5319c8e..44693e7 100644 --- a/src/__tests__/html.test.ts +++ b/src/__tests__/html.test.ts @@ -3,40 +3,9 @@ import type { SelectorConversion } from '../types'; import { describe, it, expect } from "vitest"; import { - findHtmlTagContentsByClass, obfuscateHtmlClassNames, } from "../handlers/html"; - -//! ================================ -//! findHtmlTagContentsByClass -//! ================================ - -/** - * @deprecated - */ -describe("findHtmlTagContentsByClass", () => { - const content = `
12345678
901234
56789
0123456
`; - - it("should return the correct content within the tag that with a given class", () => { - const targetClass = "test1"; - - const expectedOutput = ['
12345678
901234
56789
']; - - const result = findHtmlTagContentsByClass(content, targetClass); - expect(result).toEqual(expectedOutput); - }); - - it("should return empty array if no content found", () => { - const targetClass = "test5"; - - const expectedOutput: unknown[] = []; - - const result = findHtmlTagContentsByClass(content, targetClass); - expect(result).toEqual(expectedOutput); - }); -}); - //! ================================ //! obfuscateHtmlClassNames //! ================================ diff --git a/src/handlers/html.ts b/src/handlers/html.ts index 4463138..2ba059d 100644 --- a/src/handlers/html.ts +++ b/src/handlers/html.ts @@ -2,153 +2,11 @@ import type { SelectorConversion } from "../types"; import * as htmlparser2 from "htmlparser2"; import { escape as htmlEscape } from "html-escaper"; -import { log, obfuscateKeys } from "../utils"; +import { obfuscateKeys } from "../utils"; import { obfuscateJs } from "./js"; import { cssUnescape } from "css-seasoning"; -/** - * @deprecated - */ -function findHtmlTagContentsRecursive( - content: string, - targetTag: string, - targetClass: string | null = null, - foundTagContents: string[] = [], - deep = 0, - maxDeep = -1, -) { - let contentAfterTag = content; - const startTagWithClassRegexStr = targetClass - ? // ref: https://stackoverflow.com/a/16559544 - `(<\\w+?\\s+?class\\s*=\\s*['\"][^'\"]*?\\b${targetClass}\\b)` - : ""; - const startTagRegexStr = `(<${targetTag}[\\s|>])`; - const endTagRegexStr = `(<\/${targetTag}>)`; - - // clear content before the start tag - const clearContentBeforeStartTagRegex = new RegExp( - `${startTagWithClassRegexStr ? startTagWithClassRegexStr + ".*|" + startTagRegexStr : startTagRegexStr + ".*"}`, - "i", - ); - const contentAfterStartTagMatch = contentAfterTag.match( - clearContentBeforeStartTagRegex, - ); - if (contentAfterStartTagMatch) { - contentAfterTag = contentAfterStartTagMatch[0]; - } - - let endTagCont = 0; - - const endTagContRegex = new RegExp(endTagRegexStr, "gi"); - const endTagContMatch = contentAfterTag.match(endTagContRegex); - if (endTagContMatch) { - endTagCont = endTagContMatch.length; - } - - let closeTagPoition = 0; - - const tagPatternRegex = new RegExp( - `${startTagWithClassRegexStr ? startTagWithClassRegexStr + "|" + startTagRegexStr : startTagRegexStr}|${endTagRegexStr}`, - "gi", - ); - const tagPatternMatch = contentAfterTag.match(tagPatternRegex); - if (tagPatternMatch) { - let tagCount = 0; - let markedPosition = false; - for (let i = 0; i < tagPatternMatch.length; i++) { - if (tagPatternMatch[i].startsWith(")`, "i"); - const remainingHtmlTagMatch = remainingHtml.match(remainingHtmlTagRegex); - if (remainingHtmlTagMatch) { - if (maxDeep === -1 || deep < maxDeep) { - return findHtmlTagContentsRecursive( - remainingHtml, - targetTag, - targetClass, - foundTagContents, - deep + 1, - maxDeep, - ); - } - log("warn", "HTML search:", "Max deep reached, recursive break"); - return foundTagContents; - } - } - - return foundTagContents; -} - -/** - * @deprecated - */ -function findHtmlTagContents( - content: string, - targetTag: string, - targetClass: string | null = null, -) { - return findHtmlTagContentsRecursive(content, targetTag, targetClass); -} - -/** - * @deprecated - */ -function findHtmlTagContentsByClass(content: string, targetClass: string) { - const regex = new RegExp( - `(<(\\w+)\\s+class\\s*=\\s*['\"][^'\"]*?\\b${targetClass}\\b)`, - "i", - ); - const match = content.match(regex); - if (match) { - const tag = match[2]; - return findHtmlTagContents(content, tag, targetClass); - } - return []; -} - -function obfuscateHtmlClassNames({ +export const obfuscateHtmlClassNames = ({ html, selectorConversion, obfuscateMarkerClass = "", @@ -158,7 +16,7 @@ function obfuscateHtmlClassNames({ selectorConversion: SelectorConversion; obfuscateMarkerClass?: string; contentIgnoreRegexes?: RegExp[]; -}) { +}) => { const voidTags = [ "area", "base", @@ -295,9 +153,3 @@ function obfuscateHtmlClassNames({ usedKeys: Array.from(new Set(usedKeys)), }; } - -export { - findHtmlTagContents, - findHtmlTagContentsByClass, - obfuscateHtmlClassNames, -}; diff --git a/src/utils.ts b/src/utils.ts index 5564549..17e9935 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -267,12 +267,12 @@ const replaceJsonKeysInFiles = ( // }); } -function obfuscateKeys( +const obfuscateKeys = ( selectorConversion: SelectorConversion, fileContent: string, contentIgnoreRegexes: RegExp[] = [], useHtmlEntity: boolean = false -) { +) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js const usedKeys = new Set(); @@ -281,20 +281,13 @@ function obfuscateKeys( // let keyUse = escapeRegExp(key.slice(1).replace(/\\/g, "")); let keyUse = cssUnescape(key).slice(1); - //! deprecated - // if (useHtmlEntity) { - // const regex = new RegExp(`(${Object.keys(HTML_CHARACTER_ENTITY_CONVERSION).join("|")})`, "g"); - // keyUse = keyUse.replace(regex, (m: string) => { - // return HTML_CHARACTER_ENTITY_CONVERSION[m] - // }); - // } - keyUse = escapeRegExp(keyUse.replace(/\\/g, "")); + keyUse = escapeRegExp(keyUse.replace(/\\/g, "")); // escape the key //? sample: "text-sm w-full\n text-right\n p-2 flex gap-2 hover:bg-gray-100 dark:hover:bg-red-700 text-right" let exactMatchRegex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`]|\\\\n|\\\\",|\\\\"})`, 'g'); // match exact wording & avoid ` ' "" // exactMatchRegex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`])`, 'g'); // match exact wording & avoid ` ' "" - const replacement = `$1` + selectorConversion[key].slice(1).replace(/\\/g, ""); + const replacement = `$1` + selectorConversion[key].slice(1).replace(/\\/g, "").slice(1); const matches = fileContent.match(exactMatchRegex); const originalObscuredContentPairs = matches?.map((match) => { From a290b14b5e42afedb666d2111e1779464ccd1cb0 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 21:41:48 +0100 Subject: [PATCH 08/28] refactor: Simplify and export utility functions Refactors utility functions for better organization and reusability. - Removes unused random string generation and string simplification functions. - Exports previously internal functions to enhance module accessibility and facilitate testing. - Streamlines the codebase by removing dead code and improving overall structure. --- src/__tests__/utils.test.ts | 186 ------------------------------------ src/config.ts | 6 +- src/handlers/js-ast.ts | 18 ++-- src/handlers/js.ts | 25 ++--- src/utils.ts | 180 +++++----------------------------- 5 files changed, 44 insertions(+), 371 deletions(-) diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index f921647..48c34e6 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -2,10 +2,7 @@ import { describe, it, expect, test, beforeEach } from "vitest"; import { findContentBetweenMarker, getFilenameFromPath, - getRandomString, - seedableSimplifyString, duplicationCheck, - simplifyString, } from "../utils"; import NumberGenerator from "recoverable-random"; @@ -139,149 +136,6 @@ describe("getFilenameFromPath", () => { }); -//! ================================ -//! getRandomString -//! ================================ - -describe("getRandomString", () => { - let rng: NumberGenerator; - - beforeEach(() => { - rng = new NumberGenerator(); - }); - - test("should generate a random string of a given length", () => { - // Arrange - const length = 10; - const seed = "testSeed"; - rng = new NumberGenerator(seed); // Mocked RNG for consistent results - - // Act - const result = getRandomString(length, seed); - - // Assert - expect(result.randomString).toHaveLength(length); - expect(result.randomString).toMatch(/^[a-z][a-z0-9-_]+$/); - }); - - test("should recover RNG state if state code is provided", () => { - // Arrange - const length = 10; - const seed = "testSeed"; - const stateCode = "someStateCode"; - rng = new NumberGenerator(seed); // Mocked RNG for consistent results - const initialStateCode = rng.getStateCode(); - - // Act - const result = getRandomString(length, seed, stateCode); - - // Assert - expect(result.rngStateCode).not.toBe(initialStateCode); - }); - - test("should throw an error if length is not a positive integer", () => { - // Arrange - const invalidLengths = [0, -1, 1.5, NaN, Infinity]; - - // Act & Assert - invalidLengths.forEach(length => { - expect(() => getRandomString(length as any)).toThrow(); - }); - }); - - test("should handle edge case where length is 1", () => { - // Arrange - const length = 1; - - // Act - const result = getRandomString(length); - - // Assert - expect(result.randomString).toHaveLength(length); - expect(result.randomString).toMatch(/^[a-z]$/); - }); - - test("should return a valid rngStateCode", () => { - // Arrange - const length = 10; - - // Act - const result = getRandomString(length); - - // Assert - expect(result.rngStateCode).toBeDefined(); - expect(typeof parseInt(result.rngStateCode)).toBe("number"); - }); -}); - -//! ================================ -//! seedableSimplifyString -//! ================================ - -describe("seedableSimplifyString", () => { - let rng: NumberGenerator; - - beforeEach(() => { - rng = new NumberGenerator("default-seed"); - }); - - test("should throw an error for empty string", () => { - // Act & Assert - expect(() => seedableSimplifyString("")).toThrow("String can not be empty"); - }); - - test("should return a simplified string and rng state code", () => { - // Arrange - const input = "a1e2i3o4u5w6_-"; - - // Act - const result = seedableSimplifyString(input, "seed"); - - // Assert - expect(result.randomString.length).toBeLessThan(input.length); - expect(typeof parseInt(result.rngStateCode)).toBe("number"); - }); - - test("should recover RNG state from state code", () => { - // Arrange - const stateCode = "some-state-code"; - const input = "test"; - rng.recoverState(stateCode); - const expectedStateCode = rng.getStateCode(); - - // Act - const result = seedableSimplifyString(input, undefined, stateCode); - - // Assert - expect(result.rngStateCode).toBe(expectedStateCode); - }); - - test("should handle strings without vowels or numbers", () => { - // Arrange - const input = "bcdfghjklmnpqrstvxyz"; - const expectedOutput = input; // No vowels or numbers to remove - - // Act - const result = seedableSimplifyString(input, "seed"); - - // Assert - expect(result.randomString).toBe(expectedOutput); - }); - - test("should handle strings with only vowels and numbers", () => { - // Arrange - const input = "aeiou12345"; - const expectedOutput = ""; // All characters should be removed - - // Act - const result = seedableSimplifyString(input, "seed"); - - // Assert - expect(result.randomString).toHaveLength(1); // Should contain one random character - }); -}); - - //! ================================ //! duplicationCheck //! ================================ @@ -376,43 +230,3 @@ describe("duplicationCheck", () => { expect(result).toBe(false); }); }); - - -//! ================================ -//! simplifyString -//! ================================ - -describe("simplifyString", () => { - - test.each([ - { position: 1, expected: "a" }, - { position: 26, expected: "z" }, - { position: 27, expected: "aa" }, - { position: 52, expected: "az" }, - { position: 53, expected: "ba" }, - { position: 702, expected: "zz" }, - { position: 703, expected: "aaa" }, - ])("returns correct string for position $position", ({ position, expected }) => { - // Act - const result = simplifyString(position); - - // Assert - expect(result).toBe(expected); - }); - - test("throws error for negative position", () => { - // Arrange - const input = -1; - - // Act & Assert - expect(() => simplifyString(input)).toThrow("Position must be a positive integer"); - }); - - test("throws error for non-integer position", () => { - // Arrange - const input = 27.5; - - // Act & Assert - expect(() => simplifyString(input)).toThrow("Position must be a positive integer"); - }); -}); \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 15409dd..2e48a34 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,6 +1,6 @@ import type { Options, OptionalOptions } from "./types"; -const defaultOptions: Options = { +export const defaultOptions: Options = { enable: true, // Enable or disable the plugin. mode: "random", // Obfuscate mode, "random", "simplify" or "simplify-seedable". buildFolderPath: ".next", // Build folder of your project. @@ -36,7 +36,7 @@ const defaultOptions: Options = { logLevel: "info", // Log level }; -class Config { +export class Config { private options: Options; constructor(options?: OptionalOptions) { @@ -55,4 +55,4 @@ class Config { } } -export default Config; \ No newline at end of file +export default Config; diff --git a/src/handlers/js-ast.ts b/src/handlers/js-ast.ts index 44907e8..8b368e3 100644 --- a/src/handlers/js-ast.ts +++ b/src/handlers/js-ast.ts @@ -14,12 +14,12 @@ import { type SelectorConversion } from "../types"; * @param stripUnnecessarySpace - whether to strip unnecessary space in the className, e.g. " a b c " => "a b c" * @returns - the obfuscated code and the used keys */ -function obfuscateJsWithAst( +export const obfuscateJsWithAst = ( code: string, selectorConversion: SelectorConversion | undefined, startingKeys: string[] = [], stripUnnecessarySpace: boolean = true -) { +) => { const ast = parser.parse(code, { sourceType: "module", plugins: ["jsx"] }); const usedKeys: Set = new Set(); @@ -42,6 +42,7 @@ function obfuscateJsWithAst( : str; const { obfuscatedContent, usedKeys: obfuscateUsedKeys } = obfuscateKeys(selectorConversion, str); + if (obfuscatedContent !== str) { obfuscateUsedKeys.forEach(key => usedKeys.add(key)); return obfuscatedContent; @@ -63,7 +64,7 @@ function obfuscateJsWithAst( obfuscatedCode: obfuscatedCode.code, usedKeys: usedKeys }; -} +}; /** @@ -73,12 +74,12 @@ function obfuscateJsWithAst( * @param scannedNodes - (for recursion) keep track of scanned nodes to avoid infinite loop * @returns - the modified AST node */ -function searchStringLiterals(path: NodePath, +export const searchStringLiterals = (path: NodePath, callback: (str: string) => void | string, //? keep track of scanned nodes to avoid infinite loop scannedNodes: Set = new Set() -) { +) => { /* Skip this node if it has already been scanned */ if (path.node && scannedNodes.has(path.node)) { return; @@ -365,9 +366,4 @@ function searchStringLiterals(path: NodePath, }); } return path; -} - -export { - searchStringLiterals, - obfuscateJsWithAst, -} +}; diff --git a/src/handlers/js.ts b/src/handlers/js.ts index 343c98e..292f415 100644 --- a/src/handlers/js.ts +++ b/src/handlers/js.ts @@ -11,8 +11,7 @@ import { import { SelectorConversion } from "../types"; import { obfuscateJsWithAst } from "./js-ast"; - -function searchForwardComponent(content: string) { +export const searchForwardComponent = (content: string) => { const componentSearchRegex = /(?<=\.jsx\()[^,|"|']+/g; //eg. o.jsx(yt,{data:yc,index:"date // then return yt @@ -24,9 +23,9 @@ function searchForwardComponent(content: string) { return match; } return []; -} +}; -function searchComponent(content: string, componentName: string) { +const searchComponent = (content: string, componentName: string) => { const componentSearchRegex = new RegExp(`\\b(?:const|let|var)\\s+(${componentName})\\s*=\\s*.*?(\\{)`, "g"); // eg, let yt=l().forwardRef((e,t)=>{let const match = content.match(componentSearchRegex); @@ -39,9 +38,9 @@ function searchComponent(content: string, componentName: string) { const componentContent = content.slice(openSymbolPos, closeMarkerPos); return componentContent; -} +}; -function obfuscateForwardComponentJs(searchContent: string, wholeContent: string, selectorConversion: SelectorConversion) { +export const obfuscateForwardComponentJs = (searchContent: string, wholeContent: string, selectorConversion: SelectorConversion) => { const componentNames = searchForwardComponent(searchContent).filter((componentName) => { return !componentName.includes("."); }); @@ -93,10 +92,10 @@ function obfuscateForwardComponentJs(searchContent: string, wholeContent: string } return componentObfuscatedcomponentCodePairs; -} +}; -function obfuscateJs(content: string, key: string, selectorCoversion: SelectorConversion - , filePath: string, contentIgnoreRegexes: RegExp[] = [], useAst: boolean = false) { +export const obfuscateJs = (content: string, key: string, selectorCoversion: SelectorConversion + , filePath: string, contentIgnoreRegexes: RegExp[] = [], useAst: boolean = false) => { if (useAst) { try { @@ -126,10 +125,4 @@ function obfuscateJs(content: string, key: string, selectorCoversion: SelectorCo } }); return content; -} - -export { - obfuscateForwardComponentJs, - obfuscateJs, - searchForwardComponent, -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 17e9935..7b1ab91 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -19,11 +19,11 @@ import { obfuscateJs } from "./handlers/js"; * @param blackListedFolderPaths - Paths to exclude (higher priority than whitelist) * @returns - True if the path should be included, false otherwise */ -function shouldIncludePath( +const shouldIncludePath = ( filePath: string, whiteListedFolderPaths: (string | RegExp)[] = [], blackListedFolderPaths: (string | RegExp)[] = [] -): boolean { +): boolean => { const normalizedPath = normalizePath(filePath); // Check if the path is blacklisted (higher priority) @@ -57,7 +57,7 @@ const issuer = "[next-css-obfuscator]"; let logLevel: LogLevel = "info"; const levels: LogLevel[] = ["debug", "info", "warn", "error", "success"]; -function log(type: LogLevel, task: string, data: any) { +export const log = (type: LogLevel, task: string, data: any) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js if (levels.indexOf(type) < levels.indexOf(logLevel)) { return; @@ -85,9 +85,9 @@ function log(type: LogLevel, task: string, data: any) { console.log("'\x1b[0m'", issuer, task, data, "\x1b[0m"); break; } -} +}; -function setLogLevel(level: LogLevel) { +export const setLogLevel = (level: LogLevel) => { logLevel = level; } @@ -110,10 +110,10 @@ function setLogLevel(level: LogLevel) { //! //! ==================== -const usedKeyRegistery = new Set(); +export const usedKeyRegistery = new Set(); -const replaceJsonKeysInFiles = ( +export const replaceJsonKeysInFiles = ( { conversionTables, targetFolder, @@ -267,7 +267,7 @@ const replaceJsonKeysInFiles = ( // }); } -const obfuscateKeys = ( +export const obfuscateKeys = ( selectorConversion: SelectorConversion, fileContent: string, contentIgnoreRegexes: RegExp[] = [], @@ -318,20 +318,20 @@ const obfuscateKeys = ( return { obfuscatedContent: fileContent, usedKeys: usedKeys }; } -function escapeRegExp(str: string) { +const escapeRegExp = (str: string) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -} +}; /** * Get the filename from a file path * @param filePath - The path to the file * @returns The filename of the file */ -function getFilenameFromPath(filePath: string) { +export const getFilenameFromPath = (filePath: string) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js return filePath.replace(/^.*[\\/]/, ''); -} +}; /** * Normalizes a file path by replacing backslashes with forward slashes. @@ -347,22 +347,9 @@ function getFilenameFromPath(filePath: string) { * // Returns: 'path/to/file' * normalizePath('path\\to\\file'); */ -function normalizePath(filePath: string) { +export const normalizePath = (filePath: string) => { return filePath.replace(/\\/g, "/"); -} - -function loadAndMergeJsonFiles(jsonFolderPath: string) { - //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js - const jsonFiles: { [key: string]: any } = {}; - - fs.readdirSync(jsonFolderPath).forEach((file: string) => { - const filePath = path.join(jsonFolderPath, file); - const fileData = JSON.parse(fs.readFileSync(filePath, "utf-8")); - Object.assign(jsonFiles, fileData); - }); - - return jsonFiles; -} +}; /** * @@ -373,7 +360,7 @@ function loadAndMergeJsonFiles(jsonFolderPath: string) { * @param direction - if "forward", the function will search the closest closeMarker after the startPosition, if "backward", the function will search the closest openMarker before the startPosition * @returns */ -function findClosestSymbolPosition(content: string, openMarker: string, closeMarker: string, startPosition: number = 0, direction: "forward" | "backward" = "backward") { +export const findClosestSymbolPosition = (content: string, openMarker: string, closeMarker: string, startPosition: number = 0, direction: "forward" | "backward" = "backward") => { let level = 0; let currentPos = startPosition; @@ -406,9 +393,9 @@ function findClosestSymbolPosition(content: string, openMarker: string, closeMar } return currentPos; -} +}; -function findContentBetweenMarker(content: string, targetStr: string, openMarker: string, closeMarker: string) { +export const findContentBetweenMarker = (content: string, targetStr: string, openMarker: string, closeMarker: string) => { if (openMarker === closeMarker) { throw new Error("openMarker and closeMarker can not be the same"); } @@ -433,13 +420,13 @@ function findContentBetweenMarker(content: string, targetStr: string, openMarker } return truncatedContents; -} +}; -export function addKeysToRegistery(usedKeys: Set | string[]) { +export const addKeysToRegistery = (usedKeys: Set | string[]) => { usedKeys.forEach((key) => { usedKeyRegistery.add(key); }); -} +}; /** * Find all files with the specified extension in the build folder. @@ -451,7 +438,7 @@ export function addKeysToRegistery(usedKeys: Set | string[]) { * @param options.blackListedFolderPaths - an array of folder paths to exclude from the search. Higher priority than whiteListedFolderPaths. * @returns - an array of file relative paths. */ -const findAllFilesWithExt = ( +export const findAllFilesWithExt = ( ext: string, targetFolderPath: string, options?: { whiteListedFolderPaths?: (string | RegExp)[], @@ -494,131 +481,23 @@ const findAllFilesWithExt = ( return targetExtFiles; } -let rng: NumberGenerator | undefined = undefined; - -function getRandomString(length: number, seed?: string, rngStateCode?: string, str?: string) { - if (length <= 0 || !Number.isInteger(length)) { - throw new Error("Length must be a positive integer"); - } - - if (!rng) { - rng = new NumberGenerator(seed); - } - if (rngStateCode) { - rng.recoverState(rngStateCode); - } - - let rn = rng.random(0, 1, true); - if (str && seed) { - // can create a more collision resistant "random number" but in fact it's not random number - rn = Number.parseFloat(`0.${NumberGenerator.stringToSeed(str) + NumberGenerator.stringToSeed(seed)}`); - } - - //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js - // Generate a random string of characters with the specified length - const randomString = rn.toString(36).substring(2, length - 1 + 2); - // Combine the random string with a prefix to make it a valid class name (starts with a letter, contains only letters, digits, hyphens, and underscores) - const randomLetter = String.fromCharCode(Math.floor(rng.random(0, 1, true) * 26) + 97); // 97 is the ASCII code for lowercase 'a' - return { - rngStateCode: rng.getStateCode(), - randomString: `${randomLetter}${randomString}`, - }; -} - -/** - * - * @param str - * @param seed - * @param rngStateCode - * @returns - */ -function seedableSimplifyString(str: string, seed?: string, rngStateCode?: string) { - if (!str) { - throw new Error("String can not be empty"); - } - if (!rng) { - rng = new NumberGenerator(seed); - } - if (rngStateCode) { - rng.recoverState(rngStateCode); - } - - //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js - const tempStr = str.replace(/[aeiouw\d_-]/gi, ""); - - return { - rngStateCode: rng.getStateCode(), - randomString: tempStr.length < 1 - ? String.fromCharCode(Math.floor(rng.random(0, 1, true) * 26) + 97) + tempStr - : tempStr, - }; -} - -/** - * Get a simplified string from a number - * @param alphabetPoistion (starting from 1) - * @returns alphabet string - * - * @example - * simplifyString(1) // returns "a" - * simplifyString(26) // returns "z" - * simplifyString(27) // returns "aa" - * simplifyString(52) // returns "az" - * simplifyString(53) // returns "ba" - */ -function simplifyString(alphabetPoistion: number) { - if (alphabetPoistion <= 0 || !Number.isInteger(alphabetPoistion)) { - throw new Error("Position must be a positive integer"); - } - - let dividend = alphabetPoistion; - let columnName = ""; - let modulo = 0; - - while (dividend > 0) { - modulo = (dividend - 1) % 26; - columnName = String.fromCharCode(97 + modulo) + columnName; - dividend = Math.floor((dividend - modulo) / 26); - } - - return columnName; -} - -function replaceFirstMatch(source: string, find: string, replace: string): string { +export const replaceFirstMatch = (source: string, find: string, replace: string): string => { const index = source.indexOf(find); if (index !== -1) { return source.slice(0, index) + replace + source.slice(index + find.length); } return source; -} +}; /** * Check if there are any duplicates in an array of strings * @param arr - an array of strings * @returns - true if there are any duplicates, false otherwise */ -function duplicationCheck(arr: string[]) { +export const duplicationCheck = (arr: string[]) => { const set = new Set(arr); return arr.length !== set.size; -} - - -function createKey(str: string) { - const b64 = Buffer.from(str).toString("base64").replace(/=/g, ""); - return `{{{{{{${b64}}}}}}}`; -} - -function decodeKey(str: string) { - const regex = /{{{{{{([\w\+\/]+)}}}}}}/g; - str = str.replace(regex, (match, p1) => { - // Calculate the number of '=' needed - const padding = p1.length % 4 === 0 ? 0 : 4 - (p1.length % 4); - // Add back the '=' - const b64 = p1 + "=".repeat(padding); - return Buffer.from(b64, "base64").toString("ascii"); - }); - return str; -} +}; /** * Convert a string to a number by summing the char codes of each character @@ -666,12 +545,3 @@ export const loadConversionTables = (folderPath: string): ConversionTables => { return tables; } - -export { - getFilenameFromPath, log, normalizePath, loadAndMergeJsonFiles - , replaceJsonKeysInFiles, setLogLevel, findContentBetweenMarker, replaceFirstMatch - , findAllFilesWithExt, getRandomString, seedableSimplifyString, usedKeyRegistery - , obfuscateKeys, findClosestSymbolPosition, duplicationCheck - , createKey, decodeKey, simplifyString -}; - From 668a5f66abdd174bf8ecbd18e9872a9719c73508 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:39:15 +0100 Subject: [PATCH 09/28] feat: v3 migration with TailwindCSS 4 support Introduces breaking changes to support TailwindCSS 4, nested CSS, and CSS ident obfuscation. - Updates configuration options, including renaming, merging, and removing deprecated options. - Migrates to css-seasoning v1.4.1. - Enables JS AST parsing by default. - Updates documentation with v3 migration guide. --- README.md | 112 +++++++++++++++++++++++++++++------------- docs/upgrade-to-v3.md | 20 ++++++++ package-lock.json | 8 +-- package.json | 2 +- src/config.ts | 31 +++++++++--- src/handlers/css.ts | 39 ++++++--------- src/index.ts | 12 +++-- src/types.ts | 24 +++++++-- src/utils.ts | 22 ++++----- 9 files changed, 184 insertions(+), 86 deletions(-) create mode 100644 docs/upgrade-to-v3.md diff --git a/README.md b/README.md index 3e6ede2..4729f1d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ - - - # NEXT-CSS-OBFUSCATOR Project starts on 30-10-2023 @@ -21,20 +18,31 @@ Visit the [GitHub Page](https://github.com/soranoo/next-css-obfuscator/) for bet --- -### 🎉 Version 2.1.0 has NOW been released 🎉 - Shout out to [hoangnhan2ka3](https://github.com/hoangnhan2ka3) for providing a 💪wonderful [issue](https://github.com/soranoo/next-css-obfuscator/issues/6) report and a demo site. +### 🎉 Version 3 has NOW been released 🎉 (💥 Breaking Changes) - #### 📌 Changes - - Much Much Much better quality of CSS selector obfuscation - - Delete original CSS automatically after obfuscation (only apply at full obfuscation) - - Support TailwindCSS Universal Selector (eg. `*:pt-4`) - - More tests +>[!IMPORTANT]\ +> This version is a major update and has breaking changes. Please read the [migration guide](docs/upgrade-to-v3.md) carefully before upgrading. + +>[!TIP]\ +> Don't upgrade to this version unless you are using TailwindCSS 4.0.0 or above. "If it works, don't touch it." :) + + #### 📌 Feature Changes + + - Support TailwindCSS 4. + - Support nested CSS. + - Support CSS idents obfuscation. #### 📌 Configuration Changes - - Removed `customTailwindDarkModeSelector` option, the dark mode selector will be automatically obfuscated at full obfuscation. - - Merged `includeAnyMatchRegexes` and `excludeAnyMatchRegexes` options into `whiteListedFolderPaths` and `blackListedFolderPaths` options. (Directly move the regexes to the `whiteListedFolderPaths` and `blackListedFolderPaths` options) - - Added `removeOriginalCss` option, default to `false`. Set to `true` to delete original CSS from CSS files if it has a obfuscated version. - - `classIgnore` option now supports Regex. + + - `enableJsAst` option is now enabled by default. + - Default `generatorSeed` not longer fixed to `-1`, but a random string. + - `simplify-seedable` mode is not longer supported. Use `random` mode instead. + - Removed `includeAnyMatchRegexes` and `excludeAnyMatchRegexes` options, the `whiteListedFolderPaths` and `blackListedFolderPaths` options will be used instead. + - Deprecated `classLength` option, not longer supported. + - Added `ignorePatterns` option to ignore the class names and idents that match the regexes or strings. + - Not longer preserve TailwindCSS dark mode class names (ie `.dark`). Add the dark mode class name to the `ignorePatterns.selectors` option to preserve it. + - Merge `classIgnore` into `ignorePatterns.selectors` option. + - Renamed `classPrefix` and `classSuffix` to `prefix` and `suffix`. ### 💥 Version 2 (Major Update) This version is deeply inspired by [PostCSS-Obfuscator](https://github.com/n4j1Br4ch1D/postcss-obfuscator). Shout out to [n4j1Br4ch1D](https://github.com/n4j1Br4ch1D) for creating such a great package and thank you [tremor](https://github.com/tremorlabs) for sponsoring this project. @@ -50,10 +58,13 @@ Visit the [GitHub Page](https://github.com/soranoo/next-css-obfuscator/) for bet ### 📚 Migration Guides - [Migrate from version 1.x to 2.x](docs/upgrade-to-v2.md) +- [Migrate from version 2.x to 3.x](docs/upgrade-to-v3.md) [version 1.x README](https://github.com/soranoo/next-css-obfuscator/tree/v.1.1.0) +[version 2.x README](https://github.com/soranoo/next-css-obfuscator/tree/v.2.2.19) + Give me a ⭐ if you like it. ## 📖 Table of Contents @@ -159,17 +170,21 @@ Visit the [npm](https://www.npmjs.com/package/next-css-obfuscator) page. ```javascript module.exports = { enable: true, - mode: "random", // random | simplify | simplify-seedable + mode: "random", // random | simplify refreshClassConversionJson: false, // recommended set to true if not in production allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], }; ``` ##### Partially obfuscate + + > [!CAUTION]\ + > Partially obfuscate can be EXTREMELY buggy. Be cautious when using this feature. + ```javascript module.exports = { enable: true, - mode: "random", // random | simplify | simplify-seedable + mode: "random", // random | simplify refreshClassConversionJson: false, // recommended set to true if not in production allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], @@ -184,14 +199,14 @@ Visit the [npm](https://www.npmjs.com/package/next-css-obfuscator) page. module.exports = { // other options ... - } as Options; + } satisfies Options; ``` Feel free to checkout [📖 Config Options Reference](#-config-options-reference) for more options and details. - > [!NOTE]\ + > [!TIP]\ > The obfuscation will never work as expected, tweak the options with your own needs. 2. Add the following code to `package.json`: @@ -263,14 +278,14 @@ See [Next 14 App Router Partially Obfuscated Demo](https://github.com/soranoo/ne ## 🔧 My Setting -If you are interested in my setting (from my production site), here it is +If you are interested in my setting, here it is ```javascript // next-css-obfuscator.config.cjs module.exports = { enable: true, - mode: "random", // random | simplify | simplify-seedable + mode: "random", // random | simplify refreshClassConversionJson: false, // recommended set to true if not in production allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], @@ -283,6 +298,7 @@ module.exports = { ], }; ``` + [*1] See this [comment](https://github.com/soranoo/next-css-obfuscator/issues/6#issuecomment-1919495298) It may not be the best setting but it works for me. :) @@ -292,14 +308,13 @@ It may not be the best setting but it works for me. :) | Option | Type | Default | Description | | ---------------------------- | ----------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | | enable | boolean | true | Enable or disable the obfuscation. | -|mode| "random" \| "simplify" \| "simplify-seedable" | "random" | Obfuscate mode,

**random**: Fixed size random class name

**simplify**: Alphabetic class name, like [medium](https://medium.com/)

**simplify-seedable**: Random dynamic size class name| +| mode | "random" \| "simplify" | "random" | Obfuscate mode,

**random**: Fixed size random class name

**simplify**: Alphabetic class name, like [medium](https://medium.com/)| |buildFolderPath|string|"./.next"|The folder path to store the build files built by Next.js.| |classConversionJsonFolderPath|string|"./css-obfuscator"|The folder path to store the before obfuscate and after obfuscated classes conversion table.| |refreshClassConversionJson|boolean|false|Refresh the class conversion JSON file(s) at every obfuscation. Good for setting tweaking but not recommended for production.| -|classLength|number|5|The length of the obfuscated class name if in random mode.

It is not recommended to set the length to less than 4. -|classPrefix|string|""|The prefix of the obfuscated class name.| -|classSuffix|string|""|The suffix of the obfuscated class name.| -|classIgnore|(string \| Regex)[ ]|[ ]|The class names to be ignored during obfuscation.| +|prefix|string|""|The prefix of the obfuscated class and ident name.| +|suffix|string|""|The suffix of the obfuscated class and ident name.| +|ignorePatterns|{selectors: [], idents: []}|{selectors: [], idents: []}|The patterns to be ignored during obfuscation.| |allowExtensions|string[ ]|[".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"]|The file extensions to be processed.| |contentIgnoreRegexes|RegExp[ ]|[/\.jsxs\)\("\w+"/g]|The regexes to match the content to be ignored during obfuscation.| |whiteListedFolderPaths|(string \| Regex)[ ]|[ ]|The folder paths/Regex to be processed. Empty array means all folders will be processed.| @@ -308,13 +323,13 @@ It may not be the best setting but it works for me. :) |markers|string[ ]|[ ]|Classes that indicate component(s) need to obfuscate.| |removeMarkersAfterObfuscated|boolean|true|Remove the obfuscation markers from HTML elements after obfuscation.| |removeOriginalCss|boolean|false|Delete original CSS from CSS files if it has a obfuscated version. (*NOT recommended* using in partial obfuscation) -|generatorSeed|string|"-1"|The seed for the random class name generator. "-1" means use random seed.

For "random" and "simplify-seedable" mode only. | +|generatorSeed|string \| undefined|{random string}|The seed for the random class name generator. "undefined" means use random seed.

For "random" mode only. | |logLevel|"debug" \| "info" \| "warn" \| "error" \| "success"| "info"|The log level.| ### Experimental Features Options 🚧 | Option| Type| Default| Description| Stage | | - | - | - | - | - | -|enableJsAst|boolean|false|Whether to obfuscate JS files using abstract syntax tree parser.

`contentIgnoreRegexes` option will be ignored if this option is enabled.|Alpha| +|enableJsAst|boolean|true|Whether to obfuscate JS files using abstract syntax tree parser.

`contentIgnoreRegexes` option will be ignored if this option is enabled.|Alpha| > [!NOTE]\ > The above options are still at the early stages of development and may not work as expected. @@ -334,15 +349,38 @@ It may not be the best setting but it works for me. :) module.exports = { enable: true, // Enable or disable the plugin. - mode: "random", // Obfuscate mode, "random", "simplify" or "simplify-seedable" + mode: "random", // Obfuscate mode, "random", "simplify" or "simplify-seedable". buildFolderPath: ".next", // Build folder of your project. classConversionJsonFolderPath: "./css-obfuscator", // The folder path to store the before obfuscate and after obfuscated classes conversion table. refreshClassConversionJson: false, // Refresh the class conversion JSON file. + /** + * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. + */ classLength: 5, // Length of the obfuscated class name. + + /** + * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. + */ classPrefix: "", // Prefix of the obfuscated class name. + + /** + * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. + */ classSuffix: "", // Suffix of the obfuscated class name. + + prefix: "", // Prefix of the obfuscated class and ident name. + suffix: "", // Suffix of the obfuscated class and ident name. + + /** + * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. + */ classIgnore: [], // The class names to be ignored during obfuscation. + ignorePatterns: { // The patterns to be ignored during obfuscation. + selectors: [], // The selectors to be ignored during obfuscation. + idents: [], // The idents to be ignored during obfuscation. + }, + allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], // The file extensions to be processed. contentIgnoreRegexes: [ /\.jsxs\)\("\w+"/g, // avoid accidentally obfuscate the HTML tag @@ -354,10 +392,12 @@ module.exports = { markers: ["next-css-obfuscation"], // Classes that indicate component(s) need to obfuscate. removeMarkersAfterObfuscated: true, // Remove the obfuscation markers from HTML elements after obfuscation. removeOriginalCss: false, // Delete original CSS from CSS files if it has a obfuscated version. - generatorSeed: "-1", // The seed for the random generator. "-1" means use random seed. + generatorSeed: undefined, // The seed for the random generator. "undefined" means use random seed. - //! Experimental feature - enableJsAst: false, // Whether to obfuscate JS files using abstract syntax tree parser (Experimental feature) + /** + * Experimental feature + */ + enableJsAst: true, // Whether to obfuscate JS files using abstract syntax tree parser. (Experimental feature) logLevel: "info", // Log level }; @@ -399,18 +439,20 @@ You are not expected to see this: /* obfuscated form */ .d8964 { - --tw-text-opacity: 1; - color: rgb(214 211 209 / var(--tw-text-opacity)); + --d89645: 1; + color: rgb(214 211 209 / var(--d89645)); } ``` + But this: + ```css /* example.css */ /* obfuscated form */ .d8964 { - --tw-text-opacity: 1; - color: rgb(214 211 209 / var(--tw-text-opacity)); + --d89645: 1; + color: rgb(214 211 209 / var(--d89645)); } ``` diff --git a/docs/upgrade-to-v3.md b/docs/upgrade-to-v3.md new file mode 100644 index 0000000..a57c426 --- /dev/null +++ b/docs/upgrade-to-v3.md @@ -0,0 +1,20 @@ +# Toward to version 3 + +Version 3 introduces several breaking changes, primarily focused on supporting TailwindCSS 4, nested CSS, and CSS ident obfuscation. Please review the configuration changes below carefully before upgrading. + +## Configuration + +The following table outlines the changes to the configuration options from version 2.x to 3.x: + +| Old configuration (v2.x) | New configuration (v3.x) | Notes | +| ------------------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | +| `generatorSeed` (default: -1) | `generatorSeed` (default: {random}) | Default seed is now a random string. Provide a fixed string if you need consistent output across builds (e.g., for CDN caching). | +| `mode: "simplify-seedable"` | ⛔ (Removed) | Use `mode: "random"` with a fixed `generatorSeed` instead. | +| `classLength` | ⛔ (Deprecated) | No longer supported. Will be removed in the next major version. | +| `classPrefix` | `prefix` | Renamed for clarity, now applies to both selectors and idents. `classPrefix` will be removed in the next major version. | +| `classSuffix` | `suffix` | Renamed for clarity, now applies to both selectors and idents. `classSuffix` will be removed in the next major version. | +| `classIgnore` | `ignorePatterns.selectors` | Merged into the new `ignorePatterns` object. `classIgnore` will be removed in the next major version. | +| ➡️ | `ignorePatterns.idents` | New option to ignore specific CSS idents| +| `includeAnyMatchRegexes` | ⛔ (Removed) | Use `whiteListedFolderPaths` instead. | +| `excludeAnyMatchRegexes` | ⛔ (Removed) | Use `blackListedFolderPaths` instead. | +| (Implicit `.dark` preservation)| (No implicit preservation) | TailwindCSS `.dark` class is no longer preserved by default. Add `.dark` or relevant selectors to `ignorePatterns.selectors`. | diff --git a/package-lock.json b/package-lock.json index 539af01..9c39053 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@babel/parser": "^7.23.9", "@babel/traverse": "^7.23.9", "css-parse": "^2.0.0", - "css-seasoning": "^1.3.0", + "css-seasoning": "^1.4.1", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "lightningcss-wasm": "^1.29.3", @@ -1734,9 +1734,9 @@ } }, "node_modules/css-seasoning": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/css-seasoning/-/css-seasoning-1.3.0.tgz", - "integrity": "sha512-D/Th17IefXLulL4AKphSN1uaclv+UV8eyY83GRVRxfsOzwreNwy4VA2ksmVRQoDKDUlJw2XpCO6HabFgPX5PlA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/css-seasoning/-/css-seasoning-1.4.1.tgz", + "integrity": "sha512-m5X8Qu5JWvMJH7KkygW1EzC2Yv504s+rR0AC8VCpabWUdlvzaMDw0BxBgu7+pdreR9BccKDCGd/6QxMrtGs79g==", "dependencies": { "@deno/shim-deno": "~0.18.0", "lightningcss-wasm": "^1.29.1", diff --git a/package.json b/package.json index c2f462b..bd3d144 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@babel/parser": "^7.23.9", "@babel/traverse": "^7.23.9", "css-parse": "^2.0.0", - "css-seasoning": "^1.3.0", + "css-seasoning": "^1.4.1", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "lightningcss-wasm": "^1.29.3", diff --git a/src/config.ts b/src/config.ts index 2e48a34..9c305e9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,13 +8,32 @@ export const defaultOptions: Options = { refreshClassConversionJson: false, // Refresh the class conversion JSON file. /** - * @deprecated Not longer used from v3.0.0 + * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. */ classLength: 5, // Length of the obfuscated class name. - + + /** + * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. + */ classPrefix: "", // Prefix of the obfuscated class name. + + /** + * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. + */ classSuffix: "", // Suffix of the obfuscated class name. + + prefix: "", // Prefix of the obfuscated class and ident name. + suffix: "", // Suffix of the obfuscated class and ident name. + + /** + * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. + */ classIgnore: [], // The class names to be ignored during obfuscation. + ignorePatterns: { // The patterns to be ignored during obfuscation. + selectors: [], // The selectors to be ignored during obfuscation. + idents: [], // The idents to be ignored during obfuscation. + }, + allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], // The file extensions to be processed. contentIgnoreRegexes: [ /\.jsxs\)\("\w+"/g, // avoid accidentally obfuscate the HTML tag @@ -26,13 +45,13 @@ export const defaultOptions: Options = { markers: ["next-css-obfuscation"], // Classes that indicate component(s) need to obfuscate. removeMarkersAfterObfuscated: true, // Remove the obfuscation markers from HTML elements after obfuscation. removeOriginalCss: false, // Delete original CSS from CSS files if it has a obfuscated version. - generatorSeed: "-1", // The seed for the random generator. "-1" means use random seed. - + generatorSeed: undefined, // The seed for the random generator. "undefined" means use random seed. + /** * Experimental feature */ - enableJsAst: false, // Whether to obfuscate JS files using abstract syntax tree parser. (Experimental feature) - + enableJsAst: true, // Whether to obfuscate JS files using abstract syntax tree parser. (Experimental feature) + logLevel: "info", // Log level }; diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 0cef632..728e067 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -26,7 +26,7 @@ const obfuscateCss = async ({ mode = "random", prefix, suffix, - classIgnore = [], + ignorePatterns, generatorSeed = Math.random().toString().slice(2, 10), // take 8 digits from the random number }: { cssPath: string, @@ -38,7 +38,7 @@ const obfuscateCss = async ({ mode?: obfuscateMode, prefix?: string, suffix?: string, - classIgnore?: (string | RegExp)[], + ignorePatterns?: TransformProps["ignorePatterns"], generatorSeed?: string, }) => { if (!outCssPath) { @@ -51,11 +51,6 @@ const obfuscateCss = async ({ const cssContent = fs.readFileSync(cssPath, "utf-8"); - // TODO: use const instead of function - // TODO: this function is combined createSelectorConversionJson and obfuscateCss - // TODO: connect props to this function - // TODO: bc we updated conversion table, so other function using the table have to update to the new table - let transformerMode: TransformProps["mode"] = mode === "simplify" ? "minimal" : "hash"; if (!transformerMode) { // @ts-expect-error - "simplify-seedable" is deprecated but for backward compatibility @@ -75,9 +70,7 @@ const obfuscateCss = async ({ prefix: prefix, suffix: suffix, seed: stringToNumber(generatorSeed), - ignorePatterns: { - selector: classIgnore - } + ignorePatterns: ignorePatterns, }); if (removeOriginalCss) { @@ -94,11 +87,11 @@ const obfuscateCss = async ({ finCss = new TextDecoder().decode(code); } - const totalConversion = Object.keys(newConversionTables.selector).length + Object.keys(newConversionTables.ident).length; + const totalConversion = Object.keys(newConversionTables.selectors).length + Object.keys(newConversionTables.idents).length; if (removeOriginalCss) { log("info", "CSS rules:", `Modified ${totalConversion} CSS rules to ${getFilenameFromPath(cssPath)}`); } else { - const oldTotalConversion = conversionTables ? Object.keys(conversionTables.selector).length + Object.keys(conversionTables.ident).length : 0; + const oldTotalConversion = conversionTables ? Object.keys(conversionTables.selectors).length + Object.keys(conversionTables.idents).length : 0; log("info", "CSS rules:", `Added ${totalConversion - oldTotalConversion} new CSS rules to ${getFilenameFromPath(cssPath)}`); } @@ -125,7 +118,7 @@ export const obfuscateCssFiles = async ({ mode = "random", prefix, suffix, - classIgnore = [], + ignorePatterns, generatorSeed = new Date().getTime().toString(), removeOriginalCss = false, }: { @@ -136,7 +129,7 @@ export const obfuscateCssFiles = async ({ mode?: obfuscateMode, prefix?: string, suffix?: string, - classIgnore?: (string | RegExp)[], + ignorePatterns?: TransformProps["ignorePatterns"], generatorSeed?: string, removeOriginalCss?: boolean, }) => { @@ -161,8 +154,8 @@ export const obfuscateCssFiles = async ({ }); const tables: ConversionTables = { - selector: {}, - ident: {}, + selectors: {}, + idents: {}, }; cssPaths.forEach(async (cssPath) => { @@ -173,22 +166,22 @@ export const obfuscateCssFiles = async ({ prefix, suffix, mode, - classIgnore, + ignorePatterns, generatorSeed, removeOriginalCss, }); // Merge the conversion tables - Object.entries(newConversionTables.selector).forEach(([key, value]) => { - if (!tables.selector[key]) { + Object.entries(newConversionTables.selectors).forEach(([key, value]) => { + if (!tables.selectors[key]) { // If it doesn't exist, create a new entry - tables.selector[key] = value; + tables.selectors[key] = value; } }); - Object.entries(newConversionTables.ident).forEach(([key, value]) => { - if (!tables.ident[key]) { + Object.entries(newConversionTables.idents).forEach(([key, value]) => { + if (!tables.idents[key]) { // If it doesn't exist, create a new entry - tables.ident[key] = value; + tables.idents[key] = value; } }); }); diff --git a/src/index.ts b/src/index.ts index fe7e6ad..04252c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,9 +40,15 @@ const obfuscate = async (options: Options) => { blackListedFolderPaths: options.blackListedFolderPaths, mode: options.mode, - prefix: options.classPrefix, - suffix: options.classSuffix, - classIgnore: options.classIgnore, + prefix: options.prefix || options.classPrefix, + suffix: options.suffix || options.classSuffix, + ignorePatterns: { + ...options.ignorePatterns, + selectors: [ + ...options.ignorePatterns?.selectors || [], + ...(options.classIgnore || []), + ] + }, generatorSeed: options.generatorSeed, removeOriginalCss: options.removeOriginalCss, diff --git a/src/types.ts b/src/types.ts index 11bc364..e97630c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,8 @@ -import type { ConversionTables } from "css-seasoning"; +import type { ConversionTables, TransformProps } from "css-seasoning"; export type LogLevel = "debug" | "info" | "warn" | "error" | "success"; export type obfuscateMode = "random" | "simplify"; -export type SelectorConversion = ConversionTables["selector"]; +export type SelectorConversion = ConversionTables["selectors"]; export type Options = { enable: boolean; @@ -11,10 +11,28 @@ export type Options = { classConversionJsonFolderPath: string; refreshClassConversionJson: boolean; + /** + * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. + */ classLength: number; + + /** + * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. + */ classPrefix: string; + /** + * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. + */ classSuffix: string; + prefix: string; + suffix: string; + + /** + * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. + */ classIgnore: (string | RegExp)[]; + ignorePatterns: TransformProps["ignorePatterns"]; + allowExtensions: string[]; contentIgnoreRegexes: RegExp[]; @@ -24,7 +42,7 @@ export type Options = { markers: string[]; removeMarkersAfterObfuscated: boolean; removeOriginalCss: boolean; - generatorSeed: string; + generatorSeed: string | undefined; enableJsAst: boolean; diff --git a/src/utils.ts b/src/utils.ts index 7b1ab91..79b34e4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -147,7 +147,7 @@ export const replaceJsonKeysInFiles = ( if (removeObfuscateMarkerClassesAfterObfuscated) { obfuscateMarkerClasses.forEach(obfuscateMarkerClass => { - conversionTables.selector[cssEscape(`.${obfuscateMarkerClass}`)] = ""; + conversionTables.selectors[cssEscape(`.${obfuscateMarkerClass}`)] = ""; }); } @@ -185,7 +185,7 @@ export const replaceJsonKeysInFiles = ( const htmlOriginal = htmlMatch[0]; const { obfuscatedContent, usedKeys } = obfuscateHtmlClassNames({ html: htmlOriginal, - selectorConversion: conversionTables.selector, + selectorConversion: conversionTables.selectors, obfuscateMarkerClass: obfuscateMarkerClass, contentIgnoreRegexes: contentIgnoreRegexes, }); @@ -197,7 +197,7 @@ export const replaceJsonKeysInFiles = ( } else { const obfuscateScriptContent = obfuscateJs(fileContent, obfuscateMarkerClass, - conversionTables.selector, + conversionTables.selectors, filePath, contentIgnoreRegexes, enableJsAst @@ -216,7 +216,7 @@ export const replaceJsonKeysInFiles = ( const obfuscateScriptContent = obfuscateJs( fileContent, enableJsAst ? "" : "jsx", - conversionTables.selector, + conversionTables.selectors, filePath, contentIgnoreRegexes, enableJsAst @@ -229,7 +229,7 @@ export const replaceJsonKeysInFiles = ( //! NEW const { obfuscatedContent, usedKeys } = obfuscateHtmlClassNames({ html: fileContent, - selectorConversion: conversionTables.selector, + selectorConversion: conversionTables.selectors, contentIgnoreRegexes: contentIgnoreRegexes, }); @@ -237,7 +237,7 @@ export const replaceJsonKeysInFiles = ( addKeysToRegistery(usedKeys); } else { const { obfuscatedContent, usedKeys } = obfuscateKeys( - conversionTables.selector, + conversionTables.selectors, fileContent, contentIgnoreRegexes ); @@ -524,8 +524,8 @@ export const stringToNumber = (str: string) => { */ export const loadConversionTables = (folderPath: string): ConversionTables => { const tables: ConversionTables = { - ident: {}, - selector: {}, + idents: {}, + selectors: {}, }; fs.readdirSync(folderPath).forEach((file: string) => { @@ -533,12 +533,12 @@ export const loadConversionTables = (folderPath: string): ConversionTables => { const fileData = JSON.parse(fs.readFileSync(filePath, "utf-8")); if (Object.keys(fileData).includes("ident") && Object.keys(fileData).includes("selector")) { - Object.assign(tables.ident, fileData.ident); - Object.assign(tables.selector, fileData.selector); + Object.assign(tables.idents, fileData.ident); + Object.assign(tables.selectors, fileData.selector); } else { // if the file doesn't have ident, it should be selector //? For backward compatibility - Object.assign(tables.selector, fileData); + Object.assign(tables.selectors, fileData); } }); From afe1bffe444b699d4982ca478f1055b5b7a12516 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:40:50 +0100 Subject: [PATCH 10/28] refactor: Standardize code formatting and improve readability across multiple files --- src/__tests__/js.test.ts | 164 ++++++++++---------- src/config.ts | 112 +++++++------- src/handlers/css.ts | 322 +++++++++++++++++++-------------------- src/handlers/html.ts | 2 +- src/handlers/js-ast.ts | 2 +- src/types.ts | 114 +++++++------- 6 files changed, 358 insertions(+), 358 deletions(-) diff --git a/src/__tests__/js.test.ts b/src/__tests__/js.test.ts index 3fea976..2e0d6c7 100644 --- a/src/__tests__/js.test.ts +++ b/src/__tests__/js.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect, test } from "vitest"; +import { describe, expect, test } from "vitest"; import { - searchForwardComponent, + searchForwardComponent, } from "../handlers/js"; //! ================================ @@ -9,118 +9,118 @@ import { describe("searchForwardComponent", () => { - test("should return component name when jsx format is correct", () => { - // Arrange - const content = `const element = o.jsx(ComponentName, {data: dataValue, index: "date"});`; + test("should return component name when jsx format is correct", () => { + // Arrange + const content = `const element = o.jsx(ComponentName, {data: dataValue, index: "date"});`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["ComponentName"]); - }); + // Assert + expect(result).toEqual(["ComponentName"]); + }); - test("should return multiple component names for multiple matches", () => { - // Arrange - const content = `o.jsx(FirstComponent, props); o.jsx(SecondComponent, otherProps);`; + test("should return multiple component names for multiple matches", () => { + // Arrange + const content = `o.jsx(FirstComponent, props); o.jsx(SecondComponent, otherProps);`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["FirstComponent", "SecondComponent"]); - }); + // Assert + expect(result).toEqual(["FirstComponent", "SecondComponent"]); + }); - test("should return an empty array when no component name is found", () => { - // Arrange - const content = `o.jsx("h1", {data: dataValue, index: "date"});`; + test("should return an empty array when no component name is found", () => { + // Arrange + const content = `o.jsx("h1", {data: dataValue, index: "date"});`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual([]); - }); + // Assert + expect(result).toEqual([]); + }); - test("should return an empty array when content is empty", () => { - // Arrange - const content = ""; + test("should return an empty array when content is empty", () => { + // Arrange + const content = ""; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual([]); - }); + // Assert + expect(result).toEqual([]); + }); - test("should return an empty array when jsx is not used", () => { - // Arrange - const content = `const element = React.createElement("div", null, "Hello World");`; + test("should return an empty array when jsx is not used", () => { + // Arrange + const content = `const element = React.createElement("div", null, "Hello World");`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual([]); - }); + // Assert + expect(result).toEqual([]); + }); - test("should handle special characters in component names", () => { - // Arrange - const content = `o.jsx($Comp_1, props); o.jsx(_Comp$2, otherProps);`; + test("should handle special characters in component names", () => { + // Arrange + const content = `o.jsx($Comp_1, props); o.jsx(_Comp$2, otherProps);`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["$Comp_1", "_Comp$2"]); - }); + // Assert + expect(result).toEqual(["$Comp_1", "_Comp$2"]); + }); - test("should not return component names when they are quoted", () => { - // Arrange - const content = `o.jsx("ComponentName", props); o.jsx('AnotherComponent', otherProps);`; + test("should not return component names when they are quoted", () => { + // Arrange + const content = `o.jsx("ComponentName", props); o.jsx('AnotherComponent', otherProps);`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual([]); - }); + // Assert + expect(result).toEqual([]); + }); - test("should return component names when they are followed by a brace", () => { - // Arrange - const content = `o.jsx(ComponentName, {props: true});`; + test("should return component names when they are followed by a brace", () => { + // Arrange + const content = `o.jsx(ComponentName, {props: true});`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["ComponentName"]); - }); + // Assert + expect(result).toEqual(["ComponentName"]); + }); - test("should handle content with line breaks and multiple jsx calls", () => { - // Arrange - const content = ` + test("should handle content with line breaks and multiple jsx calls", () => { + // Arrange + const content = ` o.jsx(FirstComponent, {data: dataValue}); o.jsx(SecondComponent, {index: "date"}); o.jsx(ThirdComponent, {flag: true}); `; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["FirstComponent", "SecondComponent", "ThirdComponent"]); - }); + // Assert + expect(result).toEqual(["FirstComponent", "SecondComponent", "ThirdComponent"]); + }); - test("should handle content with nested jsx calls", () => { - // Arrange - const content = `o.jsx(ParentComponent, {children: o.jsx(ChildComponent, {})})`; + test("should handle content with nested jsx calls", () => { + // Arrange + const content = `o.jsx(ParentComponent, {children: o.jsx(ChildComponent, {})})`; - // Act - const result = searchForwardComponent(content); + // Act + const result = searchForwardComponent(content); - // Assert - expect(result).toEqual(["ParentComponent", "ChildComponent"]); - }); + // Assert + expect(result).toEqual(["ParentComponent", "ChildComponent"]); + }); }); diff --git a/src/config.ts b/src/config.ts index 9c305e9..698402c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,77 +1,77 @@ import type { Options, OptionalOptions } from "./types"; export const defaultOptions: Options = { - enable: true, // Enable or disable the plugin. - mode: "random", // Obfuscate mode, "random", "simplify" or "simplify-seedable". - buildFolderPath: ".next", // Build folder of your project. - classConversionJsonFolderPath: "./css-obfuscator", // The folder path to store the before obfuscate and after obfuscated classes conversion table. - refreshClassConversionJson: false, // Refresh the class conversion JSON file. + enable: true, // Enable or disable the plugin. + mode: "random", // Obfuscate mode, "random", "simplify" or "simplify-seedable". + buildFolderPath: ".next", // Build folder of your project. + classConversionJsonFolderPath: "./css-obfuscator", // The folder path to store the before obfuscate and after obfuscated classes conversion table. + refreshClassConversionJson: false, // Refresh the class conversion JSON file. - /** - * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. - */ - classLength: 5, // Length of the obfuscated class name. + /** + * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. + */ + classLength: 5, // Length of the obfuscated class name. - /** - * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. - */ - classPrefix: "", // Prefix of the obfuscated class name. + /** + * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. + */ + classPrefix: "", // Prefix of the obfuscated class name. - /** - * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. - */ - classSuffix: "", // Suffix of the obfuscated class name. + /** + * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. + */ + classSuffix: "", // Suffix of the obfuscated class name. - prefix: "", // Prefix of the obfuscated class and ident name. - suffix: "", // Suffix of the obfuscated class and ident name. + prefix: "", // Prefix of the obfuscated class and ident name. + suffix: "", // Suffix of the obfuscated class and ident name. - /** - * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. - */ - classIgnore: [], // The class names to be ignored during obfuscation. - ignorePatterns: { // The patterns to be ignored during obfuscation. - selectors: [], // The selectors to be ignored during obfuscation. - idents: [], // The idents to be ignored during obfuscation. - }, + /** + * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. + */ + classIgnore: [], // The class names to be ignored during obfuscation. + ignorePatterns: { // The patterns to be ignored during obfuscation. + selectors: [], // The selectors to be ignored during obfuscation. + idents: [], // The idents to be ignored during obfuscation. + }, - allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], // The file extensions to be processed. - contentIgnoreRegexes: [ - /\.jsxs\)\("\w+"/g, // avoid accidentally obfuscate the HTML tag - ], // The regexes to match the file content to be ignored during obfuscation. + allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], // The file extensions to be processed. + contentIgnoreRegexes: [ + /\.jsxs\)\("\w+"/g, // avoid accidentally obfuscate the HTML tag + ], // The regexes to match the file content to be ignored during obfuscation. - whiteListedFolderPaths: [], // Only obfuscate files in these folders - blackListedFolderPaths: ["./.next/cache"], // Don't obfuscate files in these folders - enableMarkers: false, // Enable or disable the obfuscate marker classes. - markers: ["next-css-obfuscation"], // Classes that indicate component(s) need to obfuscate. - removeMarkersAfterObfuscated: true, // Remove the obfuscation markers from HTML elements after obfuscation. - removeOriginalCss: false, // Delete original CSS from CSS files if it has a obfuscated version. - generatorSeed: undefined, // The seed for the random generator. "undefined" means use random seed. + whiteListedFolderPaths: [], // Only obfuscate files in these folders + blackListedFolderPaths: ["./.next/cache"], // Don't obfuscate files in these folders + enableMarkers: false, // Enable or disable the obfuscate marker classes. + markers: ["next-css-obfuscation"], // Classes that indicate component(s) need to obfuscate. + removeMarkersAfterObfuscated: true, // Remove the obfuscation markers from HTML elements after obfuscation. + removeOriginalCss: false, // Delete original CSS from CSS files if it has a obfuscated version. + generatorSeed: undefined, // The seed for the random generator. "undefined" means use random seed. - /** - * Experimental feature - */ - enableJsAst: true, // Whether to obfuscate JS files using abstract syntax tree parser. (Experimental feature) + /** + * Experimental feature + */ + enableJsAst: true, // Whether to obfuscate JS files using abstract syntax tree parser. (Experimental feature) - logLevel: "info", // Log level + logLevel: "info", // Log level }; export class Config { - private options: Options; + private options: Options; - constructor(options?: OptionalOptions) { - if (!options) { - this.options = defaultOptions; - return; - } - this.options = { - ...defaultOptions, - ...options, - }; + constructor(options?: OptionalOptions) { + if (!options) { + this.options = defaultOptions; + return; } + this.options = { + ...defaultOptions, + ...options, + }; + } - public get(): Options { - return this.options; - } + public get(): Options { + return this.options; + } } export default Config; diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 728e067..1a0facf 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -8,185 +8,185 @@ import lightningcssInit, { transform as lightningcssTransform } from "lightningc // TODO: html failed with . import { - log, - findAllFilesWithExt, - getFilenameFromPath, - stringToNumber, - loadConversionTables, + log, + findAllFilesWithExt, + getFilenameFromPath, + stringToNumber, + loadConversionTables, } from "../utils"; const obfuscateCss = async ({ - cssPath, - removeOriginalCss, - isFullObfuscation, - outCssPath, - conversionTables, - - mode = "random", - prefix, - suffix, - ignorePatterns, - generatorSeed = Math.random().toString().slice(2, 10), // take 8 digits from the random number + cssPath, + removeOriginalCss, + isFullObfuscation, + outCssPath, + conversionTables, + + mode = "random", + prefix, + suffix, + ignorePatterns, + generatorSeed = Math.random().toString().slice(2, 10), // take 8 digits from the random number }: { - cssPath: string, - removeOriginalCss?: boolean, - isFullObfuscation?: boolean, - outCssPath?: string, - conversionTables?: ConversionTables, - - mode?: obfuscateMode, - prefix?: string, - suffix?: string, - ignorePatterns?: TransformProps["ignorePatterns"], - generatorSeed?: string, + cssPath: string, + removeOriginalCss?: boolean, + isFullObfuscation?: boolean, + outCssPath?: string, + conversionTables?: ConversionTables, + + mode?: obfuscateMode, + prefix?: string, + suffix?: string, + ignorePatterns?: TransformProps["ignorePatterns"], + generatorSeed?: string, }) => { - if (!outCssPath) { - // If no output path is provided, use the input path - outCssPath = cssPath; - } else if (!fs.existsSync(path.dirname(outCssPath))) { - // Create the output directory if it doesn't exist - fs.mkdirSync(path.dirname(outCssPath)); + if (!outCssPath) { + // If no output path is provided, use the input path + outCssPath = cssPath; + } else if (!fs.existsSync(path.dirname(outCssPath))) { + // Create the output directory if it doesn't exist + fs.mkdirSync(path.dirname(outCssPath)); + } + + const cssContent = fs.readFileSync(cssPath, "utf-8"); + + let transformerMode: TransformProps["mode"] = mode === "simplify" ? "minimal" : "hash"; + if (!transformerMode) { + // @ts-expect-error - "simplify-seedable" is deprecated but for backward compatibility + if (mode === "simplify-seedable") { + log("warn", "CSS obfuscation", "The 'simplify-seedable' mode is deprecated, please use 'random' or 'simplify' instead. Now will fall back to 'random' mode."); + transformerMode = "hash"; } - - const cssContent = fs.readFileSync(cssPath, "utf-8"); - - let transformerMode: TransformProps["mode"] = mode === "simplify" ? "minimal" : "hash"; - if (!transformerMode) { - // @ts-expect-error - "simplify-seedable" is deprecated but for backward compatibility - if (mode === "simplify-seedable") { - log("warn", "CSS obfuscation", "The 'simplify-seedable' mode is deprecated, please use 'random' or 'simplify' instead. Now will fall back to 'random' mode."); - transformerMode = "hash"; - } - log("error", "CSS obfuscation", `Invalid mode: ${mode}`); - throw new Error(`Invalid mode: ${mode}`); - } - - let finCss = ""; - const { css: obfuscatedCss, conversionTables: newConversionTables } = transform({ - css: cssContent, - conversionTables: conversionTables, - mode: transformerMode, - prefix: prefix, - suffix: suffix, - seed: stringToNumber(generatorSeed), - ignorePatterns: ignorePatterns, + log("error", "CSS obfuscation", `Invalid mode: ${mode}`); + throw new Error(`Invalid mode: ${mode}`); + } + + let finCss = ""; + const { css: obfuscatedCss, conversionTables: newConversionTables } = transform({ + css: cssContent, + conversionTables: conversionTables, + mode: transformerMode, + prefix: prefix, + suffix: suffix, + seed: stringToNumber(generatorSeed), + ignorePatterns: ignorePatterns, + }); + + if (removeOriginalCss) { + finCss = obfuscatedCss; + } else { + // if keep original selector, we need to merge the original css with the obfuscated css + // then minify the css in order to marge the css + const mixedCss = cssContent + obfuscatedCss; + const { code } = lightningcssTransform({ + filename: "style.css", + code: new TextEncoder().encode(mixedCss), + minify: true, }); - - if (removeOriginalCss) { - finCss = obfuscatedCss; - } else { - // if keep original selector, we need to merge the original css with the obfuscated css - // then minify the css in order to marge the css - const mixedCss = cssContent + obfuscatedCss; - const { code } = lightningcssTransform({ - filename: "style.css", - code: new TextEncoder().encode(mixedCss), - minify: true, - }); - finCss = new TextDecoder().decode(code); - } - - const totalConversion = Object.keys(newConversionTables.selectors).length + Object.keys(newConversionTables.idents).length; - if (removeOriginalCss) { - log("info", "CSS rules:", `Modified ${totalConversion} CSS rules to ${getFilenameFromPath(cssPath)}`); - } else { - const oldTotalConversion = conversionTables ? Object.keys(conversionTables.selectors).length + Object.keys(conversionTables.idents).length : 0; - log("info", "CSS rules:", `Added ${totalConversion - oldTotalConversion} new CSS rules to ${getFilenameFromPath(cssPath)}`); - } - - // Save the obfuscated CSS to the output path - const sizeBefore = Buffer.byteLength(cssContent, "utf8"); - fs.writeFileSync(outCssPath, obfuscatedCss); - const sizeAfter = Buffer.byteLength(obfuscatedCss, "utf8"); - const percentChange = Math.round(((sizeAfter) / sizeBefore) * 100); - log("success", "CSS obfuscated:", `Size from ${sizeBefore} to ${sizeAfter} bytes (${percentChange}%) in ${getFilenameFromPath(cssPath)}`); - - return { - conversionTables: newConversionTables, - } + finCss = new TextDecoder().decode(code); + } + + const totalConversion = Object.keys(newConversionTables.selectors).length + Object.keys(newConversionTables.idents).length; + if (removeOriginalCss) { + log("info", "CSS rules:", `Modified ${totalConversion} CSS rules to ${getFilenameFromPath(cssPath)}`); + } else { + const oldTotalConversion = conversionTables ? Object.keys(conversionTables.selectors).length + Object.keys(conversionTables.idents).length : 0; + log("info", "CSS rules:", `Added ${totalConversion - oldTotalConversion} new CSS rules to ${getFilenameFromPath(cssPath)}`); + } + + // Save the obfuscated CSS to the output path + const sizeBefore = Buffer.byteLength(cssContent, "utf8"); + fs.writeFileSync(outCssPath, obfuscatedCss); + const sizeAfter = Buffer.byteLength(obfuscatedCss, "utf8"); + const percentChange = Math.round(((sizeAfter) / sizeBefore) * 100); + log("success", "CSS obfuscated:", `Size from ${sizeBefore} to ${sizeAfter} bytes (${percentChange}%) in ${getFilenameFromPath(cssPath)}`); + + return { + conversionTables: newConversionTables, + } } /** * */ export const obfuscateCssFiles = async ({ - selectorConversionJsonFolderPath, - buildFolderPath, - whiteListedFolderPaths = [], - blackListedFolderPaths = [], - mode = "random", - prefix, - suffix, - ignorePatterns, - generatorSeed = new Date().getTime().toString(), - removeOriginalCss = false, + selectorConversionJsonFolderPath, + buildFolderPath, + whiteListedFolderPaths = [], + blackListedFolderPaths = [], + mode = "random", + prefix, + suffix, + ignorePatterns, + generatorSeed = new Date().getTime().toString(), + removeOriginalCss = false, }: { - selectorConversionJsonFolderPath: string, - buildFolderPath: string, - whiteListedFolderPaths: (string | RegExp)[], - blackListedFolderPaths: (string | RegExp)[], - mode?: obfuscateMode, - prefix?: string, - suffix?: string, - ignorePatterns?: TransformProps["ignorePatterns"], - generatorSeed?: string, - removeOriginalCss?: boolean, + selectorConversionJsonFolderPath: string, + buildFolderPath: string, + whiteListedFolderPaths: (string | RegExp)[], + blackListedFolderPaths: (string | RegExp)[], + mode?: obfuscateMode, + prefix?: string, + suffix?: string, + ignorePatterns?: TransformProps["ignorePatterns"], + generatorSeed?: string, + removeOriginalCss?: boolean, }) => { - // Initialize nessesary modules - await Promise.all([ - initTransform(), - lightningcssInit(), - ]); - - // Create the selector conversion JSON folder if it doesn't exist - if (!fs.existsSync(selectorConversionJsonFolderPath)) { - fs.mkdirSync(selectorConversionJsonFolderPath); - } - - // Load and merge all JSON files in the selector conversion folder - const conversionTables = loadConversionTables(selectorConversionJsonFolderPath); + // Initialize nessesary modules + await Promise.all([ + initTransform(), + lightningcssInit(), + ]); + + // Create the selector conversion JSON folder if it doesn't exist + if (!fs.existsSync(selectorConversionJsonFolderPath)) { + fs.mkdirSync(selectorConversionJsonFolderPath); + } + + // Load and merge all JSON files in the selector conversion folder + const conversionTables = loadConversionTables(selectorConversionJsonFolderPath); + + // Get all CSS files using the unified path filtering function + const cssPaths = findAllFilesWithExt(".css", buildFolderPath, { + whiteListedFolderPaths, + blackListedFolderPaths, + }); + + const tables: ConversionTables = { + selectors: {}, + idents: {}, + }; + + cssPaths.forEach(async (cssPath) => { + const { conversionTables: newConversionTables } = await obfuscateCss({ + cssPath: cssPath, + conversionTables: conversionTables, + + prefix, + suffix, + mode, + ignorePatterns, + generatorSeed, + removeOriginalCss, + }); - // Get all CSS files using the unified path filtering function - const cssPaths = findAllFilesWithExt(".css", buildFolderPath, { - whiteListedFolderPaths, - blackListedFolderPaths, + // Merge the conversion tables + Object.entries(newConversionTables.selectors).forEach(([key, value]) => { + if (!tables.selectors[key]) { + // If it doesn't exist, create a new entry + tables.selectors[key] = value; + } }); - - const tables: ConversionTables = { - selectors: {}, - idents: {}, - }; - - cssPaths.forEach(async (cssPath) => { - const { conversionTables: newConversionTables } = await obfuscateCss({ - cssPath: cssPath, - conversionTables: conversionTables, - - prefix, - suffix, - mode, - ignorePatterns, - generatorSeed, - removeOriginalCss, - }); - - // Merge the conversion tables - Object.entries(newConversionTables.selectors).forEach(([key, value]) => { - if (!tables.selectors[key]) { - // If it doesn't exist, create a new entry - tables.selectors[key] = value; - } - }); - Object.entries(newConversionTables.idents).forEach(([key, value]) => { - if (!tables.idents[key]) { - // If it doesn't exist, create a new entry - tables.idents[key] = value; - } - }); + Object.entries(newConversionTables.idents).forEach(([key, value]) => { + if (!tables.idents[key]) { + // If it doesn't exist, create a new entry + tables.idents[key] = value; + } }); + }); - return { - conversionTables: tables, - }; + return { + conversionTables: tables, + }; } diff --git a/src/handlers/html.ts b/src/handlers/html.ts index 2ba059d..dec206b 100644 --- a/src/handlers/html.ts +++ b/src/handlers/html.ts @@ -89,7 +89,7 @@ export const obfuscateHtmlClassNames = ({ modifiedHtml += `<${tagName}`; for (const key in attribs) { // modifiedHtml += ` ${key}="${attribs[key]}"`; - modifiedHtml += ` ${key}="${htmlEscape(attribs[key])}"`; + modifiedHtml += ` ${key}="${htmlEscape(attribs[key])}"`; } if (voidTags.includes(tagName)) { modifiedHtml += " />"; diff --git a/src/handlers/js-ast.ts b/src/handlers/js-ast.ts index 8b368e3..8ab82d4 100644 --- a/src/handlers/js-ast.ts +++ b/src/handlers/js-ast.ts @@ -42,7 +42,7 @@ export const obfuscateJsWithAst = ( : str; const { obfuscatedContent, usedKeys: obfuscateUsedKeys } = obfuscateKeys(selectorConversion, str); - + if (obfuscatedContent !== str) { obfuscateUsedKeys.forEach(key => usedKeys.add(key)); return obfuscatedContent; diff --git a/src/types.ts b/src/types.ts index e97630c..f52c053 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,77 +5,77 @@ export type obfuscateMode = "random" | "simplify"; export type SelectorConversion = ConversionTables["selectors"]; export type Options = { - enable: boolean; - mode: obfuscateMode; - buildFolderPath: string; - classConversionJsonFolderPath: string; - refreshClassConversionJson: boolean; + enable: boolean; + mode: obfuscateMode; + buildFolderPath: string; + classConversionJsonFolderPath: string; + refreshClassConversionJson: boolean; - /** - * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. - */ - classLength: number; - - /** - * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. - */ - classPrefix: string; - /** - * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. - */ - classSuffix: string; - prefix: string; - suffix: string; + /** + * @deprecated Not longer used from v3.0.0 and will be removed in the next major version. + */ + classLength: number; - /** - * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. - */ - classIgnore: (string | RegExp)[]; - ignorePatterns: TransformProps["ignorePatterns"]; + /** + * @deprecated Merged into `prefix` from v3.0.0 and will be removed in the next major version. + */ + classPrefix: string; + /** + * @deprecated Merged into `suffix` from v3.0.0 and will be removed in the next major version. + */ + classSuffix: string; + prefix: string; + suffix: string; - allowExtensions: string[]; - contentIgnoreRegexes: RegExp[]; + /** + * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. + */ + classIgnore: (string | RegExp)[]; + ignorePatterns: TransformProps["ignorePatterns"]; - whiteListedFolderPaths: (string | RegExp)[]; - blackListedFolderPaths: (string | RegExp)[]; - enableMarkers: boolean; - markers: string[]; - removeMarkersAfterObfuscated: boolean; - removeOriginalCss: boolean; - generatorSeed: string | undefined; + allowExtensions: string[]; + contentIgnoreRegexes: RegExp[]; - enableJsAst: boolean; + whiteListedFolderPaths: (string | RegExp)[]; + blackListedFolderPaths: (string | RegExp)[]; + enableMarkers: boolean; + markers: string[]; + removeMarkersAfterObfuscated: boolean; + removeOriginalCss: boolean; + generatorSeed: string | undefined; - logLevel: LogLevel; + enableJsAst: boolean; + + logLevel: LogLevel; } export type OptionalOptions = { - enable?: boolean; - mode?: obfuscateMode; - buildFolderPath?: string; - classConversionJsonFolderPath?: string; - refreshClassConversionJson?: boolean; + enable?: boolean; + mode?: obfuscateMode; + buildFolderPath?: string; + classConversionJsonFolderPath?: string; + refreshClassConversionJson?: boolean; - classLength?: number; - classPrefix?: string; - classSuffix?: string; - classIgnore?: string[]; - allowExtensions?: string[]; - contentIgnoreRegexes: RegExp[]; + classLength?: number; + classPrefix?: string; + classSuffix?: string; + classIgnore?: string[]; + allowExtensions?: string[]; + contentIgnoreRegexes: RegExp[]; - whiteListedFolderPaths?: (string | RegExp)[]; - blackListedFolderPaths?: (string | RegExp)[]; - enableMarkers?: boolean; - markers?: string[]; - removeMarkersAfterObfuscated?: boolean; - removeOriginalCss?: boolean; - generatorSeed?: string; + whiteListedFolderPaths?: (string | RegExp)[]; + blackListedFolderPaths?: (string | RegExp)[]; + enableMarkers?: boolean; + markers?: string[]; + removeMarkersAfterObfuscated?: boolean; + removeOriginalCss?: boolean; + generatorSeed?: string; - enableJsAst?: boolean; + enableJsAst?: boolean; - logLevel?: LogLevel; + logLevel?: LogLevel; } export interface HtmlCharacterEntityConversion { - [key: string]: string; + [key: string]: string; } From 5492d56d1871c0d58aecbf9de8bc046e2bb6a0ad Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:41:55 +0100 Subject: [PATCH 11/28] refactor: Remove unused dependency 'recoverable-random' from package files --- package-lock.json | 6 ------ package.json | 1 - src/__tests__/utils.test.ts | 2 -- src/utils.ts | 2 -- 4 files changed, 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c39053..8ed2de5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "lightningcss-wasm": "^1.29.3", - "recoverable-random": "^1.0.5", "yargs": "^17.7.2" }, "bin": { @@ -2373,11 +2372,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/recoverable-random": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/recoverable-random/-/recoverable-random-1.0.5.tgz", - "integrity": "sha512-/8pSRgo2b96TZPK7UshniNn0A/q3ePARXsDL8z0Yvhhk7+PESziarQ0e8mn4YNM7qB6bX0mPcEfMtda4RY/ahA==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", diff --git a/package.json b/package.json index bd3d144..47a26e8 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "lightningcss-wasm": "^1.29.3", - "recoverable-random": "^1.0.5", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 48c34e6..77fbd65 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -4,8 +4,6 @@ import { getFilenameFromPath, duplicationCheck, } from "../utils"; -import NumberGenerator from "recoverable-random"; - //! ================================ //! findContentBetweenMarker diff --git a/src/utils.ts b/src/utils.ts index 79b34e4..1e699db 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,12 +1,10 @@ import fs from "node:fs"; import path from "node:path"; -import NumberGenerator from "recoverable-random"; import type { LogLevel, SelectorConversion, } from "./types"; import { cssEscape, cssUnescape, type ConversionTables } from "css-seasoning"; - import { obfuscateHtmlClassNames } from "./handlers/html"; import { obfuscateJs } from "./handlers/js"; From b43a19477962fe85e7bf26b890624998648be1ba Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:58:16 +0100 Subject: [PATCH 12/28] feat: Enables semantic release for automated publishing Sets up semantic release to automate the release process. This includes: - Adding a release workflow file. - Installing semantic-release and related plugins. - Creating a release configuration file. This automates versioning, changelog generation, and package publishing. --- .github/workflows/release.yml | 32 + package-lock.json | 6514 +++++++++++++++++++++++++++++++-- package.json | 7 +- release.config.cjs | 22 + tsconfig.json | 7 +- 5 files changed, 6176 insertions(+), 406 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 release.config.cjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3f251c5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: Release + +on: + push: + branches: + - main + - beta + +permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: npm install + + - name: Build NPM package + run: npm run build + + - name: Create Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm run semantic-release diff --git a/package-lock.json b/package-lock.json index 8ed2de5..90623f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,8 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", + "@semantic-release/git": "^10.0.1", + "@semantic-release/npm": "^12.0.1", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", "@types/html-escaper": "^3.0.4", @@ -32,6 +34,7 @@ "@types/yargs": "^17.0.32", "@vitest/coverage-v8": "^3.0.5", "prettier": "^3.2.4", + "semantic-release": "^24.2.3", "tslib": "^2.6.2", "typescript": "^5.0.2", "vitest": "^3.0.5" @@ -51,81 +54,18 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/generator": { "version": "7.23.6", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", @@ -198,83 +138,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { "version": "7.26.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", @@ -498,6 +361,16 @@ "node": ">=14.21.3" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@deno/shim-deno": { "version": "0.18.2", "resolved": "https://registry.npmjs.org/@deno/shim-deno/-/shim-deno-0.18.2.tgz", @@ -1107,6 +980,216 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", + "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.5.tgz", + "integrity": "sha512-vvmsN0r7rguA+FySiCsbaTTobSftpIDIpPW81trAmsv9TGxg3YCujAxRYp/Uy8xmDgYCzzgulG62H7KYUFmeIg==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^5.0.0", + "@octokit/graphql": "^8.2.2", + "@octokit/request": "^9.2.3", + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0", + "before-after-hook": "^3.0.2", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", + "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", + "dev": true, + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz", + "integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==", + "dev": true, + "dependencies": { + "@octokit/request": "^9.2.3", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz", + "integrity": "sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz", + "integrity": "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.10.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.2.1.tgz", + "integrity": "sha512-wUc3gv0D6vNHpGxSaR3FlqJpTXGWgqmk607N9L3LvPL4QjaxDgX/1nY2mGpT37Khn+nlIXdljczkRnNdTTV3/A==", + "dev": true, + "dependencies": { + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.6.1.tgz", + "integrity": "sha512-bt3EBUkeKUzDQXRCcFrR9SWVqlLFRRqcCrr6uAorWt6NXTyjMKqcGrFmXqJy9NCbnKgiIZ2OXWq04theFc76Jg==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.7.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^6.1.3" + } + }, + "node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true + }, + "node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/request": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.3.tgz", + "integrity": "sha512-Ma+pZU8PXLOEYzsWf0cn/gY+ME57Wq8f49WTXA8FMHp2Ps9djKw//xYJ1je8Hm0pR2lU9FUGeJRWOtxq6olt4w==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^10.1.4", + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^2.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz", + "integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==", + "dev": true, + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.0.0.tgz", + "integrity": "sha512-VVmZP0lEhbo2O1pdq63gZFiGCKkm8PPp8AUOijlwPO6hojEVjspA0MWKP7E4hbvGxzFKNqKr6p0IYtOH/Wf/zA==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^25.0.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1117,6 +1200,47 @@ "node": ">=14" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.34.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.2.tgz", @@ -1364,17 +1488,337 @@ "win32" ] }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.1.tgz", + "integrity": "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==", "dev": true, "dependencies": { - "@babel/types": "^7.0.0" + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.20.5", + "node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/git": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", + "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/git/node_modules/@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/git/node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@semantic-release/git/node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@semantic-release/git/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/git/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/@semantic-release/git/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@semantic-release/git/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/git/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@semantic-release/git/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@semantic-release/git/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/git/node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@semantic-release/git/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/@semantic-release/git/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@semantic-release/github": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.1.tgz", + "integrity": "sha512-Z9cr0LgU/zgucbT9cksH0/pX9zmVda9hkDPcgIE0uvjMQ8w/mElDivGjx1w1pEQ+MuQJ5CBq3VCF16S6G4VH3A==", + "dev": true, + "dependencies": { + "@octokit/core": "^6.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/plugin-retry": "^7.0.0", + "@octokit/plugin-throttling": "^9.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^14.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^7.0.0", + "lodash-es": "^4.17.21", + "mime": "^4.0.0", + "p-filter": "^4.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=24.1.0" + } + }, + "node_modules/@semantic-release/npm": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-12.0.1.tgz", + "integrity": "sha512-/6nntGSUGK2aTOI0rHPwY3ZjgY9FkXmEHbW9Kr+62NVOsyqpKKeP0lrCH+tphv+EsNdJNmqqwijTEnVWUMQ2Nw==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "execa": "^9.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^10.5.0", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.3.tgz", + "integrity": "sha512-XxAZRPWGwO5JwJtS83bRdoIhCiYIx8Vhr+u231pQAsdFIAbm19rSVJLdnBN+Avvk7CKvNQE/nJ4y7uqKH6WTiw==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^2.0.0", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-package-up": "^11.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, @@ -1403,6 +1847,12 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, "node_modules/@types/prop-types": { "version": "15.7.9", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", @@ -1579,6 +2029,46 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1601,6 +2091,30 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", + "dev": true + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -1627,6 +2141,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/before-after-hook": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", + "dev": true + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1636,6 +2162,18 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -1645,6 +2183,15 @@ "node": ">=8" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/chai": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", @@ -1661,6 +2208,27 @@ "node": ">=12" } }, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -1670,49 +2238,299 @@ "node": ">= 16" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "escape-string-regexp": "5.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" }, "engines": { - "node": ">=7.0.0" + "node": ">=8.0.0", + "npm": ">=5.0.0" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz", + "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.0.1.tgz", + "integrity": "sha512-hlqcy3xHred2gyYg/zXSMXraY2mjAYYo0msUCpK+BGyaVJMFCKWVXPIHiaacGO2GGp13kvHWXFhYmxT4QQqW3Q==", + "dev": true, + "dependencies": { + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", + "semver": "^7.5.2" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-filter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.1.0.tgz", + "integrity": "sha512-5nxDo7TwKB5InYBl4ZC//1g9GRwB/F3TXOGR9hgUjMGfvSP4Vu5NkpNro2+1+TIEy1vwxApl5ircECr2ri5JIw==", + "dev": true, + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", @@ -1784,6 +2602,27 @@ "node": ">=6" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -1846,6 +2685,27 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1857,6 +2717,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true + }, "node_modules/entities": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", @@ -1868,72 +2734,264 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true + "node_modules/env-ci": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.1.0.tgz", + "integrity": "sha512-Z8dnwSDbV1XYM9SBF2J0GcNVvmfmfh3a49qddGIROhBoVro6MZVTji15z/sJbQ2ko2ei8n988EU1wzoLU/tF+g==", + "dev": true, + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=18" + "node": ">=16.17" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/env-ci/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" + "engines": { + "node": ">=16.17.0" } }, - "node_modules/expect-type": { - "version": "1.1.0", + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/execa": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", + "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.3", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.0", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expect-type": { + "version": "1.1.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", "dev": true, @@ -1941,6 +2999,114 @@ "node": ">=12.0.0" } }, + "node_modules/fast-content-type-parse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", + "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", + "dev": true, + "dependencies": { + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -1957,6 +3123,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1971,6 +3161,18 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-timeout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", + "integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1979,6 +3181,32 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", + "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", + "dev": true, + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -1999,6 +3227,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2007,15 +3247,125 @@ "node": ">=4" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hook-std": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/html-escaper": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", @@ -2039,11 +3389,164 @@ "entities": "^6.0.0" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ignore": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", + "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from-esm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-2.0.0.tgz", + "integrity": "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": ">=18.20" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/into-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "dev": true, + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2052,229 +3555,3624 @@ "node": ">=8" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/issue-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", + "dev": true, + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports/node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lightningcss-wasm": { + "version": "1.29.3", + "resolved": "https://registry.npmjs.org/lightningcss-wasm/-/lightningcss-wasm-1.29.3.tgz", + "integrity": "sha512-j02QNSRVBKxsSBinpSCgx3x8XwwOoO50ekDO1O5rBf+dS0j46qSojv+3BDzMNCaGFJ18EjcnXGDkG3ImIbU/PQ==", + "bundleDependencies": [ + "napi-wasm" + ], + "dependencies": { + "napi-wasm": "^1.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-wasm/node_modules/napi-wasm": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true + }, + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/marked-terminal": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz", + "integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "ansi-regex": "^6.1.0", + "chalk": "^5.4.1", + "cli-highlight": "^2.1.11", + "cli-table3": "^0.6.5", + "node-emoji": "^2.2.0", + "supports-hyperlinks": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <16" + } + }, + "node_modules/marked-terminal/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz", + "integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.9.2.tgz", + "integrity": "sha512-iriPEPIkoMYUy3F6f3wwSZAU93E0Eg6cHwIR6jzzOXWSy+SD/rOODEs74cVONHKSx2obXtuUoyidVEhISrisgQ==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "dev": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^8.0.0", + "@npmcli/config": "^9.0.0", + "@npmcli/fs": "^4.0.0", + "@npmcli/map-workspaces": "^4.0.2", + "@npmcli/package-json": "^6.1.0", + "@npmcli/promise-spawn": "^8.0.2", + "@npmcli/redact": "^3.0.0", + "@npmcli/run-script": "^9.0.1", + "@sigstore/tuf": "^3.0.0", + "abbrev": "^3.0.0", + "archy": "~1.0.0", + "cacache": "^19.0.1", + "chalk": "^5.3.0", + "ci-info": "^4.1.0", + "cli-columns": "^4.0.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.4.5", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^8.0.2", + "ini": "^5.0.0", + "init-package-json": "^7.0.2", + "is-cidr": "^5.1.0", + "json-parse-even-better-errors": "^4.0.0", + "libnpmaccess": "^9.0.0", + "libnpmdiff": "^7.0.0", + "libnpmexec": "^9.0.0", + "libnpmfund": "^6.0.0", + "libnpmhook": "^11.0.0", + "libnpmorg": "^7.0.0", + "libnpmpack": "^8.0.0", + "libnpmpublish": "^10.0.1", + "libnpmsearch": "^8.0.0", + "libnpmteam": "^7.0.0", + "libnpmversion": "^7.0.0", + "make-fetch-happen": "^14.0.3", + "minimatch": "^9.0.5", + "minipass": "^7.1.1", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^11.0.0", + "nopt": "^8.0.0", + "normalize-package-data": "^7.0.0", + "npm-audit-report": "^6.0.0", + "npm-install-checks": "^7.1.1", + "npm-package-arg": "^12.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-profile": "^11.0.1", + "npm-registry-fetch": "^18.0.2", + "npm-user-validate": "^3.0.0", + "p-map": "^4.0.0", + "pacote": "^19.0.1", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^4.0.0", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "ssri": "^12.0.0", + "supports-color": "^9.4.0", + "tar": "^6.2.1", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^6.0.0", + "which": "^5.0.0", + "write-file-atomic": "^6.0.0" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^4.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/map-workspaces": "^4.0.1", + "@npmcli/metavuln-calculator": "^8.0.0", + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.1", + "@npmcli/query": "^4.0.0", + "@npmcli/redact": "^3.0.0", + "@npmcli/run-script": "^9.0.1", + "bin-links": "^5.0.0", + "cacache": "^19.0.1", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^10.2.2", + "minimatch": "^9.0.4", + "nopt": "^8.0.0", + "npm-install-checks": "^7.1.0", + "npm-package-arg": "^12.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.1", + "pacote": "^19.0.0", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "proggy": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^4.0.0", + "semver": "^7.3.7", + "ssri": "^12.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^4.0.1", + "@npmcli/package-json": "^6.0.1", + "ci-info": "^4.0.0", + "ini": "^5.0.0", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^19.0.0", + "json-parse-even-better-errors": "^4.0.0", + "pacote": "^20.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { + "version": "20.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^9.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "normalize-package-data": "^7.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "9.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "node-gyp": "^11.0.0", + "proc-log": "^5.0.0", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^7.0.0", + "npm-normalize-package-bin": "^4.0.0", + "proc-log": "^5.0.0", + "read-cmd-shim": "^5.0.0", + "write-file-atomic": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "19.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/minizlib": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/p-map": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/tar": { + "version": "7.4.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.1.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "5.2.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/foreground-child": { + "version": "3.3.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "10.4.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^6.0.0", + "npm-package-arg": "^12.0.0", + "promzard": "^2.0.0", + "read": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "5.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^4.1.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jackspeak": { + "version": "3.4.3", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/npm/node_modules/jsbn": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^12.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "binary-extensions": "^2.3.0", + "diff": "^5.1.0", + "minimatch": "^9.0.4", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0", + "tar": "^6.2.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.0", + "@npmcli/run-script": "^9.0.1", + "ci-info": "^4.0.0", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0", + "proc-log": "^5.0.0", + "read": "^4.0.0", + "read-package-json-fast": "^4.0.0", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "11.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.0", + "@npmcli/run-script": "^9.0.1", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^7.0.0", + "npm-package-arg": "^12.0.0", + "npm-registry-fetch": "^18.0.1", + "proc-log": "^5.0.0", + "semver": "^7.3.7", + "sigstore": "^3.0.0", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.1", + "@npmcli/run-script": "^9.0.1", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "14.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "11.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/minizlib": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/tar": { + "version": "7.4.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/nopt/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "7.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "12.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^7.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "10.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "18.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^3.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^14.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^12.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/package-json-from-dist": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/npm/node_modules/pacote": { + "version": "19.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^9.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^2.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "5.0.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.6.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.0.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^3.0.0", + "@sigstore/tuf": "^3.0.0", + "@sigstore/verify": "^2.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/core": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/sign": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.0.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^14.0.1", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/verify": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.0.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.20", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/ssri": { + "version": "12.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "3.0.1", + "debug": "^4.3.6", + "make-fetch-happen": "^14.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/which": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", "dev": true, + "inBundle": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", "dev": true, + "inBundle": true, + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "inBundle": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "node_modules/npm/node_modules/write-file-atomic": { + "version": "6.0.0", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/istanbul-reports/node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "@isaacs/cliui": "^8.0.2" + "mimic-fn": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=12" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, + "node_modules/p-each-series": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", + "dev": true, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-wasm": { - "version": "1.29.3", - "resolved": "https://registry.npmjs.org/lightningcss-wasm/-/lightningcss-wasm-1.29.3.tgz", - "integrity": "sha512-j02QNSRVBKxsSBinpSCgx3x8XwwOoO50ekDO1O5rBf+dS0j46qSojv+3BDzMNCaGFJ18EjcnXGDkG3ImIbU/PQ==", - "bundleDependencies": [ - "napi-wasm" - ], + "node_modules/p-filter": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", + "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", + "dev": true, "dependencies": { - "napi-wasm": "^1.0.1" + "p-map": "^7.0.1" }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-wasm/node_modules/napi-wasm": { - "version": "1.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/loupe": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", - "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", - "dev": true + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "p-try": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "dev": true, - "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "callsites": "^3.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", "dev": true, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "dependencies": { + "parse5": "^6.0.1" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2306,6 +7204,15 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pathe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", @@ -2325,9 +7232,42 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -2372,6 +7312,160 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "dev": true, + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2380,12 +7474,31 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "deprecated": "https://github.com/lydell/resolve-url#deprecated" }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.34.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.2.tgz", @@ -2424,6 +7537,78 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semantic-release": { + "version": "24.2.3", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.3.tgz", + "integrity": "sha512-KRhQG9cUazPavJiJEFIJ3XAMjgfd0fcK3B+T26qOl8L0UG5aZUjeRfREO0KM5InGtYwxqiiytkJrbcYoLDEv0A==", + "dev": true, + "dependencies": { + "@semantic-release/commit-analyzer": "^13.0.0-beta.1", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^11.0.0", + "@semantic-release/npm": "^12.0.0", + "@semantic-release/release-notes-generator": "^14.0.0-beta.1", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^9.0.0", + "debug": "^4.0.0", + "env-ci": "^11.0.0", + "execa": "^9.0.0", + "figures": "^6.0.0", + "find-versions": "^6.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^8.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "marked": "^12.0.0", + "marked-terminal": "^7.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-package-up": "^11.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": ">=20.8.1" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -2436,46 +7621,194 @@ "semver": "bin/semver.js" }, "engines": { - "node": ">=10" + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/signale/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/signale/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" } }, - "node_modules/shebang-command": { + "node_modules/signale/node_modules/figures": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/shebang-regex": { + "node_modules/signale/node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/siginfo": { + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/skin-tone": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "engines": { - "node": ">=14" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/source-map": { @@ -2514,6 +7847,53 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "deprecated": "See https://github.com/lydell/source-map-url#deprecated" }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "node_modules/split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", + "dev": true, + "dependencies": { + "through2": "~2.0.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -2526,6 +7906,25 @@ "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", "dev": true }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2578,6 +7977,52 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/super-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", + "integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==", + "dev": true, + "dependencies": { + "function-timeout": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2590,6 +8035,73 @@ "node": ">=8" } }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/test-exclude": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", @@ -2604,6 +8116,52 @@ "node": ">=18" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -2643,12 +8201,48 @@ "node": ">=14.0.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, + "node_modules/type-fest": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz", + "integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", @@ -2662,18 +8256,107 @@ "node": ">=14.17" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", + "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "deprecated": "Please see https://github.com/lydell/urix#deprecated" }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vite": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", @@ -2868,6 +8551,12 @@ "node": ">=8" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2902,6 +8591,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", @@ -2945,6 +8643,18 @@ "engines": { "node": ">=12" } + }, + "node_modules/yoctocolors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 47a26e8..5c1f2a4 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "build": "npm run test && tsc", "dev": "tsc -w", "pub": "npm run build && npm publish", - "pub@beta": "npm run build && npm publish --tag beta" + "pub@beta": "npm run build && npm publish --tag beta", + "lint": "biome check .", + "semantic-release": "semantic-release" }, "repository": { "type": "git", @@ -35,6 +37,8 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", + "@semantic-release/git": "^10.0.1", + "@semantic-release/npm": "^12.0.1", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", "@types/html-escaper": "^3.0.4", @@ -43,6 +47,7 @@ "@types/yargs": "^17.0.32", "@vitest/coverage-v8": "^3.0.5", "prettier": "^3.2.4", + "semantic-release": "^24.2.3", "tslib": "^2.6.2", "typescript": "^5.0.2", "vitest": "^3.0.5" diff --git a/release.config.cjs b/release.config.cjs new file mode 100644 index 0000000..8ec50a2 --- /dev/null +++ b/release.config.cjs @@ -0,0 +1,22 @@ +module.exports = { + branches: [{ name: "main" }, { name: "beta", prerelease: true }], + plugins: [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + [ + "@semantic-release/npm", + { + npmPublish: true, + pkgRoot: "dist", + }, + ], + [ + "@semantic-release/git", + { + message: + "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", + assets: ["package.json", "CHANGELOG.md"], + }, + ], + ], +}; diff --git a/tsconfig.json b/tsconfig.json index 132c89a..a719f75 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "esModuleInterop": true, "skipLibCheck": true, "moduleResolution": "node", - "newLine": "LF", + "newLine": "LF" }, "exclude": [ "node_modules", @@ -23,6 +23,7 @@ "bin", "patched-postcss-obfuscator", "demos", - "src/*.test.*" + "src/*.test.*", + "release.config.cjs" ] -} \ No newline at end of file +} From f51783907915a9ca11394cd9e8437af069af46de Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:10:04 +0100 Subject: [PATCH 13/28] fix: fix html tests --- bin/cli.mjs | 2 +- biome.json | 13 +++++++---- src/__tests__/html.test.ts | 48 +++++++++++++++++++------------------- src/config.ts | 5 ++-- src/handlers/css.ts | 2 +- src/handlers/js-ast.ts | 6 ++--- src/types.ts | 4 ++-- src/utils.ts | 12 +++++----- 8 files changed, 49 insertions(+), 43 deletions(-) diff --git a/bin/cli.mjs b/bin/cli.mjs index 90ba1c3..40ac88e 100644 --- a/bin/cli.mjs +++ b/bin/cli.mjs @@ -2,4 +2,4 @@ import { obfuscateCli } from "../dist/index.js"; -obfuscateCli(); \ No newline at end of file +obfuscateCli(); diff --git a/biome.json b/biome.json index 03fb901..74c13be 100644 --- a/biome.json +++ b/biome.json @@ -7,10 +7,16 @@ }, "files": { "ignoreUnknown": false, - "ignore": [] + "ignore": [ + "node_modules", + ".next", + "packages/tsconfig", + "demos", + "coverage", + "dist" + ] }, "formatter": { - "ignore": ["node_modules", ".next"], "enabled": true, "indentStyle": "space", "lineWidth": 80, @@ -21,7 +27,6 @@ "enabled": true }, "linter": { - "ignore": ["node_modules", ".next", "packages/tsconfig"], "enabled": true, "rules": { "recommended": true, @@ -30,7 +35,7 @@ "noUselessTypeConstraint": "error", "useLiteralKeys": "error", "useOptionalChain": "error", - "noForEach": "off", + "noForEach": "off" }, "correctness": { "noUnusedVariables": "info", diff --git a/src/__tests__/html.test.ts b/src/__tests__/html.test.ts index 44693e7..80bf098 100644 --- a/src/__tests__/html.test.ts +++ b/src/__tests__/html.test.ts @@ -15,20 +15,20 @@ describe("obfuscateHtmlClassNames", () => { it("should obfuscate class names correctly", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); it("should handle nested tags with obfuscate class", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; const keyClass = "key"; // Act @@ -36,13 +36,13 @@ describe("obfuscateHtmlClassNames", () => { // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); it("should not obfuscate class names outside of obfuscate class scope", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a", ".bar": ".b" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a", "\\.bar": "\\.b" }; const keyClass = "key"; // Act @@ -56,41 +56,41 @@ describe("obfuscateHtmlClassNames", () => { it("should handle script tags", () => { // Arrange const html = ``; - const selectorConversion: SelectorConversion = { ".fol": ".a", ".foo": ".b" }; + const selectorConversion: SelectorConversion = { "\\.fol": "\\.a", "\\.foo": "\\.b" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion, obfuscateMarkerClass: "" }); // Assert expect(result.obfuscatedContent).toEqual(``); - expect(result.usedKeys).to.deep.equal([".fol", ".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.fol", "\\.foo"]); }); it("should handle void tags", () => { // Arrange const html = ``; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(``); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); it("should handle comments", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); it("should handle HTML without classes", () => { @@ -109,7 +109,7 @@ describe("obfuscateHtmlClassNames", () => { it("should handle empty HTML", () => { // Arrange const html = ""; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); @@ -122,33 +122,33 @@ describe("obfuscateHtmlClassNames", () => { it("should handle HTML with multiple classes in one element", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a", ".bar": ".b", ".baz": ".c" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a", "\\.bar": "\\.b", "\\.baz": "\\.c" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo", ".bar", ".baz"]); + expect(result.usedKeys).to.deep.equal(["\\.foo", "\\.bar", "\\.baz"]); }); it("should handle HTML with nested structures and multiple classes", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a", ".bar": ".b", ".baz": ".c" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a", "\\.bar": "\\.b", "\\.baz": "\\.c" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo", ".bar", ".baz"]); + expect(result.usedKeys).to.deep.equal(["\\.foo", "\\.bar", "\\.baz"]); }); it("should handle HTML with obfuscate marker class", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; const obfuscateMarkerClass = "key"; // Act @@ -156,13 +156,13 @@ describe("obfuscateHtmlClassNames", () => { // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); it("should handle HTML with multiple classes and obfuscate marker class", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a", ".bar": ".b", ".baz": ".c" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a", "\\.bar": "\\.b", "\\.baz": "\\.c" }; const obfuscateMarkerClass = "key"; // Act @@ -170,20 +170,20 @@ describe("obfuscateHtmlClassNames", () => { // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo", ".bar", ".baz"]); + expect(result.usedKeys).to.deep.equal(["\\.foo", "\\.bar", "\\.baz"]); }); it("should handle HTML instruction", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); /** @@ -192,13 +192,13 @@ describe("obfuscateHtmlClassNames", () => { it("should handle double quot inside double quot", () => { // Arrange const html = `
`; - const selectorConversion: SelectorConversion = { ".foo": ".a" }; + const selectorConversion: SelectorConversion = { "\\.foo": "\\.a" }; // Act const result = obfuscateHtmlClassNames({ html, selectorConversion }); // Assert expect(result.obfuscatedContent).toEqual(`
`); - expect(result.usedKeys).to.deep.equal([".foo"]); + expect(result.usedKeys).to.deep.equal(["\\.foo"]); }); }); diff --git a/src/config.ts b/src/config.ts index 698402c..251c929 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,4 @@ -import type { Options, OptionalOptions } from "./types"; +import type { OptionalOptions, Options } from "./types"; export const defaultOptions: Options = { enable: true, // Enable or disable the plugin. @@ -29,7 +29,8 @@ export const defaultOptions: Options = { * @deprecated Merged into `ignorePatterns.selectors` from v3.0.0 and will be removed in the next major version. */ classIgnore: [], // The class names to be ignored during obfuscation. - ignorePatterns: { // The patterns to be ignored during obfuscation. + ignorePatterns: { + // The patterns to be ignored during obfuscation. selectors: [], // The selectors to be ignored during obfuscation. idents: [], // The idents to be ignored during obfuscation. }, diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 1a0facf..6febdd9 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -16,7 +16,7 @@ import { } from "../utils"; -const obfuscateCss = async ({ +const obfuscateCss = ({ cssPath, removeOriginalCss, isFullObfuscation, diff --git a/src/handlers/js-ast.ts b/src/handlers/js-ast.ts index 8ab82d4..d0c1354 100644 --- a/src/handlers/js-ast.ts +++ b/src/handlers/js-ast.ts @@ -1,10 +1,10 @@ +import type { SelectorConversion } from "../types"; import * as parser from "@babel/parser"; -import traverse, { NodePath } from "@babel/traverse"; +import traverse, { type NodePath } from "@babel/traverse"; import * as t from "@babel/types"; import generator from "@babel/generator"; import { obfuscateKeys } from "../utils"; -import { type SelectorConversion } from "../types"; /** * Obfuscate the JavaScript code using AST(Abstract Syntax Tree) @@ -18,7 +18,7 @@ export const obfuscateJsWithAst = ( code: string, selectorConversion: SelectorConversion | undefined, startingKeys: string[] = [], - stripUnnecessarySpace: boolean = true + stripUnnecessarySpace = true ) => { const ast = parser.parse(code, { sourceType: "module", plugins: ["jsx"] }); const usedKeys: Set = new Set(); diff --git a/src/types.ts b/src/types.ts index f52c053..acdafcf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -47,7 +47,7 @@ export type Options = { enableJsAst: boolean; logLevel: LogLevel; -} +}; export type OptionalOptions = { enable?: boolean; @@ -74,7 +74,7 @@ export type OptionalOptions = { enableJsAst?: boolean; logLevel?: LogLevel; -} +}; export interface HtmlCharacterEntityConversion { [key: string]: string; diff --git a/src/utils.ts b/src/utils.ts index 1e699db..f61071d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -55,7 +55,7 @@ const issuer = "[next-css-obfuscator]"; let logLevel: LogLevel = "info"; const levels: LogLevel[] = ["debug", "info", "warn", "error", "success"]; -export const log = (type: LogLevel, task: string, data: any) => { +export const log = (type: LogLevel, task: string, data: unknown) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js if (levels.indexOf(type) < levels.indexOf(logLevel)) { return; @@ -202,7 +202,7 @@ export const replaceJsonKeysInFiles = ( ); if (fileContent !== obfuscateScriptContent) { fileContent = obfuscateScriptContent; - log("debug", `Obscured keys in JS like content file:`, normalizePath(filePath)); + log("debug", "Obscured keys in JS like content file:", normalizePath(filePath)); } } @@ -221,7 +221,7 @@ export const replaceJsonKeysInFiles = ( ); if (fileContent !== obfuscateScriptContent) { fileContent = obfuscateScriptContent; - log("debug", `Obscured keys in JSX related file:`, normalizePath(filePath)); + log("debug", "Obscured keys in JSX related file:", normalizePath(filePath)); } } else if ([".html"].includes(fileExt)) { //! NEW @@ -269,7 +269,7 @@ export const obfuscateKeys = ( selectorConversion: SelectorConversion, fileContent: string, contentIgnoreRegexes: RegExp[] = [], - useHtmlEntity: boolean = false + useHtmlEntity = false ) => { //ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js @@ -285,7 +285,7 @@ export const obfuscateKeys = ( let exactMatchRegex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`]|\\\\n|\\\\",|\\\\"})`, 'g'); // match exact wording & avoid ` ' "" // exactMatchRegex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`])`, 'g'); // match exact wording & avoid ` ' "" - const replacement = `$1` + selectorConversion[key].slice(1).replace(/\\/g, "").slice(1); + const replacement = `$1${selectorConversion[key].slice(1).replace(/\\/g, "").slice(1)}`; const matches = fileContent.match(exactMatchRegex); const originalObscuredContentPairs = matches?.map((match) => { @@ -358,7 +358,7 @@ export const normalizePath = (filePath: string) => { * @param direction - if "forward", the function will search the closest closeMarker after the startPosition, if "backward", the function will search the closest openMarker before the startPosition * @returns */ -export const findClosestSymbolPosition = (content: string, openMarker: string, closeMarker: string, startPosition: number = 0, direction: "forward" | "backward" = "backward") => { +export const findClosestSymbolPosition = (content: string, openMarker: string, closeMarker: string, startPosition = 0, direction: "forward" | "backward" = "backward") => { let level = 0; let currentPos = startPosition; From e33c10f9e4434a0dab54f9632b7094cf830379aa Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:14:29 +0100 Subject: [PATCH 14/28] refactor: Update string interpolation to use double quotes for consistency in tests and handlers --- src/__tests__/js-ast.test.ts | 85 ++++++++++++++++++------------------ src/__tests__/js.test.ts | 8 ++-- src/__tests__/utils.test.ts | 11 +---- src/handlers/css.ts | 3 +- src/handlers/js.ts | 7 ++- 5 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/__tests__/js-ast.test.ts b/src/__tests__/js-ast.test.ts index 4e5a0aa..a4470b9 100644 --- a/src/__tests__/js-ast.test.ts +++ b/src/__tests__/js-ast.test.ts @@ -1,21 +1,20 @@ import { describe, it, expect } from "vitest"; -import traverse, { NodePath } from "@babel/traverse"; -import * as t from "@babel/types"; +import traverse, { type NodePath } from "@babel/traverse"; +import type * as t from "@babel/types"; import * as parser from "@babel/parser"; import generator from "@babel/generator"; import { searchStringLiterals, obfuscateJsWithAst } from "../handlers/js-ast"; -function stripCode(code: string) { +const stripCode = (code: string) => { return code.replace(/\s/g, ""); } - //! ================================ //! searchStringLiterals //! ================================ describe("searchStringLiterals", () => { - function findStartPointNode(ast: t.File) { + const findStartPointNode = (ast: t.File) => { let startPointNode: NodePath | undefined; traverse(ast, { FunctionDeclaration(path) { @@ -25,7 +24,7 @@ describe("searchStringLiterals", () => { }, }); return startPointNode; - } + }; //? ******************************* //? Basic @@ -48,7 +47,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -77,7 +76,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -119,7 +118,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -147,7 +146,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -181,7 +180,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -212,7 +211,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -249,7 +248,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -288,7 +287,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -329,7 +328,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -366,7 +365,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -403,7 +402,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -448,7 +447,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -495,7 +494,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -532,7 +531,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -561,7 +560,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -588,7 +587,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -623,7 +622,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -658,7 +657,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -691,7 +690,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -730,7 +729,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -769,7 +768,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -812,7 +811,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -855,7 +854,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -886,7 +885,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -919,7 +918,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -950,7 +949,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -985,7 +984,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1020,7 +1019,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1059,7 +1058,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1112,7 +1111,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1155,7 +1154,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1192,7 +1191,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1227,7 +1226,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1270,7 +1269,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1319,7 +1318,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1348,7 +1347,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" @@ -1377,7 +1376,7 @@ describe("searchStringLiterals", () => { ` const ast = parser.parse(code); - let result: string[] = []; + const result: string[] = []; searchStringLiterals(findStartPointNode(ast)!, (str) => { result.push(str); return "{{found}}" diff --git a/src/__tests__/js.test.ts b/src/__tests__/js.test.ts index 2e0d6c7..ff7c455 100644 --- a/src/__tests__/js.test.ts +++ b/src/__tests__/js.test.ts @@ -22,7 +22,7 @@ describe("searchForwardComponent", () => { test("should return multiple component names for multiple matches", () => { // Arrange - const content = `o.jsx(FirstComponent, props); o.jsx(SecondComponent, otherProps);`; + const content = "o.jsx(FirstComponent, props); o.jsx(SecondComponent, otherProps);"; // Act const result = searchForwardComponent(content); @@ -66,7 +66,7 @@ describe("searchForwardComponent", () => { test("should handle special characters in component names", () => { // Arrange - const content = `o.jsx($Comp_1, props); o.jsx(_Comp$2, otherProps);`; + const content = "o.jsx($Comp_1, props); o.jsx(_Comp$2, otherProps);"; // Act const result = searchForwardComponent(content); @@ -88,7 +88,7 @@ describe("searchForwardComponent", () => { test("should return component names when they are followed by a brace", () => { // Arrange - const content = `o.jsx(ComponentName, {props: true});`; + const content = "o.jsx(ComponentName, {props: true});"; // Act const result = searchForwardComponent(content); @@ -114,7 +114,7 @@ describe("searchForwardComponent", () => { test("should handle content with nested jsx calls", () => { // Arrange - const content = `o.jsx(ParentComponent, {children: o.jsx(ChildComponent, {})})`; + const content = "o.jsx(ParentComponent, {children: o.jsx(ChildComponent, {})})"; // Act const result = searchForwardComponent(content); diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 77fbd65..9a43b75 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -12,7 +12,7 @@ import { describe("findContentBetweenMarker", () => { it("should return the correct content between markers", () => { - const content = `123{{4}5{67}8}901{2345678}9`; + const content = "123{{4}5{67}8}901{2345678}9"; const targetStr = '5'; const openSymbol = '{'; const closeSymbol = '}'; @@ -123,15 +123,6 @@ describe("getFilenameFromPath", () => { // Assert expect(result).toBe("my report.pdf"); }); - - test("should throw an error for non-string inputs", () => { - // Arrange - const input: any = null; - - // Act and Assert - expect(() => getFilenameFromPath(input)).toThrow(TypeError); - }); - }); //! ================================ diff --git a/src/handlers/css.ts b/src/handlers/css.ts index 6febdd9..915ef39 100644 --- a/src/handlers/css.ts +++ b/src/handlers/css.ts @@ -1,8 +1,9 @@ import type { obfuscateMode } from "../types"; +import type { ConversionTables, TransformProps } from "css-seasoning"; import path from "node:path"; import fs from "node:fs"; -import { initTransform, transform, type ConversionTables, type TransformProps } from "css-seasoning"; +import { initTransform, transform } from "css-seasoning"; import lightningcssInit, { transform as lightningcssTransform } from "lightningcss-wasm"; // TODO: html failed with . diff --git a/src/handlers/js.ts b/src/handlers/js.ts index 292f415..65d484e 100644 --- a/src/handlers/js.ts +++ b/src/handlers/js.ts @@ -1,3 +1,4 @@ +import type { SelectorConversion } from "../types"; import { log, findContentBetweenMarker, @@ -7,8 +8,6 @@ import { addKeysToRegistery, findClosestSymbolPosition } from "../utils"; - -import { SelectorConversion } from "../types"; import { obfuscateJsWithAst } from "./js-ast"; export const searchForwardComponent = (content: string) => { @@ -61,14 +60,14 @@ export const obfuscateForwardComponentJs = (searchContent: string, wholeContent: }); if (classNameBlocks.length !== obfuscatedClassNameBlocks.length) { - log("error", `Component obfuscation:`, `classNameBlocks.length !== obfuscatedClassNameBlocks.length`); + log("error", "Component obfuscation:", "classNameBlocks.length !== obfuscatedClassNameBlocks.length"); return componentContent; } let obscuredCode = componentContent.code; for (let i = 0; i < classNameBlocks.length; i++) { obscuredCode = replaceFirstMatch(obscuredCode, classNameBlocks[i], obfuscatedClassNameBlocks[i]); } - log("debug", `Obscured keys in component:`, componentContent.name); + log("debug", "Obscured keys in component:", componentContent.name); return { name: componentContent.name, code: obscuredCode From 38d4ac24265c4d18a5d7fcdf0c04d45993174426 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:22:09 +0100 Subject: [PATCH 15/28] chore: Remove version field from package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 5c1f2a4..56926fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,5 @@ { "name": "next-css-obfuscator", - "version": "3.0.0-b1", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From 8954a501276c51cb7ef99bde3a69f3236cf599b3 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:35:47 +0100 Subject: [PATCH 16/28] ci: Update semantic release configuration and dependencies --- .github/workflows/release.yml | 2 +- package-lock.json | 2 +- package.json | 4 ++-- release.config.cjs | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f251c5..6cfbfaa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,4 +29,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: npm run semantic-release + run: npx semantic-release diff --git a/package-lock.json b/package-lock.json index 90623f5..ccc26c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,6 @@ "packages": { "": { "name": "next-css-obfuscator", - "version": "3.0.0-b1", "license": "MIT", "dependencies": { "@babel/generator": "^7.23.6", @@ -25,6 +24,7 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^11.0.1", "@semantic-release/npm": "^12.0.1", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", diff --git a/package.json b/package.json index 56926fa..1a5a8c1 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "dev": "tsc -w", "pub": "npm run build && npm publish", "pub@beta": "npm run build && npm publish --tag beta", - "lint": "biome check .", - "semantic-release": "semantic-release" + "lint": "biome check ." }, "repository": { "type": "git", @@ -37,6 +36,7 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^11.0.1", "@semantic-release/npm": "^12.0.1", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", diff --git a/release.config.cjs b/release.config.cjs index 8ec50a2..ac68d26 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -18,5 +18,6 @@ module.exports = { assets: ["package.json", "CHANGELOG.md"], }, ], + "@semantic-release/github", ], }; From 3002e5c365f9a371389030dac0dfdebe49a0cde2 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:40:18 +0100 Subject: [PATCH 17/28] ci: Update Node.js setup in release workflow and change npm install to npm ci --- .github/workflows/release.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cfbfaa..087b834 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,8 +19,13 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + - name: Install dependencies - run: npm install + run: npm ci - name: Build NPM package run: npm run build From 0ec81314b5947119684efa2e8382e9c8f03520d1 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:51:27 +0100 Subject: [PATCH 18/28] ci: Update GitHub Actions workflows to use actions/checkout@v4 and npm install --- .github/workflows/auto_test.yml | 2 +- .github/workflows/release.yml | 7 +------ .releaserc | 0 package.json | 1 + 4 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 .releaserc diff --git a/.github/workflows/auto_test.yml b/.github/workflows/auto_test.yml index c39fa9b..38c6b2d 100644 --- a/.github/workflows/auto_test.yml +++ b/.github/workflows/auto_test.yml @@ -21,7 +21,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Install dependencie using the runners shell - name: Install dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 087b834..6cfbfaa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,13 +19,8 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: "lts/*" - - name: Install dependencies - run: npm ci + run: npm install - name: Build NPM package run: npm run build diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 1a5a8c1..556883a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "next-css-obfuscator", + "version": "3.0.0-b1", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From 935dde8d466abd9ea88a0b06f6a0d0bbb49e4759 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:23:52 +0100 Subject: [PATCH 19/28] ci: Update release workflow to handle push and pull request events, add dry run step --- .github/workflows/release.yml | 22 ++++++++++++++++------ .releaserc | 0 package-lock.json | 1 + release.config.cjs | 8 +------- 4 files changed, 18 insertions(+), 13 deletions(-) delete mode 100644 .releaserc diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cfbfaa..4caadfa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,16 +5,19 @@ on: branches: - main - beta - -permissions: - contents: write # to be able to publish a GitHub release - issues: write # to be able to comment on released issues - pull-requests: write # to be able to comment on released pull requests - id-token: write # to enable use of OIDC for npm provenance + pull_request: + branches: + - main + - beta jobs: release: runs-on: ubuntu-latest + permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance steps: - name: Checkout code uses: actions/checkout@v4 @@ -26,7 +29,14 @@ jobs: run: npm run build - name: Create Release + if: github.event_name == 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: npx semantic-release + + - name: Dry Run Release + if: github.event_name == 'pull_request' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx semantic-release --dry-run diff --git a/.releaserc b/.releaserc deleted file mode 100644 index e69de29..0000000 diff --git a/package-lock.json b/package-lock.json index ccc26c6..472ef8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "packages": { "": { "name": "next-css-obfuscator", + "version": "3.0.0-b1", "license": "MIT", "dependencies": { "@babel/generator": "^7.23.6", diff --git a/release.config.cjs b/release.config.cjs index ac68d26..0a39050 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -3,13 +3,7 @@ module.exports = { plugins: [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", - [ - "@semantic-release/npm", - { - npmPublish: true, - pkgRoot: "dist", - }, - ], + "@semantic-release/npm", [ "@semantic-release/git", { From 589a5d13dc2540e98ef659dd1bc7ef7cc0788773 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 25 Apr 2025 10:33:04 +0000 Subject: [PATCH 20/28] chore(release): 1.0.0-beta.1 [skip ci] # 1.0.0-beta.1 (2025-04-25) ### Bug Fixes * fix html tests ([f517839](https://github.com/soranoo/next-css-obfuscator/commit/f51783907915a9ca11394cd9e8437af069af46de)) * **html:** fix [#57](https://github.com/soranoo/next-css-obfuscator/issues/57) ([a638538](https://github.com/soranoo/next-css-obfuscator/commit/a6385382a43ce497fb233f7b79d6f154fb513cc7)) * **html:** fix incorrect html class name truncation ([7cb985d](https://github.com/soranoo/next-css-obfuscator/commit/7cb985d4c424a4458e2a72db9e76da899c44da63)) * **js-ast:** added support to `MemberExpression` [#45](https://github.com/soranoo/next-css-obfuscator/issues/45) ([8c95ba0](https://github.com/soranoo/next-css-obfuscator/commit/8c95ba07d62608ca77eeb02db78dd4a5afe10a8c)) * **js-ast:** added support to `TemplateLiteral` & `TemplateElement` [#45](https://github.com/soranoo/next-css-obfuscator/issues/45) ([0dd46b3](https://github.com/soranoo/next-css-obfuscator/commit/0dd46b377cca59e59514e3a78b1e6f3b9b92b651)) ### Features * Enables semantic release for automated publishing ([b43a194](https://github.com/soranoo/next-css-obfuscator/commit/b43a19477962fe85e7bf26b890624998648be1ba)) * Upgrades to v3 with new CSS transformation ([0afd780](https://github.com/soranoo/next-css-obfuscator/commit/0afd7808b2c6405b5fbedb4b8ff0e34f813ccd82)) * v3 migration with TailwindCSS 4 support ([668a5f6](https://github.com/soranoo/next-css-obfuscator/commit/668a5f66abdd174bf8ecbd18e9872a9719c73508)) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 556883a..f344c9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-css-obfuscator", - "version": "3.0.0-b1", + "version": "1.0.0-beta.1", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From 502270a5c4f5165e5adadd63604f33e46b11edb6 Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:54:15 +0100 Subject: [PATCH 21/28] ci: upgrade version BREAKING CHANGE --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4729f1d..d7474d1 100644 --- a/README.md +++ b/README.md @@ -545,7 +545,7 @@ Thank you to all the sponsors who support this project. ## 🤝 Contributing -Contributions are welcome! If you find a bug or have a feature request, please open an issue. If you want to contribute code, please fork the repository and run `npm run test` before submit a pull request. +Contributions are welcome! If you find a bug or have a feature request, please open an issue. If you want to contribute code, please fork the repository and run `npm run test` before submit a pull request. We are following the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification for commit messages. ## 🏛️ Commercial Usage diff --git a/package.json b/package.json index f344c9f..24b8a83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-css-obfuscator", - "version": "1.0.0-beta.1", + "version": "2.0.0-beta.1", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From c388e4bac6dbe5e5a801bb9a92e88021afb1831d Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:57:27 +0100 Subject: [PATCH 22/28] BREAKING CHANGE: upgrade semantic-release release version to v2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24b8a83..3d3bdab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-css-obfuscator", - "version": "2.0.0-beta.1", + "version": "2.0.0", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From 7466b77865d5bfd774d504e03b2ebfc08f6ffd6d Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:00:47 +0100 Subject: [PATCH 23/28] feat: upgrade semantic-release release version to v2 BREAKING CHANGE --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d7474d1..e35eee4 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Visit the [GitHub Page](https://github.com/soranoo/next-css-obfuscator/) for bet --- +. ### 🎉 Version 3 has NOW been released 🎉 (💥 Breaking Changes) From d454f6bd13cc6c9d51dffbe1ad7c9e932ed734de Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 25 Apr 2025 11:02:54 +0000 Subject: [PATCH 24/28] chore(release): 1.0.0-beta.2 [skip ci] # [1.0.0-beta.2](https://github.com/soranoo/next-css-obfuscator/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2025-04-25) ### Features * upgrade semantic-release release version to v2 ([7466b77](https://github.com/soranoo/next-css-obfuscator/commit/7466b77865d5bfd774d504e03b2ebfc08f6ffd6d)) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d3bdab..089d4cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-css-obfuscator", - "version": "2.0.0", + "version": "1.0.0-beta.2", "description": "A package deeply inspired by PostCSS-Obfuscator but for Next.js.", "main": "dist/index.js", "type": "commonjs", From 469b3d5f48586171097f57fb57856ca9210be8af Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:04:33 +0100 Subject: [PATCH 25/28] BREAKING CHANGE: upgrade semantic-release release version to v2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e35eee4..5cebf67 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Visit the [GitHub Page](https://github.com/soranoo/next-css-obfuscator/) for bet --- -. +.. ### 🎉 Version 3 has NOW been released 🎉 (💥 Breaking Changes) From 73b5a60430ee86a4a53611d8da68a3c7100f047c Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:07:10 +0100 Subject: [PATCH 26/28] !feat: upgrade semantic-release release version to v2 --- README.md | 1 - src/config.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cebf67..d7474d1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ Visit the [GitHub Page](https://github.com/soranoo/next-css-obfuscator/) for bet --- -.. ### 🎉 Version 3 has NOW been released 🎉 (💥 Breaking Changes) diff --git a/src/config.ts b/src/config.ts index 251c929..c11bd2d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,3 +76,4 @@ export class Config { } export default Config; +console.log("Config loaded"); \ No newline at end of file From 9f1c52ce36762e00101b4938d8b67a70211e547d Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:09:33 +0100 Subject: [PATCH 27/28] !feat: update release version --- src/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index c11bd2d..251c929 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,4 +76,3 @@ export class Config { } export default Config; -console.log("Config loaded"); \ No newline at end of file From 6b1c3881628495204c100996f07dfa6ada65c8cf Mon Sep 17 00:00:00 2001 From: Freeman <46896789+soranoo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:13:11 +0100 Subject: [PATCH 28/28] feat!: update release version --- src/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.ts b/src/config.ts index 251c929..465d2da 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,3 +76,4 @@ export class Config { } export default Config; +