Bump dev deps, use @typescript-eslint type checked style preset (#4313)

This commit is contained in:
Felix Boehm
2024-12-23 12:15:54 +00:00
committed by GitHub
parent 3c1004836d
commit 5f4e84b19b
18 changed files with 262 additions and 243 deletions

View File

@@ -90,7 +90,8 @@
"extends": [
"plugin:expect-type/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked",
"prettier"
],
"parserOptions": {

View File

@@ -18,12 +18,17 @@ const benchmarkFilter = filterIndex >= 0 ? process.argv[filterIndex] : '';
const cheerioOnly = process.argv.includes('--cheerio-only');
interface SuiteOptions<T> {
test($: CheerioAPI, data: T): void;
setup($: CheerioAPI): T;
}
type SuiteOptions<T> = T extends void
? {
test(this: void, $: CheerioAPI): void;
setup?: (this: void, $: CheerioAPI) => T;
}
: {
test(this: void, $: CheerioAPI, data: T): void;
setup(this: void, $: CheerioAPI): T;
};
async function benchmark<T>(
async function benchmark<T = void>(
name: string,
fileName: string,
options: SuiteOptions<T>,
@@ -40,7 +45,7 @@ async function benchmark<T>(
// Add Cheerio test
const $ = load(markup);
const setupData: T = setup($);
const setupData = setup?.($) as T;
bench.add('cheerio', () => {
test($, setupData);
@@ -52,23 +57,20 @@ async function benchmark<T>(
jQueryScript.runInContext(dom.getInternalVMContext());
const setupData: T = setup(dom.window['$']);
const setupData = setup?.(dom.window['$'] as CheerioAPI) as T;
bench.add('jsdom', () => test(dom.window['$'], setupData));
bench.add('jsdom', () => test(dom.window['$'] as CheerioAPI, setupData));
}
await bench.warmup(); // Make results more reliable, ref: https://github.com/tinylibs/tinybench/pull/50
await bench.run();
console.table(bench.table());
}
await benchmark<void>('Select all', 'jquery.html', {
setup() {},
await benchmark('Select all', 'jquery.html', {
test: ($) => $('*').length,
});
await benchmark<void>('Select some', 'jquery.html', {
setup() {},
await benchmark('Select some', 'jquery.html', {
test: ($) => $('li').length,
});
@@ -116,7 +118,7 @@ await benchmark<Cheerio<Element>>('manipulation - remove', 'jquery.html', {
},
});
await benchmark<void>('manipulation - replaceWith', 'jquery.html', {
await benchmark('manipulation - replaceWith', 'jquery.html', {
setup($) {
$('body').append('<div id="foo">');
},
@@ -147,8 +149,7 @@ await benchmark<Cheerio<Element>>('manipulation - html render', 'jquery.html', {
const HTML_INDEPENDENT_MARKUP =
'<div class="foo"><div id="bar">bat<hr>baz</div> </div>'.repeat(6);
await benchmark<void>('manipulation - html independent', 'jquery.html', {
setup() {},
await benchmark('manipulation - html independent', 'jquery.html', {
test: ($) => $(HTML_INDEPENDENT_MARKUP).html(),
});
await benchmark<Cheerio<Element>>('manipulation - text', 'jquery.html', {

245
package-lock.json generated
View File

@@ -35,19 +35,19 @@
"eslint-plugin-expect-type": "^0.6.2",
"eslint-plugin-jsdoc": "^50.6.1",
"eslint-plugin-n": "^17.15.1",
"eslint-plugin-unicorn": "^55.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vitest": "^0.5.4",
"husky": "^9.1.7",
"jquery": "^3.7.1",
"jsdom": "^24.1.1",
"jsdom": "^25.0.1",
"lint-staged": "^15.2.11",
"prettier": "^3.4.2",
"prettier-plugin-jsdoc": "^1.3.0",
"tinybench": "^2.9.0",
"tinybench": "^3.1.0",
"tshy": "^3.0.2",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"vitest": "^2.0.5"
"typescript": "^5.7.2",
"vitest": "^2.1.8"
},
"engines": {
"node": ">=18.17"
@@ -2282,9 +2282,9 @@
}
},
"node_modules/browserslist": {
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
"version": "4.24.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz",
"integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==",
"dev": true,
"funding": [
{
@@ -2300,11 +2300,12 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001587",
"electron-to-chromium": "^1.4.668",
"node-releases": "^2.0.14",
"update-browserslist-db": "^1.0.13"
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.1"
},
"bin": {
"browserslist": "cli.js"
@@ -2344,9 +2345,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001609",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz",
"integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==",
"version": "1.0.30001690",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz",
"integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==",
"dev": true,
"funding": [
{
@@ -2361,7 +2362,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
],
"license": "CC-BY-4.0"
},
"node_modules/chai": {
"version": "5.1.2",
@@ -2609,13 +2611,13 @@
"dev": true
},
"node_modules/core-js-compat": {
"version": "3.37.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz",
"integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==",
"version": "3.39.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz",
"integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.23.0"
"browserslist": "^4.24.2"
},
"funding": {
"type": "opencollective",
@@ -2623,10 +2625,11 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -2672,12 +2675,13 @@
}
},
"node_modules/cssstyle": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
"integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
"integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
"dev": true,
"license": "MIT",
"dependencies": {
"rrweb-cssom": "^0.6.0"
"rrweb-cssom": "^0.7.1"
},
"engines": {
"node": ">=18"
@@ -2862,10 +2866,11 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.4.736",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz",
"integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==",
"dev": true
"version": "1.5.75",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz",
"integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==",
"dev": true,
"license": "ISC"
},
"node_modules/emoji-regex": {
"version": "10.4.0",
@@ -2979,10 +2984,11 @@
}
},
"node_modules/escalade": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
@@ -3214,18 +3220,19 @@
}
},
"node_modules/eslint-plugin-unicorn": {
"version": "55.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz",
"integrity": "sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==",
"version": "56.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz",
"integrity": "sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.24.5",
"@babel/helper-validator-identifier": "^7.24.7",
"@eslint-community/eslint-utils": "^4.4.0",
"ci-info": "^4.0.0",
"clean-regexp": "^1.0.0",
"core-js-compat": "^3.37.0",
"esquery": "^1.5.0",
"globals": "^15.7.0",
"core-js-compat": "^3.38.1",
"esquery": "^1.6.0",
"globals": "^15.9.0",
"indent-string": "^4.0.0",
"is-builtin-module": "^3.2.1",
"jsesc": "^3.0.2",
@@ -3233,7 +3240,7 @@
"read-pkg-up": "^7.0.1",
"regexp-tree": "^0.1.27",
"regjsparser": "^0.10.0",
"semver": "^7.6.1",
"semver": "^7.6.3",
"strip-indent": "^3.0.0"
},
"engines": {
@@ -3247,10 +3254,11 @@
}
},
"node_modules/eslint-plugin-unicorn/node_modules/globals": {
"version": "15.8.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz",
"integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==",
"version": "15.14.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz",
"integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
@@ -4120,12 +4128,13 @@
}
},
"node_modules/jsdom": {
"version": "24.1.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz",
"integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==",
"version": "25.0.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz",
"integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssstyle": "^4.0.1",
"cssstyle": "^4.1.0",
"data-urls": "^5.0.0",
"decimal.js": "^10.4.3",
"form-data": "^4.0.0",
@@ -4138,7 +4147,7 @@
"rrweb-cssom": "^0.7.1",
"saxes": "^6.0.0",
"symbol-tree": "^3.2.4",
"tough-cookie": "^4.1.4",
"tough-cookie": "^5.0.0",
"w3c-xmlserializer": "^5.0.0",
"webidl-conversions": "^7.0.0",
"whatwg-encoding": "^3.1.1",
@@ -4159,13 +4168,6 @@
}
}
},
"node_modules/jsdom/node_modules/rrweb-cssom": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
"integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
"dev": true,
"license": "MIT"
},
"node_modules/jsesc": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
@@ -5225,10 +5227,11 @@
"dev": true
},
"node_modules/node-releases": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
"dev": true
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true,
"license": "MIT"
},
"node_modules/normalize-package-data": {
"version": "2.5.0",
@@ -5649,13 +5652,6 @@
"prettier": "^3.0.0"
}
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"dev": true,
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5665,13 +5661,6 @@
"node": ">=6"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true,
"license": "MIT"
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5837,13 +5826,6 @@
"jsesc": "bin/jsesc"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true,
"license": "MIT"
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -6023,10 +6005,11 @@
}
},
"node_modules/rrweb-cssom": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
"dev": true
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
"integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
"dev": true,
"license": "MIT"
},
"node_modules/run-parallel": {
"version": "1.2.0",
@@ -6516,11 +6499,14 @@
"dev": true
},
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-3.1.0.tgz",
"integrity": "sha512-Km+oMh2xqNCxuyoUsqbRmHgFSd8sATh7v7xreP+kHN6x67w28Pawr83WmBxcaORvxkc0Ex6zgqK951yBnTFaaQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/tinyexec": {
"version": "0.3.1",
@@ -6556,6 +6542,26 @@
"node": ">=14.0.0"
}
},
"node_modules/tldts": {
"version": "6.1.69",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.69.tgz",
"integrity": "sha512-Oh/CqRQ1NXNY7cy9NkTPUauOWiTro0jEYZTioGbOmcQh6EC45oribyIMJp0OJO3677r13tO6SKdWoGZUx2BDFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"tldts-core": "^6.1.69"
},
"bin": {
"tldts": "bin/cli.js"
}
},
"node_modules/tldts-core": {
"version": "6.1.69",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.69.tgz",
"integrity": "sha512-nygxy9n2PBUFQUtAXAc122gGo+04/j5qr5TGQFZTHafTKYvmARVXt2cA5rgero2/dnXUfkdPtiJoKmrd3T+wdA==",
"dev": true,
"license": "MIT"
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -6570,29 +6576,16 @@
}
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
"integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
"tldts": "^6.1.32"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
"node": ">=16"
}
},
"node_modules/tr46": {
@@ -7176,10 +7169,11 @@
}
},
"node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7238,9 +7232,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.0.13",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"dev": true,
"funding": [
{
@@ -7256,9 +7250,10 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"escalade": "^3.1.1",
"picocolors": "^1.0.0"
"escalade": "^3.2.0",
"picocolors": "^1.1.0"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -7276,17 +7271,6 @@
"punycode": "^2.1.0"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"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",
@@ -7453,6 +7437,13 @@
}
}
},
"node_modules/vitest/node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true,
"license": "MIT"
},
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",

