From 67f1ff5c8f35d51425d3494c8e439b0050db9aec Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 29 Jan 2026 23:04:52 -0500 Subject: [PATCH 1/6] fix: fix ESM build and types Fixes #1317 --- package.json | 4 ++-- rollup.config.mjs | 42 ++++++++++++++++++++++++------------------ scripts/fix-esm.sh | 13 +++++++++++++ 3 files changed, 39 insertions(+), 20 deletions(-) create mode 100755 scripts/fix-esm.sh diff --git a/package.json b/package.json index feed2c30..83877f6e 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ "scripts": { "build": "run-s build:*", "build:cjs": "tsc", - "build:esm": "rollup --config --failAfterWarnings --environment ESM:true", + "build:esm": "rollup --config --failAfterWarnings --environment ESM:true && scripts/fix-esm.sh", "build:umd": "rollup --config --failAfterWarnings --environment UMD:true", - "clean": "rm -rf .nyc_output coverage dist lib esm", + "clean": "rm -rf .nyc_output coverage dist esm lib", "lint": "eslint .", "lint:fix": "npm run lint -- --fix", "lint:package": "publint", diff --git a/rollup.config.mjs b/rollup.config.mjs index 9bd630ea..4eff19ff 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -20,10 +20,8 @@ const getPlugins = ({ browser = false, minify = false, outDir }) => ], }), typescript({ - declaration: false, - declarationMap: false, - module: 'esnext', compilerOptions: { + module: 'esnext', outDir, }, }), @@ -42,41 +40,49 @@ const getUMDConfig = (minify = false) => { name: 'HTMLDOMParser', sourcemap: true, }, - plugins: getPlugins({ browser: true, minify, outDir: 'dist' }), + plugins: getPlugins({ + browser: true, + minify, + outDir: 'dist', + }), }; }; const esmConfigs = [ + // ESM server { input: 'src/index.ts', output: { - file: 'esm/index.mjs', + dir: 'esm', + entryFileNames: '[name].mjs', format: 'es', + preserveModules: true, + preserveModulesRoot: 'src', sourcemap: true, }, - plugins: getPlugins({ browser: false, minify: false, outDir: 'esm' }), + plugins: getPlugins({ + browser: false, + minify: false, + outDir: 'esm', + }), }, - // Client build: use preserveModules for proper module structure + + // ESM client { input: 'src/client/html-to-dom.ts', output: { dir: 'esm/client', - format: 'es', entryFileNames: '[name].mjs', + format: 'es', preserveModules: true, preserveModulesRoot: 'src/client', sourcemap: true, }, - plugins: getPlugins({ browser: true, minify: false, outDir: 'esm/client' }), - }, - { - input: 'src/server/html-to-dom.ts', - output: { - file: 'esm/server/html-to-dom.mjs', - format: 'es', - sourcemap: true, - }, - plugins: getPlugins({ browser: false, minify: false, outDir: 'esm' }), + plugins: getPlugins({ + browser: true, + minify: false, + outDir: 'esm/client', + }), }, ]; diff --git a/scripts/fix-esm.sh b/scripts/fix-esm.sh new file mode 100755 index 00000000..50fad9c5 --- /dev/null +++ b/scripts/fix-esm.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# replace `.d.ts` -> `.d.mts` +find esm -type f -exec perl -i -pe 's/\.d\.ts/\.d\.mts/g' {} + + +# rename `.d.ts` -> `.d.mts` +find esm -name '*.d.ts' -exec bash -c 'mv "$1" "${1%.d.ts}.d.mts"' _ {} \; + +# rename `.d.ts.map` -> `.d.mts.map` +find esm -name '*.d.ts.map' -exec bash -c 'mv "$1" "${1%.d.ts.map}.d.mts.map"' _ {} \; + +# delete extraneous files +rm -rf esm/client/{client,server,index.*,types.*} From 4316c2ad036cbe24c498778ea2ad9dbf088cf82e Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 30 Jan 2026 00:49:57 -0500 Subject: [PATCH 2/6] refactor(eslint): update eslint.config.mjs and fix lint issues --- eslint.config.mjs | 46 ++--- package-lock.json | 418 +++++++++++++++++++++++++++++++++++++- package.json | 15 +- src/client/constants.ts | 15 +- src/client/domparser.ts | 14 +- src/client/html-to-dom.ts | 2 +- tsconfig.test.json | 7 + 7 files changed, 472 insertions(+), 45 deletions(-) create mode 100644 tsconfig.test.json diff --git a/eslint.config.mjs b/eslint.config.mjs index bc3515de..4ff2e05c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,47 +1,47 @@ -import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { includeIgnoreFile } from '@eslint/compat'; -import { FlatCompat } from '@eslint/eslintrc'; -import js from '@eslint/js'; -import typescriptEslint from '@typescript-eslint/eslint-plugin'; -import tsParser from '@typescript-eslint/parser'; +import eslint from '@eslint/js'; +import { defineConfig } from 'eslint/config'; import prettier from 'eslint-plugin-prettier'; import simpleImportSort from 'eslint-plugin-simple-import-sort'; +import tsdoc from 'eslint-plugin-tsdoc'; import globals from 'globals'; +import tseslint from 'typescript-eslint'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const gitignorePath = path.resolve(__dirname, '.gitignore'); +const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)); -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, -}); - -export default [ +export default defineConfig([ includeIgnoreFile(gitignorePath), - ...compat.extends( - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - ), - { + files: ['**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}'], + plugins: { - '@typescript-eslint': typescriptEslint, 'simple-import-sort': simpleImportSort, + eslint, prettier, + tsdoc, }, + extends: [ + eslint.configs.recommended, + tseslint.configs.recommended, + tseslint.configs.recommendedTypeChecked, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, + ], + languageOptions: { globals: { ...globals.browser, ...globals.mocha, ...globals.node, }, - parser: tsParser, + parserOptions: { + project: ['tsconfig.json', 'tsconfig.test.json'], + tsconfigRootDir: import.meta.dirname, + }, }, rules: { @@ -62,4 +62,4 @@ export default [ '@typescript-eslint/no-require-imports': 'off', }, }, -]; +]); diff --git a/package-lock.json b/package-lock.json index a6361b4a..c07ec079 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,12 @@ "": { "name": "html-dom-parser", "version": "5.1.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/remarkablemark" + } + ], "license": "MIT", "dependencies": { "domhandler": "5.0.3", @@ -16,7 +22,6 @@ "@commitlint/cli": "20.3.1", "@commitlint/config-conventional": "20.3.1", "@eslint/compat": "2.0.1", - "@eslint/eslintrc": "3.3.3", "@eslint/js": "9.39.2", "@rollup/plugin-alias": "6.0.0", "@rollup/plugin-commonjs": "29.0.0", @@ -28,12 +33,11 @@ "@types/estree": "1.0.8", "@types/mocha": "10.0.10", "@types/node": "25.1.0", - "@typescript-eslint/eslint-plugin": "8.54.0", - "@typescript-eslint/parser": "8.54.0", "chai": "4.5.0", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", "eslint-plugin-simple-import-sort": "12.1.1", + "eslint-plugin-tsdoc": "0.5.0", "globals": "17.2.0", "html-minifier": "4.0.0", "husky": "9.1.7", @@ -53,7 +57,8 @@ "rollup": "4.57.0", "size-limit": "12.0.0", "ts-node": "10.9.2", - "typescript": "5.9.3" + "typescript": "5.9.3", + "typescript-eslint": "8.54.0" } }, "node_modules/@ampproject/remapping": { @@ -1187,6 +1192,81 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.0.tgz", + "integrity": "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -4619,6 +4699,199 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.5.0.tgz", + "integrity": "sha512-ush8ehCwub2rgE16OIgQPFyj/o0k3T8kL++9IrAI4knsmupNo8gvfO2ERgDHWWgTC5MglbwLVRswU93HyXqNpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "@microsoft/tsdoc-config": "0.18.0", + "@typescript-eslint/utils": "~8.46.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/project-service": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.4.tgz", + "integrity": "sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.4", + "@typescript-eslint/types": "^8.46.4", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz", + "integrity": "sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz", + "integrity": "sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/types": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.4.tgz", + "integrity": "sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz", + "integrity": "sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.4", + "@typescript-eslint/tsconfig-utils": "8.46.4", + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/utils": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.4.tgz", + "integrity": "sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.4", + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/typescript-estree": "8.46.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz", + "integrity": "sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.4", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-tsdoc/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -5063,6 +5336,36 @@ "dev": true, "license": "MIT" }, + "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, + "license": "MIT", + "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/fast-glob/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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5083,6 +5386,16 @@ "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", "dev": true }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -6415,6 +6728,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7357,6 +7677,16 @@ "dev": true, "license": "MIT" }, + "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, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -8963,6 +9293,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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" + } + ], + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -9204,6 +9555,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -9273,6 +9635,30 @@ "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -10449,6 +10835,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/ua-parser-js": { "version": "0.7.39", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", diff --git a/package.json b/package.json index 83877f6e..4159e60a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,13 @@ "name": "html-dom-parser", "version": "5.1.5", "description": "HTML to DOM parser.", - "author": "Mark ", + "author": "Mark (https://remarkabl.org)", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/remarkablemark" + } + ], "main": "./lib/index.js", "module": "./esm/index.mjs", "exports": { @@ -69,7 +75,6 @@ "@commitlint/cli": "20.3.1", "@commitlint/config-conventional": "20.3.1", "@eslint/compat": "2.0.1", - "@eslint/eslintrc": "3.3.3", "@eslint/js": "9.39.2", "@rollup/plugin-alias": "6.0.0", "@rollup/plugin-commonjs": "29.0.0", @@ -81,12 +86,11 @@ "@types/estree": "1.0.8", "@types/mocha": "10.0.10", "@types/node": "25.1.0", - "@typescript-eslint/eslint-plugin": "8.54.0", - "@typescript-eslint/parser": "8.54.0", "chai": "4.5.0", "eslint": "9.39.2", "eslint-plugin-prettier": "5.5.5", "eslint-plugin-simple-import-sort": "12.1.1", + "eslint-plugin-tsdoc": "0.5.0", "globals": "17.2.0", "html-minifier": "4.0.0", "husky": "9.1.7", @@ -106,7 +110,8 @@ "rollup": "4.57.0", "size-limit": "12.0.0", "ts-node": "10.9.2", - "typescript": "5.9.3" + "typescript": "5.9.3", + "typescript-eslint": "8.54.0" }, "files": [ "/dist", diff --git a/src/client/constants.ts b/src/client/constants.ts index da5809a8..7d457dfa 100644 --- a/src/client/constants.ts +++ b/src/client/constants.ts @@ -37,17 +37,16 @@ export const CASE_SENSITIVE_TAG_NAMES = [ 'textPath', ] as const; -export const CASE_SENSITIVE_TAG_NAMES_MAP = CASE_SENSITIVE_TAG_NAMES.reduce( - (accumulator, tagName) => { - accumulator[tagName.toLowerCase()] = tagName; - return accumulator; - }, - {} as Record, -); +export const CASE_SENSITIVE_TAG_NAMES_MAP = CASE_SENSITIVE_TAG_NAMES.reduce< + Record +>((accumulator, tagName) => { + accumulator[tagName.toLowerCase()] = tagName; + return accumulator; +}, {}); export const CARRIAGE_RETURN = '\r'; export const CARRIAGE_RETURN_REGEX = new RegExp(CARRIAGE_RETURN, 'g'); -export const CARRIAGE_RETURN_PLACEHOLDER = `__HTML_DOM_PARSER_CARRIAGE_RETURN_PLACEHOLDER_${Date.now()}__`; +export const CARRIAGE_RETURN_PLACEHOLDER = `__HTML_DOM_PARSER_CARRIAGE_RETURN_PLACEHOLDER_${Date.now().toString()}__`; export const CARRIAGE_RETURN_PLACEHOLDER_REGEX = new RegExp( CARRIAGE_RETURN_PLACEHOLDER, 'g', diff --git a/src/client/domparser.ts b/src/client/domparser.ts index 98513351..310a94da 100644 --- a/src/client/domparser.ts +++ b/src/client/domparser.ts @@ -62,6 +62,7 @@ if (typeof DOMParser === 'function') { * * @see https://developer.mozilla.org/docs/Web/API/DOMImplementation/createHTMLDocument */ +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (typeof document === 'object' && document.implementation) { const htmlDocument = document.implementation.createHTMLDocument(); @@ -98,6 +99,7 @@ const template = let parseFromTemplate: (html: string) => NodeList; +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (template && template.content) { /** * Uses a template element (content fragment) to parse HTML. @@ -111,6 +113,8 @@ if (template && template.content) { }; } +const createNodeList = () => document.createDocumentFragment().childNodes; + /** * Parses HTML string to DOM nodes. * @@ -121,8 +125,8 @@ export default function domparser(html: string): NodeList { // Escape special characters before parsing html = escapeSpecialCharacters(html); - const match = html.match(FIRST_TAG_REGEX); - const firstTagName = match && match[1] ? match[1].toLowerCase() : ''; + const match = FIRST_TAG_REGEX.exec(html); + const firstTagName = match?.[1]?.toLowerCase(); switch (firstTagName) { case HTML: { @@ -149,7 +153,7 @@ export default function domparser(html: string): NodeList { // if there's a sibling element, then return both elements if (BODY_TAG_REGEX.test(html) && HEAD_TAG_REGEX.test(html)) { - return elements[0].parentNode!.childNodes; + return elements[0].parentNode?.childNodes ?? createNodeList(); } return elements; @@ -157,11 +161,13 @@ export default function domparser(html: string): NodeList { // low-level tag or text default: { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (parseFromTemplate) { return parseFromTemplate(html); } + const element = parseFromDocument(html, BODY).querySelector(BODY); - return element!.childNodes; + return element?.childNodes ?? createNodeList(); } } } diff --git a/src/client/html-to-dom.ts b/src/client/html-to-dom.ts index 3aeb4fb9..4eb5583d 100644 --- a/src/client/html-to-dom.ts +++ b/src/client/html-to-dom.ts @@ -19,7 +19,7 @@ export default function HTMLDOMParser(html: string) { } // match directive - const match = html.match(DIRECTIVE_REGEX); + const match = DIRECTIVE_REGEX.exec(html); const directive = match ? match[1] : undefined; return formatDOM(domparser(html), null, directive); diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..83570b28 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "allowJs": true + }, + "include": ["eslint.config.mjs", "test"] +} From a303c82c0b88dc009ed23e41b647671c441ce347 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 30 Jan 2026 01:42:37 -0500 Subject: [PATCH 3/6] refactor: fix lint and type errors --- .github/workflows/lint.yml | 3 +++ eslint.config.mjs | 2 +- karma.conf.js | 2 ++ package.json | 2 +- rollup.config.mjs | 3 ++- src/client/utilities.ts | 9 +++++---- test/cases/index.js | 8 ++++++-- test/client/index.js | 2 ++ test/helpers/cycle.js | 4 +++- test/helpers/run-tests.js | 10 ++++++---- test/helpers/test-case-sensitive-tags.js | 3 ++- test/helpers/throw-errors.js | 5 +++-- test/server/server.test.ts | 18 ++++++++++++------ test/types/jsdomify.d.ts | 10 ++++++++++ tsconfig.build.json | 14 ++++++++++++++ tsconfig.json | 17 +++++------------ tsconfig.test.json | 10 ++++++++-- 17 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 test/types/jsdomify.d.ts create mode 100644 tsconfig.build.json diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0a47d3e5..ceef5196 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,6 +20,9 @@ jobs: - name: Install dependencies run: npm ci --prefer-offline + - name: Build package + run: npm run build + - name: Run ESLint run: npm run lint diff --git a/eslint.config.mjs b/eslint.config.mjs index 4ff2e05c..ec253767 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -39,7 +39,7 @@ export default defineConfig([ ...globals.node, }, parserOptions: { - project: ['tsconfig.json', 'tsconfig.test.json'], + project: ['tsconfig.build.json', 'tsconfig.test.json'], tsconfigRootDir: import.meta.dirname, }, }, diff --git a/karma.conf.js b/karma.conf.js index 99881f90..eda1de58 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,5 +1,7 @@ /** * @see https://karma-runner.github.io/6.4/config/configuration-file.html + * + * @param {{LOG_INFO: string; set: () => void}} config */ module.exports = (config) => { config.set({ diff --git a/package.json b/package.json index 4159e60a..6d5aece4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "scripts": { "build": "run-s build:*", - "build:cjs": "tsc", + "build:cjs": "tsc --project tsconfig.build.json", "build:esm": "rollup --config --failAfterWarnings --environment ESM:true && scripts/fix-esm.sh", "build:umd": "rollup --config --failAfterWarnings --environment UMD:true", "clean": "rm -rf .nyc_output coverage dist esm lib", diff --git a/rollup.config.mjs b/rollup.config.mjs index 4eff19ff..eb92d973 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -8,7 +8,7 @@ import typescript from '@rollup/plugin-typescript'; const require = createRequire(import.meta.url); -const getPlugins = ({ browser = false, minify = false, outDir }) => +const getPlugins = ({ browser = false, minify = false, outDir = '' }) => [ browser && alias({ @@ -20,6 +20,7 @@ const getPlugins = ({ browser = false, minify = false, outDir }) => ], }), typescript({ + tsconfig: 'tsconfig.build.json', compilerOptions: { module: 'esnext', outDir, diff --git a/src/client/utilities.ts b/src/client/utilities.ts index 7b51b7b0..ea08270f 100644 --- a/src/client/utilities.ts +++ b/src/client/utilities.ts @@ -121,11 +121,11 @@ export function formatDOM( } case 3: - current = new Text(revertEscapedCharacters(node.nodeValue!)); + current = new Text(revertEscapedCharacters(node.nodeValue ?? '')); break; case 8: - current = new Comment(node.nodeValue!); + current = new Comment(node.nodeValue ?? ''); break; default: @@ -133,7 +133,8 @@ export function formatDOM( } // set previous node next - const prev = domNodes[index - 1] || null; + const prev = domNodes[index - 1] ?? null; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (prev) { prev.next = current; } @@ -152,7 +153,7 @@ export function formatDOM( directive, ); - current.next = domNodes[0] || null; + current.next = domNodes[0] ?? null; current.parent = parent as Element; domNodes.unshift(current); diff --git a/test/cases/index.js b/test/cases/index.js index 916b88d8..f624f0cf 100644 --- a/test/cases/index.js +++ b/test/cases/index.js @@ -1,6 +1,9 @@ -const fs = require('fs'); -const path = require('path'); +const fs = require('node:fs'); +const path = require('node:path'); + +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { minify } = require('html-minifier'); + const htmlCases = require('./html'); /** @@ -17,6 +20,7 @@ const html = [ ...htmlCases, { name: 'complex html', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call data: minify(read('./complex.html'), { collapseWhitespace: true, }), diff --git a/test/client/index.js b/test/client/index.js index 4b27836c..3c5b4f7a 100644 --- a/test/client/index.js +++ b/test/client/index.js @@ -1,3 +1,5 @@ +/* eslint-disable */ + const htmlCases = require('../cases/html'); const serverParser = require('../../dist/htmlparser2').parseDOM; const clientParser = require('../../dist/html-dom-parser'); diff --git a/test/helpers/cycle.js b/test/helpers/cycle.js index e98ab4c8..8f1d963a 100644 --- a/test/helpers/cycle.js +++ b/test/helpers/cycle.js @@ -1,3 +1,5 @@ +/* eslint-disable */ + /** * @see {@link https://github.com/douglascrockford/JSON-js/blob/master/cycle.js} */ @@ -142,7 +144,7 @@ if (typeof JSON.retrocycle !== 'function') { // produces an array containing a single element which is the array itself. var px = - /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/; // eslint-disable-line no-control-regex + /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/; (function rez(value) { // The rez function walks recursively through the object looking for $ref diff --git a/test/helpers/run-tests.js b/test/helpers/run-tests.js index 19288e51..4733feec 100644 --- a/test/helpers/run-tests.js +++ b/test/helpers/run-tests.js @@ -6,10 +6,10 @@ const isKarma = /** * Runs tests. * - * @param {Function} assert - Assert. - * @param {Object} testCases - Test cases. - * @param {Function} actualParser - Actual parser. - * @param {Function} expectedParser - Expected parser. + * @param {{deepEqual: () => void}} assert + * @param {Record[]} testCases + * @param {() => object} actualParser + * @param {() => object} expectedParser */ module.exports = function runTests( assert, @@ -27,7 +27,9 @@ module.exports = function runTests( // use `JSON.decycle` since `assert.deepEqual` fails // when instance types are different in the browser if (isKarma) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment actualOutput = JSON.decycle(actualOutput); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment expectedOutput = JSON.decycle(expectedOutput); } diff --git a/test/helpers/test-case-sensitive-tags.js b/test/helpers/test-case-sensitive-tags.js index 356df441..f9fc5879 100644 --- a/test/helpers/test-case-sensitive-tags.js +++ b/test/helpers/test-case-sensitive-tags.js @@ -3,7 +3,8 @@ const constants = require('../../lib/client/constants'); /** * Tests case-sensitive tags (SVG) to make sure their case is preserved. * - * @param {Function} parser - The parser. + * @param {{equal: () => void}} assert + * @param {() => object[]} parser */ module.exports = function testCaseSensitiveTags(assert, parser) { it('preserves case of case-sensitive SVG tags', () => { diff --git a/test/helpers/throw-errors.js b/test/helpers/throw-errors.js index 5ace9b82..b33ed2d9 100644 --- a/test/helpers/throw-errors.js +++ b/test/helpers/throw-errors.js @@ -7,6 +7,7 @@ const values = [ false, {}, [], + // eslint-disable-next-line @typescript-eslint/no-empty-function () => {}, new Date(), ]; @@ -14,8 +15,8 @@ const values = [ /** * Calls parser with invalid arguments. * - * @param {Function} assert - Assert. - * @param {Function} expectedParser - Expected parser. + * @param {{throws: () => void}} assert + * @param {() => object} expectedParser */ module.exports = function throwErrors(assert, expectedParser) { values.forEach((value) => { diff --git a/test/server/server.test.ts b/test/server/server.test.ts index 8a6fc1fa..acc1e236 100644 --- a/test/server/server.test.ts +++ b/test/server/server.test.ts @@ -1,16 +1,19 @@ import { assert } from 'chai'; import * as htmlparser from 'htmlparser2'; -// @ts-ignore import jsdomify from 'jsdomify'; import serverParser from '../../src'; import cases from '../cases'; import { runTests, testCaseSensitiveTags, throwErrors } from '../helpers'; +const parseDOM = (data: string, options: htmlparser.Options) => + htmlparser.parseDocument(data, options).children; + describe('server parser', () => { throwErrors(assert, serverParser); - runTests(assert, serverParser, htmlparser.parseDOM, cases.html); - runTests(assert, serverParser, htmlparser.parseDOM, cases.svg); + + runTests(assert, serverParser, parseDOM, cases.html); + runTests(assert, serverParser, parseDOM, cases.svg); // TODO: case-sensitive (SVG) tags are not preserved in server parser // testCaseSensitiveTags(assert, serverParser); @@ -18,11 +21,14 @@ describe('server parser', () => { describe('client parser in jsdom', () => { jsdomify.create(); - const clientParser = require('../../src/client/html-to-dom').default; + + const clientParser = + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + require('../../src/client/html-to-dom').default as unknown; throwErrors(assert, clientParser); - runTests(assert, clientParser, htmlparser.parseDOM, cases.html); - runTests(assert, clientParser, htmlparser.parseDOM, cases.svg); + runTests(assert, clientParser, parseDOM, cases.html); + runTests(assert, clientParser, parseDOM, cases.svg); testCaseSensitiveTags(assert, clientParser); after(() => { diff --git a/test/types/jsdomify.d.ts b/test/types/jsdomify.d.ts new file mode 100644 index 00000000..b5d6d718 --- /dev/null +++ b/test/types/jsdomify.d.ts @@ -0,0 +1,10 @@ +declare module 'jsdomify' { + interface JsdomifyOptions { + html?: string; + url?: string; + } + + export function create(options?: JsdomifyOptions): void; + export function destroy(): void; + export const jsdom: unknown; +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..86c49afd --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "lib": ["es5", "dom"], + "esModuleInterop": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "outDir": "lib" + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json index 86c49afd..ef8d8654 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,7 @@ { - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "lib": ["es5", "dom"], - "esModuleInterop": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "strict": true, - "outDir": "lib" - }, - "include": ["src"] + "files": [], + "references": [ + { "path": "./tsconfig.build.json" }, + { "path": "./tsconfig.test.json" } + ] } diff --git a/tsconfig.test.json b/tsconfig.test.json index 83570b28..c14628de 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,7 +1,13 @@ { - "extends": "./tsconfig.json", + "extends": "./tsconfig.build.json", "compilerOptions": { "allowJs": true }, - "include": ["eslint.config.mjs", "test"] + "include": [ + "src", + "test", + "eslint.config.mjs", + "karma.conf.js", + "rollup.config.mjs" + ] } From f89d491e795698c9ba4b6bb5bb94dec411c017de Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 30 Jan 2026 01:59:34 -0500 Subject: [PATCH 4/6] test(client): ignore lines from test coverage --- .github/workflows/test.yml | 6 ++---- package.json | 1 + src/client/domparser.ts | 10 +++++++++- src/client/utilities.ts | 2 ++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 32751da4..98c30a91 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,12 +21,10 @@ jobs: run: npm ci --prefer-offline - name: Run server test - run: npm run test:server + run: npm run test:coverage - name: Generate coverage report - run: | - mkdir -p coverage - npx nyc report --reporter=text-lcov > coverage/lcov.info + run: npx nyc report --reporter=text-lcov > coverage/lcov.info - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 diff --git a/package.json b/package.json index 6d5aece4..0335d623 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "test:client": "npm run test:client:watch -- --single-run", "test:client:build": "NODE_ENV=test npm run build", "test:client:watch": "npm run test:client:build && karma start", + "test:coverage": "npm run test:server && nyc report --reporter=html", "test:esm": "npm run build && node --test test/esm", "test:server": "npm run build:cjs && nyc mocha" }, diff --git a/src/client/domparser.ts b/src/client/domparser.ts index 310a94da..f951d98f 100644 --- a/src/client/domparser.ts +++ b/src/client/domparser.ts @@ -46,8 +46,8 @@ if (typeof DOMParser === 'function') { * @returns - Document. */ parseFromString = (html: string, tagName?: string): Document => { + /* istanbul ignore if */ if (tagName) { - /* istanbul ignore next */ html = `<${tagName}>${html}`; } @@ -74,6 +74,7 @@ if (typeof document === 'object' && document.implementation) { * @returns - Document */ parseFromDocument = function (html: string, tagName?: string): Document { + /* istanbul ignore if */ if (tagName) { const element = htmlDocument.documentElement.querySelector(tagName); @@ -113,6 +114,7 @@ if (template && template.content) { }; } +/* istanbul ignore next */ const createNodeList = () => document.createDocumentFragment().childNodes; /** @@ -136,11 +138,13 @@ export default function domparser(html: string): NodeList { // so make sure to remove them if they don't actually exist if (!HEAD_TAG_REGEX.test(html)) { const element = doc.querySelector(HEAD); + /* istanbul ignore next */ element?.parentNode?.removeChild(element); } if (!BODY_TAG_REGEX.test(html)) { const element = doc.querySelector(BODY); + /* istanbul ignore next */ element?.parentNode?.removeChild(element); } @@ -153,6 +157,7 @@ export default function domparser(html: string): NodeList { // if there's a sibling element, then return both elements if (BODY_TAG_REGEX.test(html) && HEAD_TAG_REGEX.test(html)) { + /* istanbul ignore next */ return elements[0].parentNode?.childNodes ?? createNodeList(); } @@ -166,7 +171,10 @@ export default function domparser(html: string): NodeList { return parseFromTemplate(html); } + /* istanbul ignore next */ const element = parseFromDocument(html, BODY).querySelector(BODY); + + /* istanbul ignore next */ return element?.childNodes ?? createNodeList(); } } diff --git a/src/client/utilities.ts b/src/client/utilities.ts index ea08270f..f2655a4e 100644 --- a/src/client/utilities.ts +++ b/src/client/utilities.ts @@ -121,10 +121,12 @@ export function formatDOM( } case 3: + /* istanbul ignore next */ current = new Text(revertEscapedCharacters(node.nodeValue ?? '')); break; case 8: + /* istanbul ignore next */ current = new Comment(node.nodeValue ?? ''); break; From e98355dc295001e740c8d88a49268ff928b5ba90 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 30 Jan 2026 17:55:25 -0500 Subject: [PATCH 5/6] fix: correct internal resolution resolution of esm types Fixes #1317 https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md --- package-lock.json | 822 +++++++++++++++++++++++++++++++---- package.json | 16 +- rollup.config.mjs | 46 +- scripts/add-mjs-extension.ts | 116 +++++ scripts/build.sh | 18 + scripts/fix-esm.sh | 13 - test/types/index.test.mts | 16 + test/types/index.test.ts | 4 +- tsconfig.test.json | 12 +- 9 files changed, 927 insertions(+), 136 deletions(-) create mode 100644 scripts/add-mjs-extension.ts create mode 100755 scripts/build.sh delete mode 100755 scripts/fix-esm.sh create mode 100644 test/types/index.test.mts diff --git a/package-lock.json b/package-lock.json index c07ec079..2bedacea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@size-limit/preset-big-lib": "12.0.0", "@types/chai": "4.3.16", "@types/estree": "1.0.8", + "@types/jscodeshift": "17.3.0", "@types/mocha": "10.0.10", "@types/node": "25.1.0", "chai": "4.5.0", @@ -41,6 +42,7 @@ "globals": "17.2.0", "html-minifier": "4.0.0", "husky": "9.1.7", + "jscodeshift": "17.3.0", "jsdomify": "3.1.1", "karma": "6.4.4", "karma-chai": "0.1.0", @@ -76,15 +78,15 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -149,22 +151,35 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", @@ -192,30 +207,127 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -224,10 +336,24 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -235,9 +361,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -245,9 +371,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -269,13 +395,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.28.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -284,59 +410,394 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.28.6.tgz", + "integrity": "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-flow": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.27.1.tgz", + "integrity": "sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-flow-strip-types": "^7.27.1" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.6.tgz", + "integrity": "sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/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, "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1129,18 +1590,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1153,16 +1610,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", @@ -1182,9 +1629,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2017,6 +2464,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jscodeshift": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@types/jscodeshift/-/jscodeshift-17.3.0.tgz", + "integrity": "sha512-ogvGG8VQQqAQQ096uRh+d6tBHrYuZjsumHirKtvBa5qEyTMN3IQJ7apo+sw9lxaB/iKWIhbbLlF3zmAWk9XQIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "recast": "^0.23.11" + } + }, + "node_modules/@types/jscodeshift/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3633,6 +4104,21 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -5579,6 +6065,16 @@ "dev": true, "license": "ISC" }, + "node_modules/flow-parser": { + "version": "0.299.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.299.0.tgz", + "integrity": "sha512-phGMRoNt6SNglPHGRbCyWm9/pxfe6t/t4++EIYPaBGWT6e0lphLBgUMrvpL62NbRo9R549o3oqrbKHq82kANCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -6476,6 +6972,19 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -6549,6 +7058,16 @@ "dev": true, "license": "ISC" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -6755,6 +7274,61 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jscodeshift": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-17.3.0.tgz", + "integrity": "sha512-LjFrGOIORqXBU+jwfC9nbkjmQfFldtMIoS6d9z2LG/lkmyNXsJAySPT+2SWXJEoE68/bCWcxKpXH37npftgmow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/preset-flow": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "@babel/register": "^7.24.6", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.7", + "neo-async": "^2.5.0", + "picocolors": "^1.0.1", + "recast": "^0.23.11", + "tmp": "^0.2.3", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "node_modules/jscodeshift/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/jsdom": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.5.0.tgz", @@ -7230,6 +7804,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8989,6 +9573,26 @@ "node": ">=0.10" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -9400,6 +10004,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -9764,6 +10398,19 @@ "dev": true, "license": "ISC" }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10572,6 +11219,13 @@ "dev": true, "license": "MIT" }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", diff --git a/package.json b/package.json index 0335d623..9a6b56be 100644 --- a/package.json +++ b/package.json @@ -33,24 +33,24 @@ "./package.json": "./package.json" }, "scripts": { - "build": "run-s build:*", - "build:cjs": "tsc --project tsconfig.build.json", - "build:esm": "rollup --config --failAfterWarnings --environment ESM:true && scripts/fix-esm.sh", - "build:umd": "rollup --config --failAfterWarnings --environment UMD:true", + "build": "run-s clean build:*", + "build:cjs": "scripts/build.sh --cjs", + "build:esm": "scripts/build.sh --esm", + "build:umd": "scripts/build.sh --umd", "clean": "rm -rf .nyc_output coverage dist esm lib", "lint": "eslint .", "lint:fix": "npm run lint -- --fix", "lint:package": "publint", - "lint:tsc": "tsc --noEmit", + "lint:tsc": "tsc --project tsconfig.test.json", "prepare": "husky", "prepublishOnly": "run-s lint lint:tsc clean build lint:package", "size-limit": "size-limit", "test": "run-s test:server test:client", "test:client": "npm run test:client:watch -- --single-run", - "test:client:build": "NODE_ENV=test npm run build", + "test:client:build": "run-p build:cjs build:umd", "test:client:watch": "npm run test:client:build && karma start", "test:coverage": "npm run test:server && nyc report --reporter=html", - "test:esm": "npm run build && node --test test/esm", + "test:esm": "npm run build:esm && node --test test/esm", "test:server": "npm run build:cjs && nyc mocha" }, "repository": { @@ -85,6 +85,7 @@ "@size-limit/preset-big-lib": "12.0.0", "@types/chai": "4.3.16", "@types/estree": "1.0.8", + "@types/jscodeshift": "17.3.0", "@types/mocha": "10.0.10", "@types/node": "25.1.0", "chai": "4.5.0", @@ -95,6 +96,7 @@ "globals": "17.2.0", "html-minifier": "4.0.0", "husky": "9.1.7", + "jscodeshift": "17.3.0", "jsdomify": "3.1.1", "karma": "6.4.4", "karma-chai": "0.1.0", diff --git a/rollup.config.mjs b/rollup.config.mjs index eb92d973..5694c43d 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -8,28 +8,28 @@ import typescript from '@rollup/plugin-typescript'; const require = createRequire(import.meta.url); -const getPlugins = ({ browser = false, minify = false, outDir = '' }) => - [ - browser && - alias({ - entries: [ - { - find: './server/html-to-dom', - replacement: './client/html-to-dom', - }, - ], - }), - typescript({ - tsconfig: 'tsconfig.build.json', - compilerOptions: { - module: 'esnext', - outDir, - }, +// eslint-disable-next-line @typescript-eslint/no-unsafe-return +const getPlugins = ({ browser = false, minify = false, outDir = '' }) => [ + browser && + alias({ + entries: [ + { + find: './server/html-to-dom', + replacement: './client/html-to-dom', + }, + ], }), - commonjs(), - resolve({ browser }), - minify && terser(), - ].filter(Boolean); + typescript({ + tsconfig: 'tsconfig.build.json', + compilerOptions: { + module: 'esnext', + outDir, + }, + }), + commonjs(), + resolve({ browser }), + minify && terser(), +]; const getUMDConfig = (minify = false) => { const output = `dist/html-dom-parser${minify ? '.min' : ''}.js`; @@ -52,7 +52,7 @@ const getUMDConfig = (minify = false) => { const esmConfigs = [ // ESM server { - input: 'src/index.ts', + input: 'src/index.mts', output: { dir: 'esm', entryFileNames: '[name].mjs', @@ -70,7 +70,7 @@ const esmConfigs = [ // ESM client { - input: 'src/client/html-to-dom.ts', + input: 'src/client/html-to-dom.mts', output: { dir: 'esm/client', entryFileNames: '[name].mjs', diff --git a/scripts/add-mjs-extension.ts b/scripts/add-mjs-extension.ts new file mode 100644 index 00000000..481a7805 --- /dev/null +++ b/scripts/add-mjs-extension.ts @@ -0,0 +1,116 @@ +import * as path from 'node:path'; + +import type { API, FileInfo } from 'jscodeshift'; + +/** + * Codemod to add .mjs extension to all imports in TypeScript files + * + * This codemod transforms: + * import { something } from './module'; + * To: + * import { something } from './module.mjs'; + * + * It handles: + * - Named imports + * - Default imports + * - Namespace imports + * - Dynamic imports + * - Re-exports + */ + +export default function transformer(fileInfo: FileInfo, api: API): string { + const j = api.jscodeshift; + const root = j(fileInfo.source); + + // Helper to check if a module path is relative + function isRelativeModulePath(modulePath: string): boolean { + return modulePath.startsWith('./') || modulePath.startsWith('../'); + } + + // Helper to check if module already has an extension + function hasExtension(modulePath: string): boolean { + return path.extname(modulePath) !== ''; + } + + // Helper to add .mjs extension + function addMjsExtension(modulePath: string): string { + return modulePath + '.mjs'; + } + + // Transform import declarations + root.find(j.ImportDeclaration).forEach((path) => { + const source = path.node.source.value as string; + + if (isRelativeModulePath(source) && !hasExtension(source)) { + path.node.source.value = addMjsExtension(source); + } + }); + + // Transform export from declarations + root + .find(j.ExportNamedDeclaration, { source: { type: 'StringLiteral' } }) + .forEach((path) => { + const source = path.node.source?.value as string; + + if ( + path.node.source && + isRelativeModulePath(source) && + !hasExtension(source) + ) { + path.node.source.value = addMjsExtension(source); + } + }); + + // Transform export all declarations + root + .find(j.ExportAllDeclaration, { source: { type: 'StringLiteral' } }) + .forEach((path) => { + const source = path.node.source.value as string; + + if (isRelativeModulePath(source) && !hasExtension(source)) { + path.node.source.value = addMjsExtension(source); + } + }); + + // Transform dynamic import() calls + root + .find(j.CallExpression, { + callee: { type: 'Import' }, + }) + .forEach((path) => { + const argument = path.node.arguments[0]; + + if (j.StringLiteral.check(argument)) { + const source = argument.value; + + if (isRelativeModulePath(source) && !hasExtension(source)) { + argument.value = addMjsExtension(source); + } + } + }); + + // Transform require() calls (for completeness, though less common in ESM) + root + .find(j.CallExpression, { + callee: { name: 'require' }, + }) + .forEach((path) => { + const argument = path.node.arguments[0]; + + if (j.StringLiteral.check(argument)) { + const source = argument.value; + + if (isRelativeModulePath(source) && !hasExtension(source)) { + argument.value = addMjsExtension(source); + } + } + }); + + return root.toSource({ + quote: 'single', + trailingComma: true, + lineTerminator: '\n', + }); +} + +export const parser = 'ts'; diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 00000000..2292c796 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +if [[ $1 == '--cjs' ]]; then + tsc --project tsconfig.build.json + find lib -type f \( -name '*.mjs*' -or -name '*.mts*' \) -delete + +elif [[ $1 == '--esm' ]]; then + find src -type f -name '*.ts' -exec bash -c 'mv "$1" "${1%.ts}.mts"' _ {} \; + jscodeshift -t scripts/add-mjs-extension.ts src --extensions=mts + rollup --config --failAfterWarnings --environment ESM:true + rm -rf esm/client/{client,server,index.*,types.*} + git restore src + git clean -f src + +elif [[ $1 == '--umd' ]]; then + rollup --config --failAfterWarnings --environment UMD:true + rm -rf dist/{client,server,*.mts*,*.ts*} +fi diff --git a/scripts/fix-esm.sh b/scripts/fix-esm.sh deleted file mode 100755 index 50fad9c5..00000000 --- a/scripts/fix-esm.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# replace `.d.ts` -> `.d.mts` -find esm -type f -exec perl -i -pe 's/\.d\.ts/\.d\.mts/g' {} + - -# rename `.d.ts` -> `.d.mts` -find esm -name '*.d.ts' -exec bash -c 'mv "$1" "${1%.d.ts}.d.mts"' _ {} \; - -# rename `.d.ts.map` -> `.d.mts.map` -find esm -name '*.d.ts.map' -exec bash -c 'mv "$1" "${1%.d.ts.map}.d.mts.map"' _ {} \; - -# delete extraneous files -rm -rf esm/client/{client,server,index.*,types.*} diff --git a/test/types/index.test.mts b/test/types/index.test.mts new file mode 100644 index 00000000..a57aeeb3 --- /dev/null +++ b/test/types/index.test.mts @@ -0,0 +1,16 @@ +import parse from '../../esm/index.mjs'; + +// $ExpectType (Element | Text | Comment | ProcessingInstruction)[] +parse('
text
'); + +// $ExpectType (Element | Text | Comment | ProcessingInstruction)[] +parse('
text
', { xmlMode: true }); + +// $ExpectType (Element | Text | Comment | ProcessingInstruction)[] +parse('
text
', { decodeEntities: false }); + +// $ExpectType (Element | Text | Comment | ProcessingInstruction)[] +parse('
text
', { lowerCaseTags: true }); + +// $ExpectType (Element | Text | Comment | ProcessingInstruction)[] +parse(''); diff --git a/test/types/index.test.ts b/test/types/index.test.ts index 574408df..3efd0007 100644 --- a/test/types/index.test.ts +++ b/test/types/index.test.ts @@ -7,10 +7,10 @@ parse('
text
'); parse('
text
', { xmlMode: true }); // $ExpectType (Element | Text | Comment | ProcessingInstruction)[] -parse('
text
', { withStartIndices: true }); +parse('
text
', { decodeEntities: false }); // $ExpectType (Element | Text | Comment | ProcessingInstruction)[] -parse('
text
', { withEndIndices: true }); +parse('
text
', { lowerCaseTags: true }); // $ExpectType (Element | Text | Comment | ProcessingInstruction)[] parse(''); diff --git a/tsconfig.test.json b/tsconfig.test.json index c14628de..e6894102 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,13 +1,11 @@ { "extends": "./tsconfig.build.json", "compilerOptions": { + "target": "esnext", + "module": "nodenext", + "moduleResolution": "nodenext", + "noEmit": true, "allowJs": true }, - "include": [ - "src", - "test", - "eslint.config.mjs", - "karma.conf.js", - "rollup.config.mjs" - ] + "include": ["scripts", "src", "test", "*.mjs", "*.js"] } From b1bf1d540d87e902c0f54a86baf8ff0174aa6236 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 30 Jan 2026 18:08:59 -0500 Subject: [PATCH 6/6] ci(github): check types in workflow lint.yml --- .github/workflows/build.yml | 3 --- .github/workflows/lint.yml | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8055e54b..03b256ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,3 @@ jobs: - name: Build package run: npm run build - - - name: Lint package - run: npm run lint:package diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ceef5196..04561fc7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,3 +28,14 @@ jobs: - name: Type check run: npm run lint:tsc + + - name: Lint package + run: npm run lint:package + + - name: Check types + run: | + npx @arethetypeswrong/cli --pack + if [[ "$(npx @arethetypeswrong/cli --pack -f json | jq '.problems != {}')" == 'true' ]]; then + npx @arethetypeswrong/cli --pack -f json | jq + exit 1 + fi