diff --git a/README.md b/README.md index 1b698be..f4c9a4b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ An every-growing collection of JavaScript utility packages targeting Node.js and * [@bust/config](packages/config) * Schema-driven configuration management for Node.js or the browser +* [@bust/eslint-config](packages/eslint-config) + * Shared ESLint configuration for Busticated JS/TS projects * [@bust/numeric-id-hasher](packages/numeric-id-hasher) * Encode / decode bigints as string hashes for use in shortened urls * [@bust/periodical](packages/periodical) diff --git a/bin/create-package.mjs b/bin/create-package.mjs index 17edb58..c4c8a96 100755 --- a/bin/create-package.mjs +++ b/bin/create-package.mjs @@ -25,7 +25,7 @@ try { licenseMD, packageJSON, readmeMD, - tsconfigJSON + tsconfigJSON, } = await loadTemplates(); await Promise.all([ @@ -35,7 +35,7 @@ try { fs.outputFile(path.join(pkg.path, 'package.json'), packageJSON(pkg)), fs.outputFile(path.join(pkg.path, 'tsconfig.json'), tsconfigJSON(pkg)), fs.outputFile(path.join(pkg.path, 'src', 'index.test.ts'), indexTestTS(pkg)), - fs.outputFile(path.join(pkg.path, 'src', 'index.ts'), indexTS(pkg)) + fs.outputFile(path.join(pkg.path, 'src', 'index.ts'), indexTS(pkg)), ]); await execa('npm', ['install'], { stdio: 'inherit' }); // so root lockfile includes new package @@ -73,14 +73,14 @@ async function promptForPackageInfo(cli){ return `Directory "${pkg.path}" already exists! please choose a different name.`; } return true; - } + }, }, { type: 'input', name: 'description', message: 'What does your package do?', - result: (description) => description || '' - } + result: (description) => description || '', + }, ]); return new Pkg({ name, description }); diff --git a/bin/lib/git.mjs b/bin/lib/git.mjs index cfc160f..81c9178 100644 --- a/bin/lib/git.mjs +++ b/bin/lib/git.mjs @@ -25,5 +25,14 @@ export class Git { async log(args, options) { return this.exec(['log', ...args], options); } + + async hasTag(tag, options) { + try { + await this.exec(['rev-parse', '--verify', '--quiet', `refs/tags/${tag}`], options); + return true; + } catch { + return false; + } + } } diff --git a/bin/lib/load-templates.mjs b/bin/lib/load-templates.mjs index f9429ef..2605720 100644 --- a/bin/lib/load-templates.mjs +++ b/bin/lib/load-templates.mjs @@ -20,8 +20,8 @@ export const loadTemplates = async () => { templates[key] = _.template(tmplData, { imports: { camelCase: _.camelCase, - upperFirst: _.upperFirst - } + upperFirst: _.upperFirst, + }, }); } diff --git a/bin/lib/log.mjs b/bin/lib/log.mjs index 214c4f0..bd02283 100644 --- a/bin/lib/log.mjs +++ b/bin/lib/log.mjs @@ -15,7 +15,7 @@ export const logBanner = () => { ' _ | \\___ \\\\ \\ / /| | | |/ _ \\', ' | |_| |___) |\\ V / | | | | __/', ' \\___/|____/ \\_/ |_|_|_|\\___|', - '' + '', ].forEach(log); }; diff --git a/bin/lib/pkg.mjs b/bin/lib/pkg.mjs index 0449345..0ba945d 100644 --- a/bin/lib/pkg.mjs +++ b/bin/lib/pkg.mjs @@ -12,7 +12,6 @@ const README_MARKER_START = ''; const README_MARKER_END = ''; - export class Pkg { static async createFromDisk(name) { const pkg = new Pkg({ name }); @@ -34,6 +33,7 @@ export class Pkg { this.readmePath = path.join(this.path, 'README.md'); this.jsonPath = path.join(this.path, 'package.json'); this.json = null; + this.publishedTag = undefined; this.git = new Git(); } @@ -55,17 +55,36 @@ export class Pkg { return fs.readJson(this.jsonPath); } - async getUnpublishedChanges() { - const { name, basename } = this; + // the tag the last published release is on, or `null` when this repo has + // none - a package that has never been published, or one whose earlier + // versions were published from somewhere else + async getPublishedTag() { + if (this.publishedTag !== undefined) { + return this.publishedTag; + } + let version; try { - ({ stdout: version } = await execa('npm', ['view', name, 'version'])); + ({ stdout: version } = await execa('npm', ['view', this.name, 'version'])); } catch { - version = '0.0.0'; + this.publishedTag = null; + return this.publishedTag; } - const range = `${name}@${version}..HEAD`; + const tag = `${this.name}@${version}`; + + this.publishedTag = await this.git.hasTag(tag) ? tag : null; + + return this.publishedTag; + } + + async getUnpublishedChanges() { + const { basename } = this; + const tag = await this.getPublishedTag(); + // without a published release to diff against, every commit touching + // this package is unpublished + const range = tag ? `${tag}..HEAD` : 'HEAD'; const query = `--grep=\\[${basename}\\]`; const fmt = '--pretty=format:%B'; const prefix = `[${basename}]`; @@ -106,7 +125,7 @@ export class Pkg { lines.push('\n'); return this.writeChangelog( - content.replace(ptn, lines.join('')) + content.replace(ptn, lines.join('')), ); } @@ -132,7 +151,7 @@ export class Pkg { ]; return this.writeReadme( - content.replace(ptn, link.join('\n')) + content.replace(ptn, link.join('\n')), ); } } diff --git a/bin/show-unpublished-changes.mjs b/bin/show-unpublished-changes.mjs index 94af9b5..df56572 100755 --- a/bin/show-unpublished-changes.mjs +++ b/bin/show-unpublished-changes.mjs @@ -7,13 +7,21 @@ import { Pkg } from './lib/pkg.mjs'; try { const args = process.argv.slice(2); const pkg = await Pkg.createFromDisk(args[0].trim()); + const tag = await pkg.getPublishedTag(); const changes = await pkg.getUnpublishedChanges(); logTitle(`${pkg.name} - Unpublished Changes`); + log(tag + ? `:::: since ${tag}` + : ':::: no published release tagged in this repo - showing every change so far'); for (const change of changes) { log(`* ${change}`); } + + if (!changes.length) { + log('* none'); + } } catch (error) { logErrorAndExit(error); } diff --git a/bin/update-readme.mjs b/bin/update-readme.mjs index a2fc810..81157f5 100755 --- a/bin/update-readme.mjs +++ b/bin/update-readme.mjs @@ -13,7 +13,7 @@ const PKGLIST_MARKER_END = ''; try { - logTitle(`Updating package list in top-level README...`); + logTitle('Updating package list in top-level README...'); const pkgs = await getPkgs(PACKAGES_DIR); const listMarkdown = renderPackageList(pkgs); const readme = await fs.readFile(README_PATH, 'utf8'); diff --git a/eslint.config.mjs b/eslint.config.mjs index f8042fc..0e40f33 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,123 +1,32 @@ import path from 'node:path'; -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; -import globals from 'globals'; import { includeIgnoreFile } from '@eslint/compat'; +import bust from '@bust/eslint-config'; -export default tseslint.config( +export default [ includeIgnoreFile(path.join(import.meta.dirname, '.gitignore')), + + ...bust({ nodeTest: true, ignores: ['**/docs/**'] }), + { - ignores: ['**/docs/**'] - }, - js.configs.recommended, - tseslint.configs.recommended, - { - languageOptions: { - ecmaVersion: 2024, - globals: { - ...globals['shared-node-browser'], - ...globals.commonjs, - process: true - } - }, + name: 'jsville/tests', + files: ['**/*.{spec,test,e2e,integration}.{js,mjs,ts,mts}'], rules: { - 'array-bracket-spacing': ['error', 'never'], - 'arrow-spacing': 'error', - 'block-scoped-var': 'error', - 'block-spacing': 'error', - 'brace-style': ['error', '1tbs'], - 'camelcase': ['error', { - properties: 'never' - }], - 'constructor-super': 'error', - 'curly': 'error', - 'eol-last': 'error', - 'eqeqeq': ['error', 'smart'], - 'func-names': ['error', 'as-needed'], - 'func-style': ['error', 'declaration', { - allowArrowFunctions: true - }], - 'indent': ['error', 'tab', { - SwitchCase: 1, - ObjectExpression: 'first', - MemberExpression: 1, - ignoredNodes: ['TemplateLiteral *'] - }], - 'keyword-spacing': ['error', { - before: true, - after: true, - }], - 'max-depth': ['warn', 3], - 'max-len': ['error', { - code: 120, - ignoreComments: true, - ignoreTrailingComments: true, - ignoreUrls: true, - ignoreStrings: true, - ignoreTemplateLiterals: true - }], - 'max-statements': ['warn', 30], - 'new-cap': 'warn', - 'no-class-assign': 'error', - 'no-cond-assign': ['error', 'except-parens'], - 'no-console': 'error', - 'no-const-assign': 'error', - 'no-dupe-class-members': 'error', - 'no-extend-native': 'error', - 'no-extra-parens': ['error', 'functions'], - 'no-mixed-spaces-and-tabs': 'error', - 'no-multi-spaces': ['error', { - exceptions: { - VariableDeclarator: true, - } - }], - 'no-nested-ternary': 'error', - 'no-prototype-builtins': 'off', - 'no-this-before-super': 'error', - 'no-trailing-spaces': 'error', - 'no-undef': 'error', - 'no-underscore-dangle': 'off', - 'no-use-before-define': ['error', { - functions: false, - classes: false - }], - 'no-whitespace-before-property': 'error', - 'no-var': 'error', - 'object-curly-spacing': ['error', 'always'], - 'prefer-const': 'error', - 'quotes': ['error', 'single', { - avoidEscape: true, - allowTemplateLiterals: true - }], - 'semi': ['error', 'always'], - 'space-in-parens': ['error', 'never'], - 'space-infix-ops': 'error', - 'space-unary-ops': ['error', { - words: true, - nonwords: false - }], - 'strict': ['error', 'global'] - } + 'func-names': 'off', + }, }, + { - files: [ - '**/*.spec.js', - '**/*.test.js', - '**/*.e2e.js', - '**/*.integration.js', - '**/*.spec.ts', - '**/*.test.ts', - '**/*.e2e.ts', - '**/*.integration.ts', - ], + name: 'jsville/prototype-builtins', rules: { - 'func-names': 'off' - } + 'no-prototype-builtins': 'off', + }, }, + { + name: 'jsville/logger', files: ['bin/lib/log.mjs'], rules: { - 'no-console': 'off' - } - } -); + 'no-console': 'off', + }, + }, +]; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 3223044..2bca03b 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -37,7 +37,6 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", @@ -48,20 +47,257 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@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-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@bust/config": { "resolved": "packages/config", "link": true }, + "node_modules/@bust/eslint-config": { + "resolved": "packages/eslint-config", + "link": true + }, "node_modules/@bust/numeric-id-hasher": { "resolved": "packages/numeric-id-hasher", "link": true @@ -146,7 +382,6 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -165,7 +400,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -178,12 +412,153 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint-react/ast": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-5.18.6.tgz", + "integrity": "sha512-okgOez6L9onvcdU0lyLOykKQSaj2hMtVV2ucx2iqmTsfKDGyhVlMuNLnfyOkgQyHdgfROTVtAAYnQ6KPf7PggQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/typescript-estree": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "string-ts": "^2.3.1" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/core": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-5.18.6.tgz", + "integrity": "sha512-utvjmfgy/lMSMt4QSU5QK2coHk6tkRChxLmkW6z8sthgmB6138CYzC3cPR9kze5pOgYJouF95xiaPnHKnXx21A==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/scope-manager": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/eslint": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/eslint/-/eslint-5.18.6.tgz", + "integrity": "sha512-8BzLB6mtIDmAIwAt1u4g6Yp+1LSGAnqm8SGNHbyZG1sQikWW9Fskv3fx5Zy6CGMV9D7gafcHTiVTcuBYNE+87w==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.67.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/eslint-plugin": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/eslint-plugin/-/eslint-plugin-5.18.6.tgz", + "integrity": "sha512-qBZXKx05CPNrvdNydM958rZt2hgVhhriU/8LUeS5s/5gdpuekflrfF+y3yT4NT8Ej3J37h7e50RdH6Lu1r0KPg==", + "license": "MIT", + "dependencies": { + "@eslint-react/shared": "5.18.6", + "eslint-plugin-react-dom": "5.18.6", + "eslint-plugin-react-jsx": "5.18.6", + "eslint-plugin-react-naming-convention": "5.18.6", + "eslint-plugin-react-rsc": "5.18.6", + "eslint-plugin-react-web-api": "5.18.6", + "eslint-plugin-react-x": "5.18.6" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/jsx": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/jsx/-/jsx-5.18.6.tgz", + "integrity": "sha512-oAbG2pW6XhiROZotfSjLU19A84/AxYHiiKjim5USHH5xtYfYjO7skFSM6LztuPggqn/wccSxLgmKIFGUKM/95g==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/shared": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-5.18.6.tgz", + "integrity": "sha512-zCzb/W1xwG412BWVTjqhDznsJEHdyZVkVJz4jbAebHLpKxygK5XeG+vShdYbIFC7OcJU8hYbvEf3P2UNqXVhBw==", + "license": "MIT", + "dependencies": { + "@eslint-react/eslint": "5.18.6", + "@typescript-eslint/utils": "^8.67.0", + "ts-pattern": "^5.9.0", + "zod": "^3.25.0 || ^4.0.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/@eslint-react/var": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-5.18.6.tgz", + "integrity": "sha512-5pxFlOy0Ajx+JUz4I4PwnYtOrqcj/R59Gx9m/WWjukFza/ap3FYnu8vEl2Q0txUQoUPJ7euPnBhkKOE7LhsOWA==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@typescript-eslint/scope-manager": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, "node_modules/@eslint/compat": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.1.0.tgz", @@ -209,7 +584,6 @@ "version": "0.23.5", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^3.0.5", @@ -224,7 +598,6 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1" @@ -237,7 +610,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -250,7 +622,6 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", - "dev": true, "license": "MIT", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -271,7 +642,6 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -281,7 +651,6 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^1.2.1", @@ -319,7 +688,6 @@ "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/types": "^0.15.0" @@ -332,7 +700,6 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.2", @@ -347,7 +714,6 @@ "version": "0.15.0", "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -357,7 +723,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -371,7 +736,6 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -771,6 +1135,51 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", @@ -2264,6 +2673,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin/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==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", @@ -2302,14 +2760,12 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, "license": "MIT" }, "node_modules/@types/hast": { @@ -2326,7 +2782,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/node": { @@ -2347,17 +2802,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", - "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz", + "integrity": "sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/type-utils": "8.65.0", - "@typescript-eslint/utils": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/type-utils": "8.68.0", + "@typescript-eslint/utils": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2370,7 +2824,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.65.0", + "@typescript-eslint/parser": "^8.68.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -2379,23 +2833,21 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", - "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.68.0.tgz", + "integrity": "sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3" }, "engines": { @@ -2411,14 +2863,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", - "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.68.0.tgz", + "integrity": "sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.65.0", - "@typescript-eslint/types": "^8.65.0", + "@typescript-eslint/tsconfig-utils": "^8.68.0", + "@typescript-eslint/types": "^8.68.0", "debug": "^4.4.3" }, "engines": { @@ -2433,14 +2884,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", - "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.68.0.tgz", + "integrity": "sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0" + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2451,10 +2901,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", - "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.68.0.tgz", + "integrity": "sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2468,15 +2917,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", - "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz", + "integrity": "sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2493,10 +2941,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", - "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.68.0.tgz", + "integrity": "sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2507,16 +2954,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", - "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.68.0.tgz", + "integrity": "sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.65.0", - "@typescript-eslint/tsconfig-utils": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/project-service": "8.68.0", + "@typescript-eslint/tsconfig-utils": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2538,7 +2984,6 @@ "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2551,7 +2996,6 @@ "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -2565,16 +3009,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", - "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.68.0.tgz", + "integrity": "sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0" + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2589,13 +3032,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", - "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.68.0.tgz", + "integrity": "sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/types": "8.68.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2747,6 +3189,36 @@ "node": ">=16.20.0" } }, + "node_modules/@vitest/eslint-plugin": { + "version": "1.6.27", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.27.tgz", + "integrity": "sha512-X1RCAfwbatG4GFbJ/1PIHP9MSZMt0JJThqbYID+vS4L783k6QGlLPe421wQE8dHXuGCcenVLsydiM4qzsYWxhg==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "^8.58.0", + "@typescript-eslint/utils": "^8.58.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "*", + "eslint": ">=8.57.0", + "typescript": ">=5.0.0", + "vitest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -2781,7 +3253,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2794,7 +3265,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -2828,7 +3298,6 @@ "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2948,7 +3417,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -2975,6 +3443,18 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.19.tgz", + "integrity": "sha512-Grytf1xOxOEMTGRwx6rLGKkTabd4vMg3VrKdj/7joCmV0qgh4QwMMO6xh34YEXQqirAuUdgQGa5orJQQ+69RBw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -3033,6 +3513,12 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/birecord": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.2.tgz", + "integrity": "sha512-5PAPTTmMpMEb+GuMb5DebfBkipRGyIW9+gtwEBSoDA9xkhHILm04+hZQ702pMksu3d8YAuGkmgTzQWcKqTPScA==", + "license": "(MIT OR Apache-2.0)" + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -3049,7 +3535,6 @@ "version": "5.0.9", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -3058,6 +3543,39 @@ "node": "20 || >=22" } }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -3184,6 +3702,26 @@ "node": ">=6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3403,6 +3941,12 @@ "dev": true, "license": "ISC" }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3523,6 +4067,12 @@ "node": ">=22" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", @@ -3554,7 +4104,6 @@ "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", @@ -3582,7 +4131,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3615,7 +4163,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, "license": "MIT" }, "node_modules/default-browser": { @@ -3758,6 +4305,12 @@ "node": ">=0.12.18" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.413", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.413.tgz", + "integrity": "sha512-F1XPKvt7HVfly5WND90ec16nFsdr4g5x/cVUP3EqjeyXynupabGDqpMa84wwvuYGDnldXLBz6DLXyZXWO9TPvw==", + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3920,7 +4473,6 @@ "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" @@ -3930,7 +4482,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3943,7 +4494,6 @@ "version": "10.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz", "integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==", - "dev": true, "license": "MIT", "workspaces": [ "packages/*" @@ -3998,11 +4548,172 @@ } } }, + "node_modules/eslint-plugin-react-dom": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-dom/-/eslint-plugin-react-dom-5.18.6.tgz", + "integrity": "sha512-xco47I0Agu+83QH2ONbgZd1JPLSXJON+gtFGJbOhgfPvetfO7UkcHu8iLpncopwyWekAXfhvomJsDlNLTm26/g==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/jsx": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "compare-versions": "^6.1.1" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-jsx": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-jsx/-/eslint-plugin-react-jsx-5.18.6.tgz", + "integrity": "sha512-6EvzS5gZGfQ0byvSxgqV/F0qXTVnNGcCU7wgFZqz8I1IXmcbYyBCyU7gqNlKW1/1ptiZFmuwo57+eW6HyK+wEg==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/core": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/jsx": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/eslint-plugin-react-naming-convention": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-naming-convention/-/eslint-plugin-react-naming-convention-5.18.6.tgz", + "integrity": "sha512-3KZkJN8XDTq6YtaYvyWJt3GQRjW3WhoVuGgLfhf0yO+8H0GW78FkesqGe//+np+pBXwPv6hck4c8ViTEQJ9qIQ==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/core": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/eslint-plugin-react-rsc": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-rsc/-/eslint-plugin-react-rsc-5.18.6.tgz", + "integrity": "sha512-4mzLkRKRpN9Rr5JMeNrxkMFLHce1ikAdsjAiPOSIgYwWSsQWxHwpMTf+UfjXgfB6CcAcyKCyIe5HmOMX2kUoVQ==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/core": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/eslint-plugin-react-web-api": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-web-api/-/eslint-plugin-react-web-api-5.18.6.tgz", + "integrity": "sha512-r8s39AbHZ0071XcgCMoCdNkSARftqI6U/0bBJXPioVUw+hjp0n4EB27fsc69AHzRl/NJWA1oUJb+kcqxoWMR4w==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/core": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "birecord": "^0.1.2", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, + "node_modules/eslint-plugin-react-x": { + "version": "5.18.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-x/-/eslint-plugin-react-x-5.18.6.tgz", + "integrity": "sha512-VvxeREksTiY9Q7YnpNvQNrjapUGu43rQJXrtbjT9ADwXX5nZiyUqD7T7fkbUYfH6NPz2bYvnAmGEctIfEGTTfQ==", + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "5.18.6", + "@eslint-react/core": "5.18.6", + "@eslint-react/eslint": "5.18.6", + "@eslint-react/jsx": "5.18.6", + "@eslint-react/shared": "5.18.6", + "@eslint-react/var": "5.18.6", + "@typescript-eslint/scope-manager": "^8.67.0", + "@typescript-eslint/type-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/typescript-estree": "^8.67.0", + "@typescript-eslint/utils": "^8.67.0", + "compare-versions": "^6.1.1", + "string-ts": "^2.3.1", + "ts-api-utils": "^2.5.0", + "ts-pattern": "^5.9.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "eslint": "*", + "typescript": "*" + } + }, "node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "@types/esrecurse": "^4.3.1", @@ -4021,7 +4732,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -4034,7 +4744,6 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.16.0", @@ -4052,7 +4761,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -4065,7 +4773,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -4078,7 +4785,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -4088,7 +4794,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -4139,21 +4844,18 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "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", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, "license": "MIT" }, "node_modules/fd-package-json": { @@ -4170,7 +4872,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -4204,7 +4905,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -4217,7 +4917,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -4244,7 +4943,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -4258,7 +4956,6 @@ "version": "3.4.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", - "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -4375,6 +5072,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4484,7 +5190,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -4494,10 +5199,9 @@ } }, "node_modules/globals": { - "version": "17.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.9.0.tgz", - "integrity": "sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==", - "dev": true, + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", "license": "MIT", "engines": { "node": ">=18" @@ -4600,6 +5304,21 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/hosted-git-info": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", @@ -4700,7 +5419,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -4760,7 +5478,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -4873,7 +5590,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4893,7 +5609,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5000,7 +5715,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/jackspeak": { @@ -5023,7 +5737,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -5049,11 +5762,22 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -5070,14 +5794,12 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, "license": "MIT" }, "node_modules/json-stringify-nice": { @@ -5094,7 +5816,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -5160,7 +5881,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -5355,7 +6075,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -5722,7 +6441,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -5900,7 +6618,6 @@ "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.8" @@ -6095,7 +6812,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mute-stream": { @@ -6131,7 +6847,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, "license": "MIT" }, "node_modules/negotiator": { @@ -6238,6 +6953,15 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/nopt": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", @@ -6831,7 +7555,6 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -6896,7 +7619,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -6912,7 +7634,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -7248,7 +7969,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7258,7 +7978,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7285,14 +8004,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7430,7 +8147,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -7540,7 +8256,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7847,7 +8562,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -7860,7 +8574,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8030,6 +8743,12 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-ts": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.3.1.tgz", + "integrity": "sha512-xSJq+BS52SaFFAVxuStmx6n5aYZU571uYUnUrPXkPFCfdHyZMMlbP2v2Wx5sNBnAVzq/2+0+mcBLBa3Xa5ubYw==", + "license": "MIT" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8191,7 +8910,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18.12" @@ -8200,6 +8918,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-pattern": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.9.0.tgz", + "integrity": "sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==", + "license": "MIT" + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -8292,7 +9016,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -8352,7 +9075,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -8363,16 +9085,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", - "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", - "dev": true, + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.68.0.tgz", + "integrity": "sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.65.0", - "@typescript-eslint/parser": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0" + "@typescript-eslint/eslint-plugin": "8.68.0", + "@typescript-eslint/parser": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8454,11 +9175,40 @@ "node": ">= 10.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -8611,7 +9361,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -8643,7 +9392,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8761,7 +9509,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -8796,9 +9543,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "packages/config": { "name": "@bust/config", - "version": "0.0.0", + "version": "0.2.0", "license": "(MIT OR Apache-2.0)", "dependencies": { "dotenv": "^17.4.2" @@ -8823,9 +9591,27 @@ "url": "https://dotenvx.com" } }, + "packages/eslint-config": { + "name": "@bust/eslint-config", + "version": "0.0.0", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@eslint-react/eslint-plugin": "^5.18.6", + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@vitest/eslint-plugin": "^1.6.27", + "eslint-plugin-react-hooks": "^7.1.1", + "globals": "^17.11.0", + "typescript-eslint": "^8.68.0" + }, + "engines": { + "node": ">=22", + "npm": ">=10" + } + }, "packages/numeric-id-hasher": { "name": "@bust/numeric-id-hasher", - "version": "2.0.0", + "version": "2.0.1", "license": "(MIT OR Apache-2.0)", "engines": { "node": ">=22", @@ -8834,7 +9620,7 @@ }, "packages/periodical": { "name": "@bust/periodical", - "version": "2.0.0", + "version": "2.0.1", "license": "(MIT OR Apache-2.0)", "engines": { "node": ">=22", @@ -8843,7 +9629,7 @@ }, "packages/timer": { "name": "@bust/timer", - "version": "2.0.0", + "version": "2.0.1", "license": "(MIT OR Apache-2.0)", "engines": { "node": ">=22", diff --git a/packages/config/src/config.test.ts b/packages/config/src/config.test.ts index 093233a..d7f26bd 100644 --- a/packages/config/src/config.test.ts +++ b/packages/config/src/config.test.ts @@ -3,7 +3,7 @@ // values to exercise runtime validation, which fights static typing by design. import { describe, it, beforeEach } from 'node:test'; import { strict as assert } from 'node:assert'; -import { Config, ConfigEnvVars } from './config.js'; +import { Config, type ConfigEnvVars } from './config.js'; describe('@bust/config', () => { @@ -50,7 +50,7 @@ describe('@bust/config', () => { assert.throws( () => config.get('NOPE!'), { - 'message': '\'NOPE!\' is not available - please ensure you\'ve set it' + 'message': '\'NOPE!\' is not available - please ensure you\'ve set it', }, ); }); @@ -191,8 +191,8 @@ describe('@bust/config', () => { assert.throws( () => config.hydrate(schema), { - message: '\'test\' uses an unrecognized format: NOPE!' - } + message: '\'test\' uses an unrecognized format: NOPE!', + }, ); }); @@ -205,7 +205,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\' is missing - please set it!', - } + }, ); }); @@ -219,7 +219,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be one of a|b|c', - } + }, ); schema.test.default = 'a'; @@ -228,7 +228,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be one of a|b|c', - } + }, ); schema.test.default = 'a'; @@ -249,7 +249,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be an integer', - } + }, ); schema.test.default = 1.1; @@ -258,7 +258,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be an integer', - } + }, ); schema.test.default = 1; @@ -267,7 +267,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be an integer', - } + }, ); schema.test.default = 1; @@ -288,7 +288,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a positive integer', - } + }, ); schema.test.default = -1; @@ -297,7 +297,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a positive integer', - } + }, ); schema.test.default = 1.0; @@ -306,7 +306,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be a positive integer', - } + }, ); schema.test.default = 1.0; @@ -327,7 +327,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a number', - } + }, ); schema.test.default = -1.5; @@ -336,7 +336,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be a number', - } + }, ); schema.test.default = -1.5; @@ -357,7 +357,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a valid url', - } + }, ); schema.test.default = 'http://example.com'; @@ -366,7 +366,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be a valid url', - } + }, ); schema.test.default = 'http://example.com'; @@ -387,7 +387,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a boolean', - } + }, ); schema.test.default = false; @@ -407,7 +407,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a string', - } + }, ); schema.test.default = 'ok'; @@ -427,7 +427,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be a regular expression (RegExp)', - } + }, ); schema.test.default = /ok/; @@ -447,7 +447,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be an object', - } + }, ); schema.test.default = {}; @@ -456,7 +456,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be an object', - } + }, ); schema.test.default = {}; @@ -476,7 +476,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be an array', - } + }, ); schema.test.default = 'one,two,three'; @@ -485,7 +485,7 @@ describe('@bust/config', () => { () => config.hydrate(schema), { message: '\'test\': must be an array', - } + }, ); const env = { TEST: false }; @@ -495,7 +495,7 @@ describe('@bust/config', () => { () => config.hydrate(schema, env), { message: '\'test\': must be an array', - } + }, ); schema.test.default = []; diff --git a/packages/eslint-config/.tshy/build.json b/packages/eslint-config/.tshy/build.json new file mode 100644 index 0000000..aea1a9e --- /dev/null +++ b/packages/eslint-config/.tshy/build.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "../src", + "module": "nodenext", + "moduleResolution": "nodenext" + } +} diff --git a/packages/eslint-config/.tshy/esm.json b/packages/eslint-config/.tshy/esm.json new file mode 100644 index 0000000..959294a --- /dev/null +++ b/packages/eslint-config/.tshy/esm.json @@ -0,0 +1,15 @@ +{ + "extends": "./build.json", + "include": [ + "../src/**/*.ts", + "../src/**/*.mts", + "../src/**/*.tsx", + "../src/**/*.json" + ], + "exclude": [ + "../src/package.json" + ], + "compilerOptions": { + "outDir": "../.tshy-build/esm" + } +} diff --git a/packages/eslint-config/CHANGELOG.md b/packages/eslint-config/CHANGELOG.md new file mode 100644 index 0000000..e816b34 --- /dev/null +++ b/packages/eslint-config/CHANGELOG.md @@ -0,0 +1,3 @@ +# `@bust/eslint-config` Changelog + + diff --git a/packages/eslint-config/LICENSE.md b/packages/eslint-config/LICENSE.md new file mode 100644 index 0000000..97e7b62 --- /dev/null +++ b/packages/eslint-config/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 Busticated + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/packages/eslint-config/README.md b/packages/eslint-config/README.md new file mode 100644 index 0000000..b0d5cb6 --- /dev/null +++ b/packages/eslint-config/README.md @@ -0,0 +1,86 @@ +# `@bust/eslint-config` + +Shared ESLint configuration for Busticated JS/TS projects + + +## Installation + +```shell +npm install @bust/eslint-config --save-dev +``` + +`eslint` is a peer dependency - everything else this config needs (`typescript-eslint`, `@stylistic`, the React and Vitest plugins) ships with it, so there is nothing else to install. + + +## Usage + +Call the factory from your `eslint.config.js` and export the result. It targets TypeScript by default, with type-aware rules on. + +```js +// eslint.config.js +import bust from '@bust/eslint-config'; + +export default bust(); +``` + +Options turn on the layers a project needs: + +```js +export default bust({ + react: true, + vitest: true, + ignores: ['.output/', '.nitro/'], +}); +``` + +### JavaScript-only projects + +`typescript: false` drops `typescript-eslint` and the type-aware rules, keeping the same core and stylistic rules with the built-in `no-unused-vars` and `no-use-before-define` in place of their TS-aware equivalents. + +```js +export default bust({ typescript: false }); +``` + +### Test runners + +`vitest: true` adds Vitest's recommended rules. `nodeTest: true` is for projects on `node:test`, where `describe()` and `it()` return promises nobody awaits - it relaxes `no-floating-promises` across the spec, test, e2e, and integration suites, and does nothing when the type-aware rules are off. + +### Type-aware rules + +These are on by default and need your `tsconfig.json` to cover every file being linted. A file the tsconfig lists but excludes - an `eslint.config.js` in a project without `allowJs`, say - needs naming explicitly: + +```js +export default bust({ allowDefaultProject: ['eslint.config.js'] }); +``` + +Turn them off with `typeAware: false` if a project's tsconfig isn't ready for it. + +### Overriding + +The factory returns a flat-config array, so append your own blocks - later blocks win: + +```js +export default [ + ...bust(), + { + files: ['bin/**'], + rules: { 'no-console': 'off' }, + }, +]; +``` + +Every block this package contributes is named `bust/*`, so `npx eslint --inspect-config` will tell you which one applied a given rule. + + +## API + +see [here](https://github.com/busticated/jsville/tree/%40bust%2Feslint-config%400.0.0/packages/eslint-config/docs) + + +_NOTE: When in doubt, check usage in [tests](./src/index.test.ts)_ + + +## License + +_See [LICENSE.md](./LICENSE.md)_ + diff --git a/packages/eslint-config/docs/README.md b/packages/eslint-config/docs/README.md new file mode 100644 index 0000000..9159b06 --- /dev/null +++ b/packages/eslint-config/docs/README.md @@ -0,0 +1,23 @@ +**@bust/eslint-config** + +*** + +# @bust/eslint-config + +## Interfaces + +- [BustConfigOptions](interfaces/BustConfigOptions.md) + +## Variables + +- [DEFAULT\_IGNORES](variables/DEFAULT_IGNORES.md) + +## Functions + +- [bust](functions/bust.md) + +## References + +### default + +Renames and re-exports [bust](functions/bust.md) diff --git a/packages/eslint-config/docs/functions/bust.md b/packages/eslint-config/docs/functions/bust.md new file mode 100644 index 0000000..c365ca4 --- /dev/null +++ b/packages/eslint-config/docs/functions/bust.md @@ -0,0 +1,42 @@ +[**@bust/eslint-config**](../README.md) + +*** + +# Function: bust() + +> **bust**(`options?`): `Config`\<`RulesConfig`\>[] + +Defined in: [index.ts:130](/packages/eslint-config/src/index.ts#L130) + +Builds the shared ESLint configuration. + +Returns a flat-config array ready to export. Every block is named, so +`eslint --inspect-config` reports which one applied a rule. Append your own +blocks to override anything - later blocks win. + +## Parameters + +### options? + +[`BustConfigOptions`](../interfaces/BustConfigOptions.md) = `{}` + +## Returns + +`Config`\<`RulesConfig`\>[] + +## Examples + +```js +// eslint.config.js +import bust from '@bust/eslint-config'; + +export default bust({ react: true, vitest: true, ignores: ['.output/'] }); +``` + +```js +// a JS-only project, with one rule relaxed +export default [ + ...bust({ typescript: false }), + { files: ['bin/**'], rules: { 'no-console': 'off' } }, +]; +``` diff --git a/packages/eslint-config/docs/interfaces/BustConfigOptions.md b/packages/eslint-config/docs/interfaces/BustConfigOptions.md new file mode 100644 index 0000000..89c9e3c --- /dev/null +++ b/packages/eslint-config/docs/interfaces/BustConfigOptions.md @@ -0,0 +1,132 @@ +[**@bust/eslint-config**](../README.md) + +*** + +# Interface: BustConfigOptions + +Defined in: [index.ts:31](/packages/eslint-config/src/index.ts#L31) + +Options accepted by [bust](../functions/bust.md). + +## Properties + +### allowDefaultProject? + +> `optional` **allowDefaultProject?**: `string`[] + +Defined in: [index.ts:80](/packages/eslint-config/src/index.ts#L80) + +Files to type-check outside the project's `tsconfig.json` - an +`eslint.config.js` that the tsconfig lists but `allowJs` excludes, for +instance. + +*** + +### ignores? + +> `optional` **ignores?**: `string`[] + +Defined in: [index.ts:82](/packages/eslint-config/src/index.ts#L82) + +Paths to ignore, added to [DEFAULT\_IGNORES](../variables/DEFAULT_IGNORES.md). + +*** + +### nodeTest? + +> `optional` **nodeTest?**: `boolean` + +Defined in: [index.ts:68](/packages/eslint-config/src/index.ts#L68) + +Relax the type-aware rules that Node's test runner trips over. Has no +effect without `typeAware`, which is what turns those rules on. + +#### Default Value + +```ts +false +``` + +*** + +### react? + +> `optional` **react?**: `boolean` + +Defined in: [index.ts:55](/packages/eslint-config/src/index.ts#L55) + +Add React rules: `@eslint-react` plus the hooks plugin, and the JSX +half of the stylistic rules. + +#### Default Value + +```ts +false +``` + +*** + +### tsconfigRootDir? + +> `optional` **tsconfigRootDir?**: `string` + +Defined in: [index.ts:74](/packages/eslint-config/src/index.ts#L74) + +Where the type-aware project service looks for `tsconfig.json`. + +#### Default Value + +`process.cwd()` + +*** + +### typeAware? + +> `optional` **typeAware?**: `boolean` + +Defined in: [index.ts:48](/packages/eslint-config/src/index.ts#L48) + +Add the rules that need type information - the ones that catch a +promise nobody awaited. Requires `typescript`, and requires the +project's `tsconfig.json` to cover every linted file. + +#### Default Value + +```ts +true +``` + +*** + +### typescript? + +> `optional` **typescript?**: `boolean` + +Defined in: [index.ts:40](/packages/eslint-config/src/index.ts#L40) + +Lint TypeScript. Adds `typescript-eslint`'s recommended rules and the +TS-aware variants of `no-unused-vars` and `no-use-before-define`. +Turning this off yields the JS-only configuration - the same rules, +minus anything that needs a TypeScript parser. + +#### Default Value + +```ts +true +``` + +*** + +### vitest? + +> `optional` **vitest?**: `boolean` + +Defined in: [index.ts:61](/packages/eslint-config/src/index.ts#L61) + +Add Vitest's recommended rules, scoped to `*.test.*` files. + +#### Default Value + +```ts +false +``` diff --git a/packages/eslint-config/docs/variables/DEFAULT_IGNORES.md b/packages/eslint-config/docs/variables/DEFAULT_IGNORES.md new file mode 100644 index 0000000..3a72775 --- /dev/null +++ b/packages/eslint-config/docs/variables/DEFAULT_IGNORES.md @@ -0,0 +1,11 @@ +[**@bust/eslint-config**](../README.md) + +*** + +# Variable: DEFAULT\_IGNORES + +> `const` **DEFAULT\_IGNORES**: `string`[] + +Defined in: [index.ts:14](/packages/eslint-config/src/index.ts#L14) + +Build output and scratch directories every project here ignores. diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json new file mode 100644 index 0000000..8cb5c53 --- /dev/null +++ b/packages/eslint-config/package.json @@ -0,0 +1,73 @@ +{ + "name": "@bust/eslint-config", + "description": "Shared ESLint configuration for Busticated JS/TS projects", + "version": "0.0.0", + "author": "Busticated", + "license": "(MIT OR Apache-2.0)", + "keywords": [ + "eslint", + "eslintconfig", + "eslint-config", + "typescript", + "flat-config" + ], + "publishConfig": { + "access": "public" + }, + "type": "module", + "module": "./dist/esm/index.js", + "files": [ + "CHANGELOG.md", + "LICENSE.md", + "dist/**/!(*.test.js)" + ], + "tshy": { + "dialects": [ + "esm" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + } + } + }, + "scripts": { + "version": "npm run changelog:update && npm run docs:build", + "prepare": "npm run build", + "test:unit": "npm run build && node --test --test-reporter spec --experimental-test-coverage --test-coverage-lines=99 --test-coverage-branches=100 --test-coverage-functions=100 --enable-source-maps dist/esm/*.test.js", + "test:e2e": "echo \"Zero e2e tests to run!\" && exit 0", + "typecheck": "tsc --project .tshy/esm.json --noemit", + "build": "tshy", + "clean": "rm -rf ./dist && rm -rf ./tmp/*", + "clean:modules": "rm -rf ./node_modules", + "docs:build": "npm run docs:build:api && npm run docs:build:readme", + "docs:build:api": "typedoc --plugin typedoc-plugin-markdown --hideBreadcrumbs true --githubPages false --sourceLinkTemplate '/{path}#L{line}' --readme none src/index.ts", + "docs:build:readme": "node ../../bin/update-package-readme.mjs @bust/eslint-config", + "changelog:show": "node ../../bin/show-unpublished-changes.mjs @bust/eslint-config", + "changelog:update": "node ../../bin/update-changelog.mjs @bust/eslint-config" + }, + "engines": { + "node": ">=22", + "npm": ">=10" + }, + "dependencies": { + "@eslint-react/eslint-plugin": "^5.18.6", + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@vitest/eslint-plugin": "^1.6.27", + "eslint-plugin-react-hooks": "^7.1.1", + "globals": "^17.11.0", + "typescript-eslint": "^8.68.0" + }, + "peerDependencies": { + "eslint": ">=10" + } +} diff --git a/packages/eslint-config/src/index.test.ts b/packages/eslint-config/src/index.test.ts new file mode 100644 index 0000000..1e21968 --- /dev/null +++ b/packages/eslint-config/src/index.test.ts @@ -0,0 +1,188 @@ +import { describe, it } from 'node:test'; +import { strict as assert } from 'node:assert'; +import { Linter } from 'eslint'; +import type { Linter as LinterTypes } from 'eslint'; +import { bust, DEFAULT_IGNORES } from './index.js'; + + +describe('@bust/eslint-config', () => { + describe('Default options', () => { + it('Targets TypeScript, with type-aware rules and no framework blocks', () => { + const names = namesOf(bust()); + assert.deepEqual(names, [ + 'bust/ignores', + 'bust/base', + 'bust/typescript', + 'bust/type-aware', + ]); + }); + + it('Turns the project service on and roots it at the working directory', () => { + const block = blockNamed(bust(), 'bust/type-aware'); + assert.deepEqual(block.files, ['**/*.{ts,tsx,mts,cts}']); + assert.deepEqual(parserOptionsOf(block), { + projectService: true, + tsconfigRootDir: process.cwd(), + }); + }); + + it('Registers the TypeScript-aware variants of the shared rules', () => { + const rules = rulesOf(blockNamed(bust(), 'bust/typescript')); + assert.ok(rules['@typescript-eslint/no-unused-vars']); + assert.ok(rules['@typescript-eslint/no-use-before-define']); + assert.equal(rules['no-use-before-define'], 'off'); + }); + }); + + describe('Ignores', () => { + it('Ignores build output by default', () => { + const block = blockNamed(bust(), 'bust/ignores'); + assert.deepEqual(block.ignores, DEFAULT_IGNORES); + }); + + it('Appends the paths a project passes in', () => { + const block = blockNamed(bust({ ignores: ['.output/'] }), 'bust/ignores'); + assert.deepEqual(block.ignores, [...DEFAULT_IGNORES, '.output/']); + }); + }); + + describe('JavaScript-only projects', () => { + it('Drops the TypeScript blocks and keeps the core rules', () => { + const names = namesOf(bust({ typescript: false })); + assert.deepEqual(names, ['bust/ignores', 'bust/base', 'bust/javascript']); + }); + + it('Falls back to the core `no-unused-vars` with the same options', () => { + const rules = rulesOf(blockNamed(bust({ typescript: false }), 'bust/javascript')); + assert.deepEqual(rules['no-unused-vars'], ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }]); + }); + + it('Reports the shared rules against real source', () => { + const messages = new Linter().verify( + 'var x = 1\n', + bust({ typescript: false }) as LinterTypes.Config[], + 'example.js', + ); + const ruleIds = messages.map((message) => message.ruleId).sort(); + assert.deepEqual(ruleIds, ['@stylistic/semi', 'no-unused-vars', 'no-var']); + }); + }); + + describe('Type-aware rules', () => { + it('Can be turned off on their own', () => { + const names = namesOf(bust({ typeAware: false })); + assert.deepEqual(names, ['bust/ignores', 'bust/base', 'bust/typescript']); + }); + + it('Are skipped entirely for a JavaScript-only project', () => { + const names = namesOf(bust({ typescript: false, typeAware: true })); + assert.equal(names.includes('bust/type-aware'), false); + }); + + it('Carry the files a project type-checks outside its tsconfig', () => { + const block = blockNamed( + bust({ allowDefaultProject: ['eslint.config.js'] }), + 'bust/type-aware', + ); + assert.deepEqual(parserOptionsOf(block).projectService, { + allowDefaultProject: ['eslint.config.js'], + }); + }); + + it('Root the project service where the project says', () => { + const block = blockNamed(bust({ tsconfigRootDir: '/somewhere' }), 'bust/type-aware'); + assert.equal(parserOptionsOf(block).tsconfigRootDir, '/somewhere'); + }); + }); + + describe('React', () => { + it('Adds the react, jsx-stylistic, and hooks blocks', () => { + const names = namesOf(bust({ react: true })); + assert.equal(names.includes('bust/react'), true); + assert.equal(names.includes('bust/react-stylistic'), true); + assert.equal(names.includes('bust/react-hooks'), true); + }); + + it('Scopes the react blocks to jsx and tsx', () => { + const block = blockNamed(bust({ react: true }), 'bust/react-stylistic'); + assert.deepEqual(block.files, ['**/*.{jsx,tsx}']); + }); + + it('Uses the plain react rules when there is no TypeScript', () => { + const configs = bust({ typescript: false, react: true }); + const block = blockNamed(configs, 'bust/react'); + assert.ok(block.plugins); + }); + }); + + describe('Node test runner', () => { + it('Relaxes the type-aware rule its `describe()` and `it()` trip', () => { + const block = blockNamed(bust({ nodeTest: true }), 'bust/node-test'); + assert.equal(rulesOf(block)['@typescript-eslint/no-floating-promises'], 'off'); + }); + + it('Covers the spec, e2e, and integration suites too', () => { + const block = blockNamed(bust({ nodeTest: true }), 'bust/node-test'); + assert.deepEqual(block.files, ['**/*.{spec,test,e2e,integration}.{js,jsx,ts,tsx,mjs,mts}']); + }); + + it('Is skipped when there are no type-aware rules to relax', () => { + const names = namesOf(bust({ nodeTest: true, typeAware: false })); + assert.equal(names.includes('bust/node-test'), false); + }); + + it('Is absent unless asked for', () => { + assert.equal(namesOf(bust()).includes('bust/node-test'), false); + }); + }); + + describe('Vitest', () => { + it('Adds a block scoped to test files', () => { + const block = blockNamed(bust({ vitest: true }), 'bust/vitest'); + assert.deepEqual(block.files, ['**/*.test.{js,jsx,ts,tsx,mjs,mts}']); + assert.ok(block.rules); + }); + + it('Is absent unless asked for', () => { + assert.equal(namesOf(bust()).includes('bust/vitest'), false); + }); + }); + + // the plugin configs we compose carry their own names; these assertions are + // about the blocks this package contributes + function namesOf(configs: LinterTypes.Config[]): string[] { + const names: string[] = []; + + for (const config of configs) { + const name = String(config.name); + + if (name.startsWith('bust/')) { + names.push(name); + } + } + + return names; + } + + // these read blocks this package builds, so they skip the optional-chaining + // fallbacks - unreachable branches cost branch coverage on node 22, which + // counts test files where node 24 does not + function parserOptionsOf(config: LinterTypes.Config): Record { + const { languageOptions } = config as { languageOptions: { parserOptions: Record } }; + return languageOptions.parserOptions; + } + + function rulesOf(config: LinterTypes.Config): Record { + return (config as { rules: Record }).rules; + } + + function blockNamed(configs: LinterTypes.Config[], name: string): LinterTypes.Config { + const found = configs.find((config) => config.name === name); + assert.ok(found, `expected a block named '${name}'`); + return found; + } +}); diff --git a/packages/eslint-config/src/index.ts b/packages/eslint-config/src/index.ts new file mode 100644 index 0000000..8a8fbf5 --- /dev/null +++ b/packages/eslint-config/src/index.ts @@ -0,0 +1,317 @@ +import type { Linter } from 'eslint'; +import js from '@eslint/js'; +import eslintReact from '@eslint-react/eslint-plugin'; +import stylistic from '@stylistic/eslint-plugin'; +import vitest from '@vitest/eslint-plugin'; +import reactHooks from 'eslint-plugin-react-hooks'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +/** Files Node's test runner drives - it owns the e2e and integration suites too. */ +const NODE_TEST_FILES = ['**/*.{spec,test,e2e,integration}.{js,jsx,ts,tsx,mjs,mts}']; + +/** Build output and scratch directories every project here ignores. */ +export const DEFAULT_IGNORES = ['**/dist/', '**/coverage/', '**/tmp/']; + +/** Shared by the TS and JS variants of `no-unused-vars`. */ +const UNUSED_VARS = { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', +}; + +/** Shared by the TS and JS variants of `no-use-before-define`. */ +const USE_BEFORE_DEFINE = { + functions: false, + classes: false, + variables: false, +}; + +/** Options accepted by {@link bust}. */ +export interface BustConfigOptions { + /** + * Lint TypeScript. Adds `typescript-eslint`'s recommended rules and the + * TS-aware variants of `no-unused-vars` and `no-use-before-define`. + * Turning this off yields the JS-only configuration - the same rules, + * minus anything that needs a TypeScript parser. + * + * @defaultValue true + */ + typescript?: boolean; + /** + * Add the rules that need type information - the ones that catch a + * promise nobody awaited. Requires `typescript`, and requires the + * project's `tsconfig.json` to cover every linted file. + * + * @defaultValue true + */ + typeAware?: boolean; + /** + * Add React rules: `@eslint-react` plus the hooks plugin, and the JSX + * half of the stylistic rules. + * + * @defaultValue false + */ + react?: boolean; + /** + * Add Vitest's recommended rules, scoped to `*.test.*` files. + * + * @defaultValue false + */ + vitest?: boolean; + /** + * Relax the type-aware rules that Node's test runner trips over. Has no + * effect without `typeAware`, which is what turns those rules on. + * + * @defaultValue false + */ + nodeTest?: boolean; + /** + * Where the type-aware project service looks for `tsconfig.json`. + * + * @defaultValue `process.cwd()` + */ + tsconfigRootDir?: string; + /** + * Files to type-check outside the project's `tsconfig.json` - an + * `eslint.config.js` that the tsconfig lists but `allowJs` excludes, for + * instance. + */ + allowDefaultProject?: string[]; + /** Paths to ignore, added to {@link DEFAULT_IGNORES}. */ + ignores?: string[]; +} + +/** Applies {@link BustConfigOptions}' documented defaults. */ +function resolveOptions(options: BustConfigOptions): Required> + & Pick { + return { + nodeTest: options.nodeTest ?? false, + typescript: options.typescript ?? true, + typeAware: options.typeAware ?? true, + react: options.react ?? false, + vitest: options.vitest ?? false, + tsconfigRootDir: options.tsconfigRootDir ?? process.cwd(), + allowDefaultProject: options.allowDefaultProject, + ignores: options.ignores ?? [], + }; +} + +/** The React ruleset, in its TypeScript-aware form where that applies. */ +function reactRules(typescript: boolean): Linter.Config { + return (typescript + ? eslintReact.configs['recommended-typescript'] + : eslintReact.configs.recommended) as Linter.Config; +} + +/** + * Builds the shared ESLint configuration. + * + * Returns a flat-config array ready to export. Every block is named, so + * `eslint --inspect-config` reports which one applied a rule. Append your own + * blocks to override anything - later blocks win. + * + * @example + * ```js + * // eslint.config.js + * import bust from '@bust/eslint-config'; + * + * export default bust({ react: true, vitest: true, ignores: ['.output/'] }); + * ``` + * @example + * ```js + * // a JS-only project, with one rule relaxed + * export default [ + * ...bust({ typescript: false }), + * { files: ['bin/**'], rules: { 'no-console': 'off' } }, + * ]; + * ``` + */ +export function bust(options: BustConfigOptions = {}): Linter.Config[] { + const { + typescript, + typeAware, + react, + nodeTest, + vitest: withVitest, + tsconfigRootDir, + allowDefaultProject, + ignores, + } = resolveOptions(options); + const configs: Linter.Config[] = [ + { + name: 'bust/ignores', + ignores: [...DEFAULT_IGNORES, ...ignores], + }, + js.configs.recommended, + ]; + + if (typescript) { + configs.push(...(tseslint.configs.recommended as Linter.Config[])); + } + + configs.push({ + name: 'bust/base', + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: { ...globals.node, ...globals.browser }, + }, + plugins: { '@stylistic': stylistic }, + rules: { + '@stylistic/indent': ['error', 'tab'], + '@stylistic/quotes': ['error', 'single', { avoidEscape: true }], + '@stylistic/semi': ['error', 'always'], + '@stylistic/semi-spacing': 'error', + '@stylistic/semi-style': ['error', 'last'], + '@stylistic/comma-dangle': ['error', 'always-multiline'], + '@stylistic/eol-last': ['error', 'always'], + '@stylistic/linebreak-style': ['error', 'unix'], + '@stylistic/max-len': ['error', { + code: 120, + ignoreComments: true, + ignoreTrailingComments: true, + ignoreUrls: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }], + '@stylistic/no-multiple-empty-lines': ['error', { + max: 2, + maxBOF: 0, + maxEOF: 1, + }], + '@stylistic/no-multi-spaces': ['error', { + exceptions: { VariableDeclarator: true }, + }], + '@stylistic/no-trailing-spaces': 'error', + '@stylistic/no-mixed-spaces-and-tabs': 'error', + '@stylistic/no-whitespace-before-property': 'error', + '@stylistic/no-extra-semi': 'error', + '@stylistic/no-floating-decimal': 'error', + '@stylistic/brace-style': ['error', '1tbs'], + '@stylistic/block-spacing': 'error', + '@stylistic/arrow-spacing': 'error', + '@stylistic/keyword-spacing': ['error', { before: true, after: true }], + '@stylistic/array-bracket-spacing': ['error', 'never'], + '@stylistic/object-curly-spacing': ['error', 'always'], + '@stylistic/space-in-parens': ['error', 'never'], + '@stylistic/space-infix-ops': 'error', + '@stylistic/space-unary-ops': ['error', { words: true, nonwords: false }], + '@stylistic/multiline-ternary': ['error', 'always-multiline'], + 'block-scoped-var': 'error', + 'camelcase': ['error', { properties: 'never', ignoreDestructuring: true }], + 'complexity': ['error', 15], + 'curly': 'error', + 'eqeqeq': ['error', 'smart'], + 'func-names': ['error', 'as-needed'], + 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], + 'no-console': 'error', + 'no-extend-native': 'error', + 'no-nested-ternary': 'error', + 'no-var': 'error', + 'prefer-const': 'error', + }, + }); + + configs.push(typescript + ? { + name: 'bust/typescript', + rules: { + '@typescript-eslint/consistent-type-imports': ['error', { fixStyle: 'inline-type-imports' }], + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/no-unused-vars': ['error', UNUSED_VARS], + '@typescript-eslint/no-use-before-define': ['error', USE_BEFORE_DEFINE], + 'no-use-before-define': 'off', + }, + } + : { + name: 'bust/javascript', + rules: { + 'no-unused-vars': ['error', UNUSED_VARS], + 'no-use-before-define': ['error', USE_BEFORE_DEFINE], + }, + }); + + const typeChecked = typescript && typeAware; + + if (typeChecked) { + configs.push({ + name: 'bust/type-aware', + // scoped to TypeScript: the project service throws on any file the + // tsconfig does not cover, and a repo's stray `.mjs` scripts never are + files: ['**/*.{ts,tsx,mts,cts}'], + languageOptions: { + parserOptions: { + projectService: allowDefaultProject + ? { allowDefaultProject } + : true, + tsconfigRootDir, + }, + }, + rules: { + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-misused-promises': 'error', + }, + }); + } + + if (typeChecked && nodeTest) { + configs.push({ + name: 'bust/node-test', + files: NODE_TEST_FILES, + rules: { + // `describe()` and `it()` return promises nobody is meant to + // await - the rule is right about the type and wrong about + // this runner + '@typescript-eslint/no-floating-promises': 'off', + }, + }); + } + + if (react) { + configs.push( + { + // the plugin's config carries its own `name`, so it is spread + // first and ours wins + ...reactRules(typescript), + name: 'bust/react', + files: ['**/*.{jsx,tsx}'], + }, + { + name: 'bust/react-stylistic', + files: ['**/*.{jsx,tsx}'], + plugins: { '@stylistic': stylistic }, + rules: { + '@stylistic/jsx-quotes': ['error', 'prefer-double'], + '@stylistic/jsx-indent-props': ['error', 'tab'], + '@stylistic/jsx-curly-spacing': ['error', { when: 'never', children: true }], + '@stylistic/jsx-tag-spacing': ['error', { + closingSlash: 'never', + beforeSelfClosing: 'always', + afterOpening: 'never', + beforeClosing: 'never', + }], + '@stylistic/jsx-one-expression-per-line': ['error', { allow: 'single-line' }], + }, + }, + { + ...reactHooks.configs.flat['recommended-latest'] as Linter.Config, + name: 'bust/react-hooks', + }, + ); + } + + if (withVitest) { + configs.push({ + name: 'bust/vitest', + files: ['**/*.test.{js,jsx,ts,tsx,mjs,mts}'], + plugins: { vitest }, + rules: vitest.configs.recommended.rules as Linter.RulesRecord, + }); + } + + return configs; +} + +export default bust; diff --git a/packages/eslint-config/tsconfig.json b/packages/eslint-config/tsconfig.json new file mode 100644 index 0000000..41716a7 --- /dev/null +++ b/packages/eslint-config/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig" +} diff --git a/packages/numeric-id-hasher/src/index.test.ts b/packages/numeric-id-hasher/src/index.test.ts index 9306262..0758847 100644 --- a/packages/numeric-id-hasher/src/index.test.ts +++ b/packages/numeric-id-hasher/src/index.test.ts @@ -48,7 +48,7 @@ describe('@bust/numeric-id-hasher', () => { { id: '55555', hash: 'M4p' }, { id: '676767676767676767', hash: '5DLHvp97zSB' }, { id: '898989898989898989', hash: '6GFqXGaDBhr' }, - { id: '10000000000000000000000000', hash: '7aDn7BhWK5E4NvC' } + { id: '10000000000000000000000000', hash: '7aDn7BhWK5E4NvC' }, ]; } }); diff --git a/packages/periodical/src/index.test.ts b/packages/periodical/src/index.test.ts index 51b88fc..83770e0 100644 --- a/packages/periodical/src/index.test.ts +++ b/packages/periodical/src/index.test.ts @@ -24,7 +24,7 @@ describe('@bust/periodically', () => { value: 0, run() { this.value += 1; - } + }, }; ctx.mock.timers.enable({ apis: ['setTimeout'] }); diff --git a/packages/periodical/src/index.ts b/packages/periodical/src/index.ts index 52b7174..d7f9e19 100644 --- a/packages/periodical/src/index.ts +++ b/packages/periodical/src/index.ts @@ -27,7 +27,6 @@ export type Callback = () => void; export const noop = () => {}; - /** * Main `Periodical` class. *