View File

@@ -141,19 +141,19 @@
"eslint-plugin-expect-type": "^0.6.2",
"eslint-plugin-jsdoc": "^50.6.1",
"eslint-plugin-n": "^17.15.1",
"eslint-plugin-unicorn": "^55.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vitest": "^0.5.4",
"husky": "^9.1.7",
"jquery": "^3.7.1",
"jsdom": "^24.1.1",
"jsdom": "^25.0.1",
"lint-staged": "^15.2.11",
"prettier": "^3.4.2",
"prettier-plugin-jsdoc": "^1.3.0",
"tinybench": "^2.9.0",
"tinybench": "^3.1.0",
"tshy": "^3.0.2",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"vitest": "^2.0.5"
"typescript": "^5.7.2",
"vitest": "^2.1.8"
},
"engines": {
"node": ">=18.17"

View File

@@ -9,7 +9,11 @@ import { domEach, camelCase, cssCase } from '../utils.js';
import { isTag, type AnyNode, type Element } from 'domhandler';
import type { Cheerio } from '../cheerio.js';
import { innerText, textContent } from 'domutils';
const hasOwn = Object.prototype.hasOwnProperty;
const hasOwn =
// @ts-expect-error `hasOwn` is a standard object method
(Object.hasOwn as (object: unknown, prop: string) => boolean) ??
((object: unknown, prop: string) =>
Object.prototype.hasOwnProperty.call(object, prop));
const rspace = /\s+/;
const dataAttrPrefix = 'data-';
@@ -56,7 +60,7 @@ function getAttr(
return elem.attribs;
}
if (hasOwn.call(elem.attribs, name)) {
if (hasOwn(elem.attribs, name)) {
// Get the (decoded) attribute
return !xmlMode && rboolean.test(name) ? name : elem.attribs[name];
}
@@ -209,14 +213,14 @@ export function attr<T extends AnyNode>(
setAttr(el, objName, objValue);
}
} else {
setAttr(el, name as string, value as string);
setAttr(el, name!, value!);
}
});
}
return arguments.length > 1
? this
: getAttr(this[0], name as string, this.options.xmlMode);
: getAttr(this[0], name!, this.options.xmlMode);
}
/**
@@ -233,10 +237,10 @@ function getProp(
el: Element,
name: string,
xmlMode?: boolean,
): string | undefined | Element[keyof Element] {
): string | undefined | boolean | Element[keyof Element] {
return name in el
? // @ts-expect-error TS doesn't like us accessing the value directly here.
el[name]
(el[name] as string | undefined)
: !xmlMode && rboolean.test(name)
? getAttr(el, name, false) !== undefined
: getAttr(el, name, xmlMode);
@@ -259,7 +263,11 @@ function setProp(el: Element, name: string, value: unknown, xmlMode?: boolean) {
setAttr(
el,
name,
!xmlMode && rboolean.test(name) ? (value ? '' : null) : `${value}`,
!xmlMode && rboolean.test(name)
? value
? ''
: null
: `${value as string}`,
);
}
}
@@ -396,14 +404,15 @@ export function prop<T extends AnyNode>(this: Cheerio<T>, name: string): string;
export function prop<T extends AnyNode>(
this: Cheerio<T>,
name: string | Record<string, string | Element[keyof Element] | boolean>,
value?:
| ((
this: Element,
i: number,
prop: string | undefined,
) => string | Element[keyof Element] | boolean)
| unknown,
): Cheerio<T> | string | undefined | null | Element[keyof Element] | StyleProp {
value?: unknown,
):
| Cheerio<T>
| string
| boolean
| undefined
| null
| Element[keyof Element]
| StyleProp {
if (typeof name === 'string' && value === undefined) {
const el = this[0];
@@ -552,7 +561,7 @@ function readAllData(el: DataElement): unknown {
const jsName = camelCase(domName.slice(dataAttrPrefix.length));
if (!hasOwn.call(el.data, jsName)) {
if (!hasOwn(el.data, jsName)) {
el.data![jsName] = parseDataValue(el.attribs[domName]);
}
}
@@ -574,11 +583,11 @@ function readData(el: DataElement, name: string): unknown {
const domName = dataAttrPrefix + cssCase(name);
const data = el.data!;
if (hasOwn.call(data, name)) {
if (hasOwn(data, name)) {
return data[name];
}
if (hasOwn.call(el.attribs, domName)) {
if (hasOwn(el.attribs, domName)) {
return (data[name] = parseDataValue(el.attribs[domName]));
}
@@ -629,7 +638,7 @@ function parseDataValue(value: string): unknown {
export function data<T extends AnyNode>(
this: Cheerio<T>,
name: string,
): unknown | undefined;
): unknown;
/**
* Method for getting all of an element's data attributes, for only the first
* element in the matched set.
@@ -698,7 +707,7 @@ export function data<T extends AnyNode>(
this: Cheerio<T>,
name?: string | Record<string, unknown>,
value?: unknown,
): unknown | Cheerio<T> | undefined | Record<string, unknown> {
): unknown {
const elem = this[0];
if (!elem || !isTag(elem)) return;
@@ -716,7 +725,7 @@ export function data<T extends AnyNode>(
domEach(this, (el) => {
if (isTag(el)) {
if (typeof name === 'object') setData(el, name);
else setData(el, name, value as unknown);
else setData(el, name, value);
}
});
return this;
@@ -816,7 +825,7 @@ export function val<T extends AnyNode>(
* @param name - Name of the attribute to remove.
*/
function removeAttribute(elem: Element, name: string) {
if (!elem.attribs || !hasOwn.call(elem.attribs, name)) return;
if (!elem.attribs || !hasOwn(elem.attribs, name)) return;
delete elem.attribs[name];
}
@@ -1030,7 +1039,7 @@ export function removeClass<T extends AnyNode, R extends ArrayLike<T>>(
for (let j = 0; j < numClasses; j++) {
const index = elClasses.indexOf(classes[j]);
if (index >= 0) {
if (index !== -1) {
elClasses.splice(index, 1);
changed = true;
@@ -1115,9 +1124,9 @@ export function toggleClass<T extends AnyNode, R extends ArrayLike<T>>(
const index = elementClasses.indexOf(classNames[j]);
// Add if stateValue === true or we are toggling and there is no value
if (state >= 0 && index < 0) {
if (state >= 0 && index === -1) {
elementClasses.push(classNames[j]);
} else if (state <= 0 && index >= 0) {
} else if (state <= 0 && index !== -1) {
// Otherwise remove but only if the item exists
elementClasses.splice(index, 1);
}

View File

@@ -16,9 +16,7 @@ interface ExtractDescriptor {
type ExtractValue = string | ExtractDescriptor | [string | ExtractDescriptor];
export interface ExtractMap {
[key: string]: ExtractValue;
}
export type ExtractMap = Record<string, ExtractValue>;
type ExtractedValue<V extends ExtractValue, M extends ExtractMap> = V extends [
string | ExtractDescriptor,

View File

@@ -82,7 +82,7 @@ export function serializeArray<T extends AnyNode>(
}
>((_, elem) => {
const $elem = this._make(elem);
const name = $elem.attr('name') as string; // We have filtered for elements with a name before.
const name = $elem.attr('name')!; // We have filtered for elements with a name before.
// If there is no value set (e.g. `undefined`, `null`), then default value to empty
const value = $elem.val() ?? '';

View File

@@ -20,6 +20,7 @@ import { domEach, isHtml, isCheerio } from '../utils.js';
import { removeElement } from 'domutils';
import type { Cheerio } from '../cheerio.js';
import type { BasicAcceptedElems, AcceptedElems } from '../types.js';
import { ElementType } from 'htmlparser2';
/**
* Create an array of nodes, recursing into arrays and parsing strings if
@@ -129,7 +130,7 @@ function uniqueSplice(
newElems: AnyNode[],
parent: ParentNode,
): AnyNode[] {
const spliceArgs: Parameters<typeof Array.prototype.splice> = [
const spliceArgs: Parameters<AnyNode[]['splice']> = [
spliceIdx,
spliceCount,
...newElems,
@@ -152,7 +153,7 @@ function uniqueSplice(
const oldSiblings: AnyNode[] = oldParent.children;
const prevIdx = oldSiblings.indexOf(node);
if (prevIdx > -1) {
if (prevIdx !== -1) {
oldParent.children.splice(prevIdx, 1);
if (parent === oldParent && spliceIdx > prevIdx) {
spliceArgs[0]--;
@@ -588,7 +589,9 @@ export function wrapAll<T extends AnyNode>(
let elInsertLocation: Element | undefined;
for (let i = 0; i < wrap.length; i++) {
if (wrap[i].type === 'tag') elInsertLocation = wrap[i] as Element;
if (wrap[i].type === ElementType.Tag) {
elInsertLocation = wrap[i] as Element;
}
}
let j = 0;
@@ -599,8 +602,8 @@ export function wrapAll<T extends AnyNode>(
*/
while (elInsertLocation && j < elInsertLocation.children.length) {
const child = elInsertLocation.children[j];
if (child.type === 'tag') {
elInsertLocation = child as Element;
if (child.type === ElementType.Tag) {
elInsertLocation = child;
j = 0;
} else {
j++;
@@ -652,7 +655,7 @@ export function after<T extends AnyNode>(
// If not found, move on
/* istanbul ignore next */
if (index < 0) return;
if (index === -1) return;
const domSrc =
typeof elems[0] === 'function'
@@ -711,7 +714,7 @@ export function insertAfter<T extends AnyNode>(
// If not found, move on
/* istanbul ignore next */
if (index < 0) continue;
if (index === -1) continue;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index + 1, 0, clonedSelf, parent);
@@ -761,7 +764,7 @@ export function before<T extends AnyNode>(
// If not found, move on
/* istanbul ignore next */
if (index < 0) return;
if (index === -1) return;
const domSrc =
typeof elems[0] === 'function'
@@ -818,7 +821,7 @@ export function insertBefore<T extends AnyNode>(
// If not found, move on
/* istanbul ignore next */
if (index < 0) return;
if (index === -1) return;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index, 0, clonedSelf, parent);
@@ -1097,8 +1100,9 @@ export function text<T extends AnyNode>(
* @see {@link https://api.jquery.com/clone/}
*/
export function clone<T extends AnyNode>(this: Cheerio<T>): Cheerio<T> {
const clone = Array.prototype.map.call(this.get(), (el) =>
cloneNode(el, true),
const clone = Array.prototype.map.call(
this.get(),
(el) => cloneNode(el, true) as T,
) as T[];
// Add a root node around the cloned nodes

View File

@@ -30,7 +30,8 @@ describe('$(...)', () => {
describe('.load', () => {
it('should throw a TypeError if given invalid input', () => {
expect(() => {
(load as any)();
// @ts-expect-error Testing invalid input
load();
}).toThrow('cheerio.load() expects a string');
});
});
@@ -858,7 +859,7 @@ describe('$(...)', () => {
it('should yield each element', () => {
// The equivalent of: for (const element of $('li')) ...
const $li = $('li');
const iterator = $li[Symbol.iterator]();
const iterator = $li[Symbol.iterator]() as Iterator<Element, Element>;
expect(iterator.next().value.attribs).toHaveProperty('class', 'apple');
expect(iterator.next().value.attribs).toHaveProperty('class', 'orange');
expect(iterator.next().value.attribs).toHaveProperty('class', 'pear');

View File

@@ -1025,7 +1025,7 @@ export function get<T>(this: Cheerio<T>, i?: number): T | T[] {
* @returns The contained items.
*/
export function toArray<T>(this: Cheerio<T>): T[] {
return Array.prototype.slice.call(this);
return (Array.prototype as T[]).slice.call(this);
}
/**
@@ -1097,7 +1097,7 @@ export function slice<T>(
start?: number,
end?: number,
): Cheerio<T> {
return this._make(Array.prototype.slice.call(this, start, end));
return this._make<T>(Array.prototype.slice.call(this, start, end));
}
/**
@@ -1116,7 +1116,7 @@ export function slice<T>(
* @see {@link https://api.jquery.com/end/}
*/
export function end<T>(this: Cheerio<T>): Cheerio<AnyNode> {
return this.prevObject ?? this._make([]);
return (this.prevObject as Cheerio<AnyNode> | null) ?? this._make([]);
}
/**
@@ -1166,6 +1166,8 @@ export function addBack<T extends AnyNode>(
selector?: string,
): Cheerio<AnyNode> {
return this.prevObject
? this.add(selector ? this.prevObject.filter(selector) : this.prevObject)
? this.add<AnyNode, T>(
selector ? this.prevObject.filter(selector) : this.prevObject,
)
: this;
}

View File

@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import { parseDOM } from 'htmlparser2';
import { type Cheerio } from './index.js';
import { cheerio, fruits, food, noscript } from './__fixtures__/fixtures.js';
import type { Element } from 'domhandler';
import type { AnyNode, Element } from 'domhandler';
declare module './index.js' {
interface Cheerio<T> {
@@ -10,7 +10,7 @@ declare module './index.js' {
context: Cheerio<T>;
args: unknown[];
};
foo(): void;
foo(this: void): void;
}
}
@@ -221,17 +221,23 @@ describe('cheerio', () => {
});
it('(extended Array) should not interfere with prototype methods (issue #119)', () => {
const extended: any = [];
const extended: AnyNode[] = [];
// @ts-expect-error - Ignore for testing
extended.find =
// @ts-expect-error - Ignore for testing
extended.children =
// @ts-expect-error - Ignore for testing
extended.each =
function () {
/* Ignore */
};
const $empty = cheerio(extended);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect($empty.find).toBe(cheerio.prototype.find);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect($empty.children).toBe(cheerio.prototype.children);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect($empty.each).toBe(cheerio.prototype.each);
});
@@ -360,7 +366,9 @@ describe('cheerio', () => {
it('should honor extensions defined on `prototype` property', () => {
const $ = cheerio.load('<div>');
$.prototype.myPlugin = function (...args: unknown[]) {
($.prototype as Cheerio<AnyNode>).myPlugin = function (
...args: unknown[]
) {
return {
context: this,
args,
@@ -394,7 +402,7 @@ describe('cheerio', () => {
const $a = cheerio.load('<div>');
const $b = cheerio.load('<div>');
$a.prototype.foo = function () {
($a.prototype as Cheerio<AnyNode>).foo = function () {
/* Ignore */
};

View File

@@ -9,12 +9,12 @@ function noop() {
// Returns a promise and a resolve function
function getPromise() {
let cb: (error: Error | null | undefined, $: cheerio.CheerioAPI) => void;
let cb!: (error: Error | null | undefined, $: cheerio.CheerioAPI) => void;
const promise = new Promise<cheerio.CheerioAPI>((resolve, reject) => {
cb = (error, $) => (error ? reject(error) : resolve($));
});
return { promise, cb: cb! };
return { promise, cb };
}
const TEST_HTML = '<h1>Hello World</h1>';

View File

@@ -228,10 +228,11 @@ export async function fromURL(
const promise = new Promise<CheerioAPI>((resolve, reject) => {
undiciStream = undici.stream(url, requestOptions, (res) => {
const contentType = res.headers['content-type'] ?? 'text/html';
const mimeType = new MIMEType(
Array.isArray(contentType) ? contentType[0] : contentType,
);
const contentTypeHeader = res.headers['content-type'] ?? 'text/html';
const contentType = Array.isArray(contentTypeHeader)
? contentTypeHeader[0]
: contentTypeHeader;
const mimeType = new MIMEType(contentType);
if (!mimeType.isHTML() && !mimeType.isXML()) {
throw new RangeError(

View File

@@ -8,6 +8,7 @@ import { Cheerio } from './cheerio.js';
import { isHtml, isCheerio } from './utils.js';
import type { AnyNode, Document, Element, ParentNode } from 'domhandler';
import type { SelectorType, BasicAcceptedElems } from './types.js';
import { ElementType } from 'htmlparser2';
type StaticType = typeof staticMethods;
@@ -104,7 +105,7 @@ export interface CheerioAPI extends StaticType {
}
export function getLoad(
parse: typeof Cheerio.prototype._parse,
parse: Cheerio<AnyNode>['_parse'],
render: (
dom: AnyNode | ArrayLike<AnyNode>,
options: InternalOptions,
@@ -209,7 +210,7 @@ export function getLoad(
const instance = new LoadedCheerio(elements, rootInstance, options);
if (elements) {
return instance as any;
return instance as Cheerio<Result>;
}
if (typeof selector !== 'string') {
@@ -243,7 +244,7 @@ export function getLoad(
: rootInstance;
// If we still don't have a context, return
if (!searchContext) return instance as any;
if (!searchContext) return instance as Cheerio<Result>;
/*
* #id, .class, tag
@@ -267,11 +268,15 @@ export function getLoad(
};
}
function isNode(obj: any): obj is AnyNode {
function isNode(obj: unknown): obj is AnyNode {
return (
// @ts-expect-error: TS doesn't know about the `name` property.
!!obj.name ||
obj.type === 'root' ||
obj.type === 'text' ||
obj.type === 'comment'
// @ts-expect-error: TS doesn't know about the `type` property.
obj.type === ElementType.Root ||
// @ts-expect-error: TS doesn't know about the `type` property.
obj.type === ElementType.Text ||
// @ts-expect-error: TS doesn't know about the `type` property.
obj.type === ElementType.Comment
);
}

View File

@@ -264,7 +264,7 @@ describe('parse', () => {
expect(childNodes[0].previousSibling).toBe(null);
expect(childNodes[0].nextSibling).toBe(childNodes[1]);
expect(childNodes[0].parentNode).toBe(root);
expect((childNodes[0] as Element).childNodes).toHaveLength(0);
expect(childNodes[0].childNodes).toHaveLength(0);
expect(childNodes[0].firstChild).toBe(null);
expect(childNodes[0].lastChild).toBe(null);
@@ -335,23 +335,17 @@ describe('parse', () => {
false,
null,
);
const childNodes = root.childNodes as Element[];
expect(childNodes[0].tagName).toBe('table');
expect(childNodes[0].childNodes.length).toBe(1);
expect(childNodes[0].childNodes[0]).toHaveProperty('tagName', 'tbody');
expect((childNodes[0] as any).childNodes[0].childNodes[0]).toHaveProperty(
'tagName',
'tr',
);
expect(
(childNodes[0] as any).childNodes[0].childNodes[0].childNodes[0]
.tagName,
).toBe('td');
expect(
(childNodes[0] as any).childNodes[0].childNodes[0].childNodes[0]
.childNodes[0].data,
).toBe('bar');
const table = root.childNodes[0] as Element;
expect(table.tagName).toBe('table');
expect(table.childNodes.length).toBe(1);
const tbody = table.childNodes[0] as Element;
expect(table.childNodes[0]).toHaveProperty('tagName', 'tbody');
const tr = tbody.childNodes[0] as Element;
expect(tr).toHaveProperty('tagName', 'tr');
const td = tr.childNodes[0] as Element;
expect(td).toHaveProperty('tagName', 'td');
expect(td.childNodes[0]).toHaveProperty('data', 'bar');
});
it('Should parse custom tag <line>', () => {

View File

@@ -152,14 +152,14 @@ export function text(
export function parseHTML(
this: CheerioAPI,
data: string,
context?: unknown | boolean,
context?: unknown,
keepScripts?: boolean,
): AnyNode[];
export function parseHTML(this: CheerioAPI, data?: '' | null): null;
export function parseHTML(
this: CheerioAPI,
data?: string | null,
context?: unknown | boolean,
context?: unknown,
keepScripts = typeof context === 'boolean' ? context : false,
): AnyNode[] | null {
if (!data || typeof data !== 'string') {

View File

@@ -8,8 +8,10 @@ import type { Cheerio } from './cheerio.js';
* @param maybeCheerio - The object to check.
* @returns Whether the object is a Cheerio instance.
*/
export function isCheerio<T>(maybeCheerio: any): maybeCheerio is Cheerio<T> {
return maybeCheerio.cheerio != null;
export function isCheerio<T>(
maybeCheerio: unknown,
): maybeCheerio is Cheerio<T> {
return (maybeCheerio as Cheerio<T>).cheerio != null;
}
/**
@@ -21,7 +23,7 @@ export function isCheerio<T>(maybeCheerio: any): maybeCheerio is Cheerio<T> {
* @returns String in camel case notation.
*/
export function camelCase(str: string): string {
return str.replace(/[._-](\w|$)/g, (_, x) => x.toUpperCase());
return str.replace(/[._-](\w|$)/g, (_, x) => (x as string).toUpperCase());
}
/**
@@ -58,7 +60,7 @@ export function domEach<
return array;
}
const enum CharacterCodes {
const enum CharacterCode {
LowerA = 97,
LowerZ = 122,
UpperA = 65,
@@ -80,14 +82,14 @@ const enum CharacterCodes {
export function isHtml(str: string): boolean {
const tagStart = str.indexOf('<');
if (tagStart < 0 || tagStart > str.length - 3) return false;
if (tagStart === -1 || tagStart > str.length - 3) return false;
const tagChar = str.charCodeAt(tagStart + 1);
const tagChar = str.charCodeAt(tagStart + 1) as CharacterCode;
return (
((tagChar >= CharacterCodes.LowerA && tagChar <= CharacterCodes.LowerZ) ||
(tagChar >= CharacterCodes.UpperA && tagChar <= CharacterCodes.UpperZ) ||
tagChar === CharacterCodes.Exclamation) &&
((tagChar >= CharacterCode.LowerA && tagChar <= CharacterCode.LowerZ) ||
(tagChar >= CharacterCode.UpperA && tagChar <= CharacterCode.UpperZ) ||
tagChar === CharacterCode.Exclamation) &&
str.includes('>', tagStart + 2)
);
}

View File

@@ -1,6 +1,6 @@
import { defineConfig } from 'vitest/config';
import { defineConfig, type ViteUserConfig } from 'vitest/config';
export default defineConfig({
const config: ViteUserConfig = defineConfig({
test: {
coverage: {
exclude: [
@@ -13,3 +13,5 @@ export default defineConfig({
},
},
});
export default config;