diff --git a/.eslint-doc-generatorrc.js b/.eslint-doc-generatorrc.js index f2c9d67b..01e10317 100644 --- a/.eslint-doc-generatorrc.js +++ b/.eslint-doc-generatorrc.js @@ -1,5 +1,5 @@ /** @type {import('eslint-doc-generator').GenerateOptions} */ -module.exports = { +export default { configEmoji: [ ['browser', 'π'], ['internal', 'π'], diff --git a/README.md b/README.md index baf32798..8c3bf397 100644 --- a/README.md +++ b/README.md @@ -117,17 +117,17 @@ This config will be interpreted in the following way: | Name | Description | πΌ | π§ | β | | :------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [a11y-aria-label-is-well-formatted](docs/rules/a11y-aria-label-is-well-formatted.md) | [aria-label] text should be formatted as you would visual text. | βοΈ | | | +| [a11y-aria-label-is-well-formatted](docs/rules/a11y-aria-label-is-well-formatted.md) | enforce [aria-label] text to be formatted as you would visual text. | βοΈ | | | | [a11y-no-generic-link-text](docs/rules/a11y-no-generic-link-text.md) | disallow generic link text | | | β | -| [a11y-no-title-attribute](docs/rules/a11y-no-title-attribute.md) | Guards against developers using the title attribute | βοΈ | | | -| [a11y-no-visually-hidden-interactive-element](docs/rules/a11y-no-visually-hidden-interactive-element.md) | Ensures that interactive elements are not visually hidden | βοΈ | | | -| [a11y-role-supports-aria-props](docs/rules/a11y-role-supports-aria-props.md) | Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. | βοΈ | | | -| [a11y-svg-has-accessible-name](docs/rules/a11y-svg-has-accessible-name.md) | SVGs must have an accessible name | βοΈ | | | +| [a11y-no-title-attribute](docs/rules/a11y-no-title-attribute.md) | disallow using the title attribute | βοΈ | | | +| [a11y-no-visually-hidden-interactive-element](docs/rules/a11y-no-visually-hidden-interactive-element.md) | enforce that interactive elements are not visually hidden | βοΈ | | | +| [a11y-role-supports-aria-props](docs/rules/a11y-role-supports-aria-props.md) | enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. | βοΈ | | | +| [a11y-svg-has-accessible-name](docs/rules/a11y-svg-has-accessible-name.md) | require SVGs to have an accessible name | βοΈ | | | | [array-foreach](docs/rules/array-foreach.md) | enforce `for..of` loops over `Array.forEach` | β | | | | [async-currenttarget](docs/rules/async-currenttarget.md) | disallow `event.currentTarget` calls inside of async functions | π | | | | [async-preventdefault](docs/rules/async-preventdefault.md) | disallow `event.preventDefault` calls inside of async functions | π | | | | [authenticity-token](docs/rules/authenticity-token.md) | disallow usage of CSRF tokens in JavaScript | π | | | -| [filenames-match-regex](docs/rules/filenames-match-regex.md) | ensure filenames match a regex naming convention | | | | +| [filenames-match-regex](docs/rules/filenames-match-regex.md) | require filenames to match a regex naming convention | | | | | [get-attribute](docs/rules/get-attribute.md) | disallow wrong usage of attribute names | π | π§ | | | [js-class-name](docs/rules/js-class-name.md) | enforce a naming convention for js- prefixed classes | π | | | | [no-blur](docs/rules/no-blur.md) | disallow usage of `Element.prototype.blur()` | π | | | diff --git a/docs/rules/a11y-aria-label-is-well-formatted.md b/docs/rules/a11y-aria-label-is-well-formatted.md index 9c2f164a..a833c6ed 100644 --- a/docs/rules/a11y-aria-label-is-well-formatted.md +++ b/docs/rules/a11y-aria-label-is-well-formatted.md @@ -1,4 +1,4 @@ -# [aria-label] text should be formatted as you would visual text (`github/a11y-aria-label-is-well-formatted`) +# Enforce [aria-label] text to be formatted as you would visual text (`github/a11y-aria-label-is-well-formatted`) πΌ This rule is enabled in the βοΈ `react` config. diff --git a/docs/rules/a11y-no-title-attribute.md b/docs/rules/a11y-no-title-attribute.md index 29b382d1..1c0006ba 100644 --- a/docs/rules/a11y-no-title-attribute.md +++ b/docs/rules/a11y-no-title-attribute.md @@ -1,4 +1,4 @@ -# Guards against developers using the title attribute (`github/a11y-no-title-attribute`) +# Disallow using the title attribute (`github/a11y-no-title-attribute`) πΌ This rule is enabled in the βοΈ `react` config. diff --git a/docs/rules/a11y-no-visually-hidden-interactive-element.md b/docs/rules/a11y-no-visually-hidden-interactive-element.md index 52fdbc12..f5518982 100644 --- a/docs/rules/a11y-no-visually-hidden-interactive-element.md +++ b/docs/rules/a11y-no-visually-hidden-interactive-element.md @@ -1,4 +1,4 @@ -# Ensures that interactive elements are not visually hidden (`github/a11y-no-visually-hidden-interactive-element`) +# Enforce that interactive elements are not visually hidden (`github/a11y-no-visually-hidden-interactive-element`) πΌ This rule is enabled in the βοΈ `react` config. diff --git a/docs/rules/a11y-svg-has-accessible-name.md b/docs/rules/a11y-svg-has-accessible-name.md index 088e918b..000d05c4 100644 --- a/docs/rules/a11y-svg-has-accessible-name.md +++ b/docs/rules/a11y-svg-has-accessible-name.md @@ -1,4 +1,4 @@ -# SVGs must have an accessible name (`github/a11y-svg-has-accessible-name`) +# Require SVGs to have an accessible name (`github/a11y-svg-has-accessible-name`) πΌ This rule is enabled in the βοΈ `react` config. diff --git a/docs/rules/filenames-match-regex.md b/docs/rules/filenames-match-regex.md index 4d153880..586e9acd 100644 --- a/docs/rules/filenames-match-regex.md +++ b/docs/rules/filenames-match-regex.md @@ -1,4 +1,4 @@ -# Ensure filenames match a regex naming convention (`github/filenames-match-regex`) +# Require filenames to match a regex naming convention (`github/filenames-match-regex`) <!-- end auto-generated rule header --> diff --git a/eslint.config.js b/eslint.config.js index 94e32e6d..776d883a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,13 +1,16 @@ -const globals = require('globals') -const eslintPlugin = require('eslint-plugin-eslint-plugin') -const importPlugin = require('eslint-plugin-import') -const i18nTextPlugin = require('eslint-plugin-i18n-text') -const recommendedGitHub = require('./lib/configs/flat/recommended') -const {fixupPluginRules} = require('@eslint/compat') +import globals from 'globals' +import eslintPlugin from 'eslint-plugin-eslint-plugin' +import importPlugin from 'eslint-plugin-import' +import i18nTextPlugin from 'eslint-plugin-i18n-text' +import recommendedGitHub from './lib/configs/flat/recommended.js' +import {fixupPluginRules} from '@eslint/compat' -module.exports = [ +export default [ recommendedGitHub, - eslintPlugin.configs['flat/all'], + { + files: ['lib/rules/**/*.js'], + ...eslintPlugin.configs['flat/all'], + }, { ignores: ['test-examples/**'], }, @@ -32,6 +35,7 @@ module.exports = [ 'eslint-plugin/prefer-placeholders': 'off', 'eslint-plugin/test-case-shorthand-strings': 'off', 'eslint-plugin/require-meta-docs-url': 'off', + 'eslint-plugin/require-meta-default-options': 'off', }, }, ] diff --git a/lib/configs/browser.js b/lib/configs/browser.js index c9eeffae..eab0b3ac 100644 --- a/lib/configs/browser.js +++ b/lib/configs/browser.js @@ -1,4 +1,4 @@ -module.exports = { +export default { env: { browser: true, }, diff --git a/lib/configs/flat/browser.js b/lib/configs/flat/browser.js index 18311b62..dc96f387 100644 --- a/lib/configs/flat/browser.js +++ b/lib/configs/flat/browser.js @@ -1,10 +1,10 @@ -const globals = require('globals') -const github = require('../../plugin') -const importPlugin = require('eslint-plugin-import') -const escompat = require('eslint-plugin-escompat') -const {fixupPluginRules} = require('@eslint/compat') +import globals from 'globals' +import github from '../../plugin.js' +import importPlugin from 'eslint-plugin-import' +import escompat from 'eslint-plugin-escompat' +import {fixupPluginRules} from '@eslint/compat' -module.exports = { +export default { ...escompat.configs['flat/recommended'], languageOptions: { globals: { diff --git a/lib/configs/flat/internal.js b/lib/configs/flat/internal.js index 0ce81f51..7c6a7b51 100644 --- a/lib/configs/flat/internal.js +++ b/lib/configs/flat/internal.js @@ -1,7 +1,7 @@ -const github = require('../../plugin') -const {fixupPluginRules} = require('@eslint/compat') +import github from '../../plugin.js' +import {fixupPluginRules} from '@eslint/compat' -module.exports = { +export default { plugins: {github: fixupPluginRules(github)}, rules: { 'github/authenticity-token': 'error', diff --git a/lib/configs/flat/react.js b/lib/configs/flat/react.js index 193e3c2d..3df007d9 100644 --- a/lib/configs/flat/react.js +++ b/lib/configs/flat/react.js @@ -1,8 +1,8 @@ -const github = require('../../plugin') -const jsxA11yPlugin = require('eslint-plugin-jsx-a11y') -const {fixupPluginRules} = require('@eslint/compat') +import github from '../../plugin.js' +import jsxA11yPlugin from 'eslint-plugin-jsx-a11y' +import {fixupPluginRules} from '@eslint/compat' -module.exports = { +export default { ...jsxA11yPlugin.flatConfigs.recommended, languageOptions: { sourceType: 'module', diff --git a/lib/configs/flat/recommended.js b/lib/configs/flat/recommended.js index 748647ea..02113bc1 100644 --- a/lib/configs/flat/recommended.js +++ b/lib/configs/flat/recommended.js @@ -1,13 +1,13 @@ -const globals = require('globals') -const github = require('../../plugin') -const prettierPlugin = require('eslint-plugin-prettier') -const eslintComments = require('eslint-plugin-eslint-comments') -const importPlugin = require('eslint-plugin-import') -const i18nTextPlugin = require('eslint-plugin-i18n-text') -const noOnlyTestsPlugin = require('eslint-plugin-no-only-tests') -const {fixupPluginRules} = require('@eslint/compat') +import globals from 'globals' +import github from '../../plugin.js' +import prettierPlugin from 'eslint-plugin-prettier' +import eslintComments from 'eslint-plugin-eslint-comments' +import importPlugin from 'eslint-plugin-import' +import i18nTextPlugin from 'eslint-plugin-i18n-text' +import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests' +import {fixupPluginRules} from '@eslint/compat' -module.exports = { +export default { languageOptions: { ecmaVersion: 6, sourceType: 'module', diff --git a/lib/configs/flat/typescript.js b/lib/configs/flat/typescript.js index 29c48e2d..170560a5 100644 --- a/lib/configs/flat/typescript.js +++ b/lib/configs/flat/typescript.js @@ -1,13 +1,12 @@ -const tseslint = require('typescript-eslint') -const escompat = require('eslint-plugin-escompat') -const github = require('../../plugin') -const {fixupPluginRules} = require('@eslint/compat') +// eslint-disable-next-line import/no-unresolved +import tseslint from 'typescript-eslint' +import escompat from 'eslint-plugin-escompat' -module.exports = tseslint.config(...tseslint.configs.recommended, ...escompat.configs['flat/typescript-2020'], { +export default tseslint.config(...tseslint.configs.recommended, ...escompat.configs['flat/typescript-2020'], { languageOptions: { parser: tseslint.parser, }, - plugins: {'@typescript-eslint': tseslint.plugin, escompat, github: fixupPluginRules(github)}, + plugins: {'@typescript-eslint': tseslint.plugin, escompat}, rules: { camelcase: 'off', 'no-unused-vars': 'off', diff --git a/lib/configs/internal.js b/lib/configs/internal.js index f42fcf4a..627d20d6 100644 --- a/lib/configs/internal.js +++ b/lib/configs/internal.js @@ -1,4 +1,4 @@ -module.exports = { +export default { plugins: ['github'], rules: { 'github/authenticity-token': 'error', diff --git a/lib/configs/react.js b/lib/configs/react.js index 6667f597..a1983c43 100644 --- a/lib/configs/react.js +++ b/lib/configs/react.js @@ -1,4 +1,4 @@ -module.exports = { +export default { parserOptions: { sourceType: 'module', ecmaFeatures: { diff --git a/lib/configs/recommended.js b/lib/configs/recommended.js index cdbbd450..f7f9d40e 100644 --- a/lib/configs/recommended.js +++ b/lib/configs/recommended.js @@ -1,4 +1,4 @@ -module.exports = { +export default { parserOptions: { ecmaFeatures: { ecmaVersion: 6, diff --git a/lib/configs/typescript.js b/lib/configs/typescript.js index a13df33f..bcb18811 100644 --- a/lib/configs/typescript.js +++ b/lib/configs/typescript.js @@ -1,4 +1,4 @@ -module.exports = { +export default { extends: ['plugin:@typescript-eslint/recommended', 'prettier', 'plugin:escompat/typescript-2020'], parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'escompat', 'github'], diff --git a/lib/formatters/stylish-fixes.js b/lib/formatters/stylish-fixes.js index b8523229..f39769d4 100644 --- a/lib/formatters/stylish-fixes.js +++ b/lib/formatters/stylish-fixes.js @@ -1,18 +1,11 @@ -'use strict' +import childProcess from 'node:child_process' +import fs from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import SourceCodeFixer from 'eslint/lib/linter/source-code-fixer.js' +import getRuleURI from 'eslint-rule-documentation' -const childProcess = require('child_process') -const fs = require('fs') -const os = require('os') -const path = require('path') -let SourceCodeFixer = null -try { - SourceCodeFixer = require('eslint/lib/linter/source-code-fixer') -} catch { - SourceCodeFixer = require('eslint/lib/util/source-code-fixer') -} -const getRuleURI = require('eslint-rule-documentation') - -module.exports = function (results) { +export default function stylishFixes(results) { let output = '\n' let errors = 0 let warnings = 0 diff --git a/lib/index.js b/lib/index.js index aa677a2d..6091c0bc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,21 +1,31 @@ -const github = require('./plugin') +import github from './plugin.js' +import flatBrowserConfig from './configs/flat/browser.js' +import flatInternalConfig from './configs/flat/internal.js' +import flatRecommendedConfig from './configs/flat/recommended.js' +import flatTypescriptConfig from './configs/flat/typescript.js' +import flatReactConfig from './configs/flat/react.js' +import browserConfig from './configs/browser.js' +import internalConfig from './configs/internal.js' +import recommendedConfig from './configs/recommended.js' +import typescriptConfig from './configs/typescript.js' +import reactConfig from './configs/react.js' const getFlatConfig = () => ({ - browser: require('./configs/flat/browser'), - internal: require('./configs/flat/internal'), - recommended: require('./configs/flat/recommended'), - typescript: require('./configs/flat/typescript'), - react: require('./configs/flat/react'), + browser: flatBrowserConfig, + internal: flatInternalConfig, + recommended: flatRecommendedConfig, + typescript: flatTypescriptConfig, + react: flatReactConfig, }) -module.exports = { +export default { rules: github.rules, configs: { - browser: require('./configs/browser'), - internal: require('./configs/internal'), - recommended: require('./configs/recommended'), - typescript: require('./configs/typescript'), - react: require('./configs/react'), + browser: browserConfig, + internal: internalConfig, + recommended: recommendedConfig, + typescript: typescriptConfig, + react: reactConfig, }, getFlatConfigs: getFlatConfig, } diff --git a/lib/plugin.js b/lib/plugin.js index eb25a25e..93fc053d 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -1,32 +1,59 @@ -const {name, version} = require('../package.json') +import {packageJson} from './utils/commonjs-json-wrappers.cjs' +import a11yNoVisuallyHiddenInteractiveElement from './rules/a11y-no-visually-hidden-interactive-element.js' +import a11yNoGenericLinkText from './rules/a11y-no-generic-link-text.js' +import a11yNoTitleAttribute from './rules/a11y-no-title-attribute.js' +import a11yAriaLabelIsWellFormatted from './rules/a11y-aria-label-is-well-formatted.js' +import a11yRoleSupportsAriaProps from './rules/a11y-role-supports-aria-props.js' +import a11ySvgHasAccessibleName from './rules/a11y-svg-has-accessible-name.js' +import arrayForeach from './rules/array-foreach.js' +import asyncCurrenttarget from './rules/async-currenttarget.js' +import asyncPreventdefault from './rules/async-preventdefault.js' +import authenticityToken from './rules/authenticity-token.js' +import filenamesMatchRegex from './rules/filenames-match-regex.js' +import getAttribute from './rules/get-attribute.js' +import jsClassName from './rules/js-class-name.js' +import noBlur from './rules/no-blur.js' +import noDNone from './rules/no-d-none.js' +import noDataset from './rules/no-dataset.js' +import noImplicitBuggyGlobals from './rules/no-implicit-buggy-globals.js' +import noInnerHTML from './rules/no-inner-html.js' +import noInnerText from './rules/no-innerText.js' +import noDynamicScriptTag from './rules/no-dynamic-script-tag.js' +import noThen from './rules/no-then.js' +import noUselessPassive from './rules/no-useless-passive.js' +import preferObservers from './rules/prefer-observers.js' +import requirePassiveEvents from './rules/require-passive-events.js' +import unescapedHtmlLiteral from './rules/unescaped-html-literal.js' -module.exports = { +const {name, version} = packageJson + +export default { meta: {name, version}, rules: { - 'a11y-no-visually-hidden-interactive-element': require('./rules/a11y-no-visually-hidden-interactive-element'), - 'a11y-no-generic-link-text': require('./rules/a11y-no-generic-link-text'), - 'a11y-no-title-attribute': require('./rules/a11y-no-title-attribute'), - 'a11y-aria-label-is-well-formatted': require('./rules/a11y-aria-label-is-well-formatted'), - 'a11y-role-supports-aria-props': require('./rules/a11y-role-supports-aria-props'), - 'a11y-svg-has-accessible-name': require('./rules/a11y-svg-has-accessible-name'), - 'array-foreach': require('./rules/array-foreach'), - 'async-currenttarget': require('./rules/async-currenttarget'), - 'async-preventdefault': require('./rules/async-preventdefault'), - 'authenticity-token': require('./rules/authenticity-token'), - 'filenames-match-regex': require('./rules/filenames-match-regex'), - 'get-attribute': require('./rules/get-attribute'), - 'js-class-name': require('./rules/js-class-name'), - 'no-blur': require('./rules/no-blur'), - 'no-d-none': require('./rules/no-d-none'), - 'no-dataset': require('./rules/no-dataset'), - 'no-implicit-buggy-globals': require('./rules/no-implicit-buggy-globals'), - 'no-inner-html': require('./rules/no-inner-html'), - 'no-innerText': require('./rules/no-innerText'), - 'no-dynamic-script-tag': require('./rules/no-dynamic-script-tag'), - 'no-then': require('./rules/no-then'), - 'no-useless-passive': require('./rules/no-useless-passive'), - 'prefer-observers': require('./rules/prefer-observers'), - 'require-passive-events': require('./rules/require-passive-events'), - 'unescaped-html-literal': require('./rules/unescaped-html-literal'), + 'a11y-no-visually-hidden-interactive-element': a11yNoVisuallyHiddenInteractiveElement, + 'a11y-no-generic-link-text': a11yNoGenericLinkText, + 'a11y-no-title-attribute': a11yNoTitleAttribute, + 'a11y-aria-label-is-well-formatted': a11yAriaLabelIsWellFormatted, + 'a11y-role-supports-aria-props': a11yRoleSupportsAriaProps, + 'a11y-svg-has-accessible-name': a11ySvgHasAccessibleName, + 'array-foreach': arrayForeach, + 'async-currenttarget': asyncCurrenttarget, + 'async-preventdefault': asyncPreventdefault, + 'authenticity-token': authenticityToken, + 'filenames-match-regex': filenamesMatchRegex, + 'get-attribute': getAttribute, + 'js-class-name': jsClassName, + 'no-blur': noBlur, + 'no-d-none': noDNone, + 'no-dataset': noDataset, + 'no-implicit-buggy-globals': noImplicitBuggyGlobals, + 'no-inner-html': noInnerHTML, + 'no-innerText': noInnerText, + 'no-dynamic-script-tag': noDynamicScriptTag, + 'no-then': noThen, + 'no-useless-passive': noUselessPassive, + 'prefer-observers': preferObservers, + 'require-passive-events': requirePassiveEvents, + 'unescaped-html-literal': unescapedHtmlLiteral, }, } diff --git a/lib/rules/a11y-aria-label-is-well-formatted.js b/lib/rules/a11y-aria-label-is-well-formatted.js index 3e9ace86..e719b448 100644 --- a/lib/rules/a11y-aria-label-is-well-formatted.js +++ b/lib/rules/a11y-aria-label-is-well-formatted.js @@ -1,12 +1,20 @@ -const {getProp} = require('jsx-ast-utils') +import jsxAstUtils from 'jsx-ast-utils' +import url from '../url.js' -module.exports = { +const {getProp} = jsxAstUtils + +export default { meta: { + type: 'problem', docs: { - description: '[aria-label] text should be formatted as you would visual text.', - url: require('../url')(module), + description: 'enforce [aria-label] text to be formatted as you would visual text.', + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + formatting: '[aria-label] text should be formatted the same as you would visual text. Use sentence case.', + }, }, create(context) { @@ -22,7 +30,7 @@ module.exports = { if (ariaLabel.match(/^[a-z]+.*$/)) { context.report({ node, - message: '[aria-label] text should be formatted the same as you would visual text. Use sentence case.', + messageId: 'formatting', }) } }, diff --git a/lib/rules/a11y-no-generic-link-text.js b/lib/rules/a11y-no-generic-link-text.js index 93277949..b2210349 100644 --- a/lib/rules/a11y-no-generic-link-text.js +++ b/lib/rules/a11y-no-generic-link-text.js @@ -1,6 +1,8 @@ -const {getProp, getPropValue} = require('jsx-ast-utils') -const {getElementType} = require('../utils/get-element-type') +import jsxAstUtils from 'jsx-ast-utils' +import {getElementType} from '../utils/get-element-type.js' +import url from '../url.js' +const {getProp, getPropValue} = jsxAstUtils const bannedLinkText = ['read more', 'here', 'click here', 'learn more', 'more'] /* Downcase and strip extra whitespaces and punctuation */ @@ -12,15 +14,22 @@ const stripAndDowncaseText = text => { .trim() } -module.exports = { +export default { meta: { + type: 'problem', docs: { description: 'disallow generic link text', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, deprecated: true, replacedBy: ['jsx-a11y/anchor-ambiguous-text'], schema: [], + messages: { + avoidGenericLinkText: + 'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.', + ariaLabelDescriptive: 'When using ARIA to set a more descriptive text, it must fully contain the visible label.', + }, }, create(context) { @@ -47,14 +56,13 @@ module.exports = { if (bannedLinkText.includes(cleanAriaLabelValue)) { context.report({ node, - message: - 'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.', + messageId: 'avoidGenericLinkText', }) } if (cleanTextContent && !cleanAriaLabelValue.includes(cleanTextContent)) { context.report({ node, - message: 'When using ARIA to set a more descriptive text, it must fully contain the visible label.', + messageId: 'ariaLabelDescriptive', }) } } else { @@ -62,8 +70,7 @@ module.exports = { if (!bannedLinkText.includes(cleanTextContent)) return context.report({ node: jsxTextNode, - message: - 'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.', + messageId: 'avoidGenericLinkText', }) } } diff --git a/lib/rules/a11y-no-title-attribute.js b/lib/rules/a11y-no-title-attribute.js index cc3ec1d0..5e9d1f71 100644 --- a/lib/rules/a11y-no-title-attribute.js +++ b/lib/rules/a11y-no-title-attribute.js @@ -1,6 +1,8 @@ -const {getProp, getPropValue} = require('jsx-ast-utils') -const {getElementType} = require('../utils/get-element-type') +import jsxAstUtils from 'jsx-ast-utils' +import {getElementType} from '../utils/get-element-type.js' +import url from '../url.js' +const {getProp, getPropValue} = jsxAstUtils const SEMANTIC_ELEMENTS = [ 'a', 'button', @@ -38,13 +40,18 @@ const ifSemanticElement = (context, node) => { return false } -module.exports = { +export default { meta: { + type: 'problem', docs: { - description: 'Guards against developers using the title attribute', - url: require('../url')(module), + description: 'disallow using the title attribute', + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + titleAttribute: 'The title attribute is not accessible and should never be used unless for an `<iframe>`.', + }, }, create(context) { @@ -56,7 +63,7 @@ module.exports = { if (titleProp) { context.report({ node, - message: 'The title attribute is not accessible and should never be used unless for an `<iframe>`.', + messageId: 'titleAttribute', }) } } diff --git a/lib/rules/a11y-no-visually-hidden-interactive-element.js b/lib/rules/a11y-no-visually-hidden-interactive-element.js index 70f7c3cd..a7235a29 100644 --- a/lib/rules/a11y-no-visually-hidden-interactive-element.js +++ b/lib/rules/a11y-no-visually-hidden-interactive-element.js @@ -1,7 +1,9 @@ -const {getProp, getLiteralPropValue} = require('jsx-ast-utils') -const {getElementType} = require('../utils/get-element-type') -const {generateObjSchema} = require('eslint-plugin-jsx-a11y/lib/util/schemas') +import jsxAstUtils from 'jsx-ast-utils' +import {getElementType} from '../utils/get-element-type.js' +import {generateObjSchema} from 'eslint-plugin-jsx-a11y/lib/util/schemas.js' +import url from '../url.js' +const {getProp, getLiteralPropValue} = jsxAstUtils const defaultClassName = 'sr-only' const defaultcomponentName = 'VisuallyHidden' @@ -55,13 +57,19 @@ const checkIfVisuallyHiddenAndInteractive = (context, options, node, isParentVis return false } -module.exports = { +export default { meta: { + type: 'problem', docs: { - description: 'Ensures that interactive elements are not visually hidden', - url: require('../url')(module), + description: 'enforce that interactive elements are not visually hidden', + url: url(import.meta.url), + recommended: false, }, schema: [schema], + messages: { + avoid: + 'Avoid visually hidding interactive elements. Visually hiding interactive elements can be confusing to sighted keyboard users as it appears their focus has been lost when they navigate to the hidden element.', + }, }, create(context) { @@ -75,8 +83,7 @@ module.exports = { if (checkIfVisuallyHiddenAndInteractive(context, {className, componentName}, node, false)) { context.report({ node, - message: - 'Avoid visually hidding interactive elements. Visually hiding interactive elements can be confusing to sighted keyboard users as it appears their focus has been lost when they navigate to the hidden element.', + messageId: 'avoid', }) } }, diff --git a/lib/rules/a11y-role-supports-aria-props.js b/lib/rules/a11y-role-supports-aria-props.js index b6ba0710..8a014a99 100644 --- a/lib/rules/a11y-role-supports-aria-props.js +++ b/lib/rules/a11y-role-supports-aria-props.js @@ -1,16 +1,24 @@ // @ts-check -const {aria, roles} = require('aria-query') -const {getPropValue, propName} = require('jsx-ast-utils') -const {getRole} = require('../utils/get-role') +import {aria, roles} from 'aria-query' +import jsxAstUtils from 'jsx-ast-utils' +import {getRole} from '../utils/get-role.js' +import url from '../url.js' -module.exports = { +const {getPropValue, propName} = jsxAstUtils + +export default { meta: { + type: 'problem', docs: { description: - 'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.', - url: require('../url')(module), + 'enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.', + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + notSupported: 'The attribute {{attr}} is not supported by the role {{role}}.', + }, }, create(context) { @@ -51,7 +59,11 @@ module.exports = { if (prohibitedProps?.includes(propName(prop))) { context.report({ node, - message: `The attribute ${propName(prop)} is not supported by the role ${role}.`, + messageId: 'notSupported', + data: { + attr: propName(prop), + role, + }, }) } } diff --git a/lib/rules/a11y-svg-has-accessible-name.js b/lib/rules/a11y-svg-has-accessible-name.js index 45e675fd..3a750935 100644 --- a/lib/rules/a11y-svg-has-accessible-name.js +++ b/lib/rules/a11y-svg-has-accessible-name.js @@ -1,13 +1,22 @@ -const {hasProp} = require('jsx-ast-utils') -const {getElementType} = require('../utils/get-element-type') +import jsxAstUtils from 'jsx-ast-utils' +import {getElementType} from '../utils/get-element-type.js' +import url from '../url.js' -module.exports = { +const {hasProp} = jsxAstUtils + +export default { meta: { + type: 'problem', docs: { - description: 'SVGs must have an accessible name', - url: require('../url')(module), + description: 'require SVGs to have an accessible name', + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + accessibleName: + '`<svg>` must have an accessible name. Set `aria-label` or `aria-labelledby`, or nest a `<title>` element. However, if the `<svg>` is purely decorative, hide it with `aria-hidden="true"` or `role="presentation"`.', + }, }, create(context) { @@ -35,8 +44,7 @@ module.exports = { if (elementType === 'svg' && !hasAccessibleName && !isDecorative && !hasNestedTitleAsFirstChild) { context.report({ node, - message: - '`<svg>` must have an accessible name. Set `aria-label` or `aria-labelledby`, or nest a `<title>` element. However, if the `<svg>` is purely decorative, hide it with `aria-hidden="true"` or `role="presentation"`.', + messageId: 'accessibleName', }) } }, diff --git a/lib/rules/array-foreach.js b/lib/rules/array-foreach.js index 1d133db7..bfb6a058 100644 --- a/lib/rules/array-foreach.js +++ b/lib/rules/array-foreach.js @@ -1,18 +1,24 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'suggestion', docs: { description: 'enforce `for..of` loops over `Array.forEach`', - url: require('../url')(module), + url: url(import.meta.url), + recommended: true, }, schema: [], + messages: { + preferForOf: 'Prefer for...of instead of Array.forEach', + }, }, create(context) { return { CallExpression(node) { if (node.callee.property && node.callee.property.name === 'forEach') { - context.report({node, message: 'Prefer for...of instead of Array.forEach'}) + context.report({node, messageId: 'preferForOf'}) } }, } diff --git a/lib/rules/async-currenttarget.js b/lib/rules/async-currenttarget.js index a9c46999..fa7bb3b7 100644 --- a/lib/rules/async-currenttarget.js +++ b/lib/rules/async-currenttarget.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow `event.currentTarget` calls inside of async functions', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + asyncCurrentTarget: 'event.currentTarget inside an async function is error prone', + }, }, create(context) { @@ -23,7 +29,7 @@ module.exports = { if (scopeDidWait.has(scope)) { context.report({ node, - message: 'event.currentTarget inside an async function is error prone', + messageId: 'asyncCurrentTarget', }) break } diff --git a/lib/rules/async-preventdefault.js b/lib/rules/async-preventdefault.js index f4154bf0..3ba88b83 100644 --- a/lib/rules/async-preventdefault.js +++ b/lib/rules/async-preventdefault.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow `event.preventDefault` calls inside of async functions', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + eventPreventDefault: 'event.preventDefault() inside an async function is error prone', + }, }, create(context) { @@ -23,7 +29,7 @@ module.exports = { if (scopeDidWait.has(scope)) { context.report({ node, - message: 'event.preventDefault() inside an async function is error prone', + messageId: 'eventPreventDefault', }) break } diff --git a/lib/rules/authenticity-token.js b/lib/rules/authenticity-token.js index 77a9c757..c73cbb41 100644 --- a/lib/rules/authenticity-token.js +++ b/lib/rules/authenticity-token.js @@ -1,11 +1,18 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow usage of CSRF tokens in JavaScript', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + authenticityTokenUsage: + 'Form CSRF tokens (authenticity tokens) should not be created in JavaScript and their values should not be used directly for XHR requests.', + }, }, create(context) { @@ -13,8 +20,7 @@ module.exports = { if (str.includes('authenticity_token')) { context.report({ node, - message: - 'Form CSRF tokens (authenticity tokens) should not be created in JavaScript and their values should not be used directly for XHR requests.', + messageId: 'authenticityTokenUsage', }) } } diff --git a/lib/rules/filenames-match-regex.js b/lib/rules/filenames-match-regex.js index beec42d2..f8c683df 100644 --- a/lib/rules/filenames-match-regex.js +++ b/lib/rules/filenames-match-regex.js @@ -1,16 +1,18 @@ // This is adapted from https://github.com/selaux/eslint-plugin-filenames since it's no longer actively maintained // and needed a fix for eslint v9 -const path = require('path') -const parseFilename = require('../utils/parse-filename') -const getExportedName = require('../utils/get-exported-name') -const isIgnoredFilename = require('../utils/is-ignored-filename') +import path from 'node:path' +import parseFilename from '../utils/parse-filename.js' +import getExportedName from '../utils/get-exported-name.js' +import isIgnoredFilename from '../utils/is-ignored-filename.js' +import url from '../url.js' -module.exports = { +export default { meta: { type: 'problem', docs: { - description: 'ensure filenames match a regex naming convention', - url: require('../url')(module), + description: 'require filenames to match a regex naming convention', + url: url(import.meta.url), + recommended: true, }, schema: { type: 'array', @@ -22,6 +24,9 @@ module.exports = { }, ], }, + messages: { + regex: "Filename '{{name}}' does not match the regex naming convention.", + }, }, create(context) { @@ -42,8 +47,12 @@ module.exports = { if (shouldIgnore) return if (ignoreExporting && isExporting) return if (!matchesRegex) { - context.report(node, "Filename '{{name}}' does not match the regex naming convention.", { - name: parsed.base, + context.report({ + node, + messageId: 'regex', + data: { + name: parsed.base, + }, }) } }, diff --git a/lib/rules/get-attribute.js b/lib/rules/get-attribute.js index 611b8bb1..5968b633 100644 --- a/lib/rules/get-attribute.js +++ b/lib/rules/get-attribute.js @@ -1,4 +1,5 @@ -const svgElementAttributes = require('svg-element-attributes') +import {svgElementAttributes} from '../utils/commonjs-json-wrappers.cjs' +import url from '../url.js' const attributeCalls = /^(get|has|set|remove)Attribute$/ const validAttributeName = /^[a-z][a-z0-9-]*$/ @@ -17,15 +18,19 @@ function isValidAttribute(name) { return validSVGAttributeSet.has(name) || (validAttributeName.test(name) && !invalidSVGAttributeSet.has(name)) } -module.exports = { +export default { meta: { type: 'problem', docs: { description: 'disallow wrong usage of attribute names', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, fixable: 'code', schema: [], + messages: { + invalidAttribute: 'Attributes should be lowercase and hyphen separated, or part of the SVG whitelist.', + }, }, create(context) { return { @@ -41,7 +46,7 @@ module.exports = { if (!isValidAttribute(attributeNameNode.value)) { context.report({ node: attributeNameNode, - message: 'Attributes should be lowercase and hyphen separated, or part of the SVG whitelist.', + messageId: 'invalidAttribute', fix(fixer) { return fixer.replaceText(attributeNameNode, `'${attributeNameNode.value.toLowerCase()}'`) }, diff --git a/lib/rules/js-class-name.js b/lib/rules/js-class-name.js index 6de759ab..7f83c77f 100644 --- a/lib/rules/js-class-name.js +++ b/lib/rules/js-class-name.js @@ -1,11 +1,18 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'suggestion', docs: { description: 'enforce a naming convention for js- prefixed classes', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + jsClassName: 'js- class names should be lowercase and only contain dashes.', + jsClassNameStatic: 'js- class names should be statically defined.', + }, }, create(context) { @@ -17,14 +24,14 @@ module.exports = { const matches = str.match(allJsClassNameRegexp) || [] for (const match of matches) { if (!match.match(validJsClassNameRegexp)) { - context.report({node, message: 'js- class names should be lowercase and only contain dashes.'}) + context.report({node, messageId: 'jsClassName'}) } } } function checkStringEndsWithJSClassName(node, str) { if (str.match(endWithJsClassNameRegexp)) { - context.report({node, message: 'js- class names should be statically defined.'}) + context.report({node, messageId: 'jsClassNameStatic'}) } } diff --git a/lib/rules/no-blur.js b/lib/rules/no-blur.js index 775d2e93..d5863399 100644 --- a/lib/rules/no-blur.js +++ b/lib/rules/no-blur.js @@ -1,17 +1,23 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow usage of `Element.prototype.blur()`', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + noBlur: 'Do not use element.blur(), instead restore the focus of a previous element.', + }, }, create(context) { return { CallExpression(node) { if (node.callee.property && node.callee.property.name === 'blur') { - context.report({node, message: 'Do not use element.blur(), instead restore the focus of a previous element.'}) + context.report({node, messageId: 'noBlur'}) } }, } diff --git a/lib/rules/no-d-none.js b/lib/rules/no-d-none.js index 64667f40..17031c7b 100644 --- a/lib/rules/no-d-none.js +++ b/lib/rules/no-d-none.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow usage the `d-none` CSS class', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + preferHidden: 'Prefer hidden property to d-none class', + }, }, create(context) { return { @@ -21,7 +27,7 @@ module.exports = { if (invalidArgument) { context.report({ node, - message: 'Prefer hidden property to d-none class', + messageId: 'preferHidden', }) } } diff --git a/lib/rules/no-dataset.js b/lib/rules/no-dataset.js index 948b8732..08ce118f 100644 --- a/lib/rules/no-dataset.js +++ b/lib/rules/no-dataset.js @@ -1,18 +1,24 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'enforce usage of `Element.prototype.getAttribute` instead of `Element.prototype.datalist`', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + useGetAttribute: "Use getAttribute('data-your-attribute') instead of dataset", + }, }, create(context) { return { MemberExpression(node) { if (node.property && node.property.name === 'dataset') { - context.report({node, message: "Use getAttribute('data-your-attribute') instead of dataset."}) + context.report({node, messageId: 'useGetAttribute'}) } }, } diff --git a/lib/rules/no-dynamic-script-tag.js b/lib/rules/no-dynamic-script-tag.js index 7e5513d2..21474ab0 100644 --- a/lib/rules/no-dynamic-script-tag.js +++ b/lib/rules/no-dynamic-script-tag.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'suggestion', docs: { description: 'disallow creating dynamic script tags', - url: require('../url')(module), + url: url(import.meta.url), + recommended: true, }, schema: [], + messages: { + noDynamicScriptTag: "Don't create dynamic script tags, add them in the server template instead.", + }, }, create(context) { @@ -15,13 +21,13 @@ module.exports = { context.report({ node: node.arguments[0], - message: "Don't create dynamic script tags, add them in the server template instead.", + messageId: 'noDynamicScriptTag', }) }, 'AssignmentExpression[left.property.name="type"][right.value="text/javascript"]': function (node) { context.report({ node: node.right, - message: "Don't create dynamic script tags, add them in the server template instead.", + messageId: 'noDynamicScriptTag', }) }, } diff --git a/lib/rules/no-implicit-buggy-globals.js b/lib/rules/no-implicit-buggy-globals.js index 28eebbe1..a38c4d66 100644 --- a/lib/rules/no-implicit-buggy-globals.js +++ b/lib/rules/no-implicit-buggy-globals.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow implicit global variables', - url: require('../url')(module), + url: url(import.meta.url), + recommended: true, }, schema: [], + messages: { + implicitGlobalVariable: 'Implicit global variable, assign as global property instead.', + }, }, create(context) { @@ -26,7 +32,10 @@ module.exports = { (def.type === 'Variable' && def.parent.kind === 'const') || (def.type === 'Variable' && def.parent.kind === 'let') ) { - context.report({node: def.node, message: 'Implicit global variable, assign as global property instead.'}) + context.report({ + node: def.node, + messageId: 'implicitGlobalVariable', + }) } } } diff --git a/lib/rules/no-inner-html.js b/lib/rules/no-inner-html.js index 570e1269..b056e765 100644 --- a/lib/rules/no-inner-html.js +++ b/lib/rules/no-inner-html.js @@ -1,11 +1,17 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow `Element.prototype.innerHTML` in favor of `Element.prototype.textContent`', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + noInnerHTML: 'Using innerHTML poses a potential security risk and should not be used. Prefer using textContent.', + }, }, create(context) { @@ -13,7 +19,7 @@ module.exports = { 'MemberExpression[property.name=innerHTML]': function (node) { context.report({ node: node.property, - message: 'Using innerHTML poses a potential security risk and should not be used. Prefer using textContent.', + messageId: 'noInnerHTML', }) }, } diff --git a/lib/rules/no-innerText.js b/lib/rules/no-innerText.js index 5f024d09..1359c216 100644 --- a/lib/rules/no-innerText.js +++ b/lib/rules/no-innerText.js @@ -1,12 +1,18 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow `Element.prototype.innerText` in favor of `Element.prototype.textContent`', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, fixable: 'code', schema: [], + messages: { + preferTextContent: 'Prefer textContent to innerText', + }, }, create(context) { @@ -22,7 +28,7 @@ module.exports = { fixable: 'code', }, node: node.property, - message: 'Prefer textContent to innerText', + messageId: 'preferTextContent', fix(fixer) { return fixer.replaceText(node.property, 'textContent') }, diff --git a/lib/rules/no-then.js b/lib/rules/no-then.js index e1767145..ea122bef 100644 --- a/lib/rules/no-then.js +++ b/lib/rules/no-then.js @@ -1,20 +1,34 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'suggestion', docs: { description: 'enforce using `async/await` syntax over Promises', - url: require('../url')(module), + url: url(import.meta.url), + recommended: true, }, schema: [], + messages: { + preferAsyncAwait: 'Prefer async/await to Promise.{{method}}()', + }, }, create(context) { return { MemberExpression(node) { if (node.property && node.property.name === 'then') { - context.report({node: node.property, message: 'Prefer async/await to Promise.then()'}) + context.report({ + node: node.property, + messageId: 'preferAsyncAwait', + data: {method: 'then'}, + }) } else if (node.property && node.property.name === 'catch') { - context.report({node: node.property, message: 'Prefer async/await to Promise.catch()'}) + context.report({ + node: node.property, + messageId: 'preferAsyncAwait', + data: {method: 'catch'}, + }) } }, } diff --git a/lib/rules/no-useless-passive.js b/lib/rules/no-useless-passive.js index e472b5b8..7ee50e8f 100644 --- a/lib/rules/no-useless-passive.js +++ b/lib/rules/no-useless-passive.js @@ -1,3 +1,5 @@ +import url from '../url.js' + const passiveEventListenerNames = new Set([ 'touchstart', 'touchmove', @@ -10,15 +12,19 @@ const passiveEventListenerNames = new Set([ const propIsPassiveTrue = prop => prop.key && prop.key.name === 'passive' && prop.value && prop.value.value === true -module.exports = { +export default { meta: { type: 'suggestion', docs: { description: 'disallow marking a event handler as passive when it has no effect', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, fixable: 'code', schema: [], + messages: { + passive: '"{{name}}" event listener is not cancellable and so `passive: true` does nothing.', + }, }, create(context) { @@ -35,7 +41,8 @@ module.exports = { const source = context.sourceCode ?? context.getSourceCode() context.report({ node: passiveProp, - message: `"${name.value}" event listener is not cancellable and so \`passive: true\` does nothing.`, + messageId: 'passive', + data: {name: name.value}, fix(fixer) { const removals = [] if (l === 1) { diff --git a/lib/rules/prefer-observers.js b/lib/rules/prefer-observers.js index 00abd41a..a10cfecc 100644 --- a/lib/rules/prefer-observers.js +++ b/lib/rules/prefer-observers.js @@ -1,15 +1,21 @@ +import url from '../url.js' + const observerMap = { scroll: 'IntersectionObserver', resize: 'ResizeObserver', } -module.exports = { +export default { meta: { type: 'suggestion', docs: { description: 'disallow poorly performing event listeners', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + avoid: 'Avoid using "{{name}}" event listener. Consider using {{observer}} instead', + }, }, create(context) { @@ -20,7 +26,8 @@ module.exports = { if (!(name.value in observerMap)) return context.report({ node, - message: `Avoid using "${name.value}" event listener. Consider using ${observerMap[name.value]} instead`, + messageId: 'avoid', + data: {name: name.value, observer: observerMap[name.value]}, }) }, } diff --git a/lib/rules/require-passive-events.js b/lib/rules/require-passive-events.js index f55044b6..264f0bd6 100644 --- a/lib/rules/require-passive-events.js +++ b/lib/rules/require-passive-events.js @@ -1,3 +1,5 @@ +import url from '../url.js' + const passiveEventListenerNames = new Set([ 'touchstart', 'touchmove', @@ -10,14 +12,18 @@ const passiveEventListenerNames = new Set([ const propIsPassiveTrue = prop => prop.key && prop.key.name === 'passive' && prop.value && prop.value.value === true -module.exports = { +export default { meta: { type: 'suggestion', docs: { description: 'enforce marking high frequency event handlers as passive', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + passive: 'High Frequency Events like "{{name}}" should be `passive: true`', + }, }, create(context) { @@ -28,7 +34,7 @@ module.exports = { if (name.type !== 'Literal') return if (!passiveEventListenerNames.has(name.value)) return if (options && options.type === 'ObjectExpression' && options.properties.some(propIsPassiveTrue)) return - context.report({node, message: `High Frequency Events like "${name.value}" should be \`passive: true\``}) + context.report({node, messageId: 'passive', data: {name: name.value}}) }, } }, diff --git a/lib/rules/unescaped-html-literal.js b/lib/rules/unescaped-html-literal.js index b69dbf08..d8a7c6fd 100644 --- a/lib/rules/unescaped-html-literal.js +++ b/lib/rules/unescaped-html-literal.js @@ -1,16 +1,21 @@ -module.exports = { +import url from '../url.js' + +export default { meta: { type: 'problem', docs: { description: 'disallow unescaped HTML literals', - url: require('../url')(module), + url: url(import.meta.url), + recommended: false, }, schema: [], + messages: { + unescapedHtmlLiteral: 'Unescaped HTML literal. Use html`` tag template literal for secure escaping.', + }, }, create(context) { const htmlOpenTag = /^<[a-zA-Z]/ - const message = 'Unescaped HTML literal. Use html`` tag template literal for secure escaping.' return { Literal(node) { @@ -18,7 +23,7 @@ module.exports = { context.report({ node, - message, + messageId: 'unescapedHtmlLiteral', }) }, TemplateLiteral(node) { @@ -27,7 +32,7 @@ module.exports = { if (!node.parent.tag || node.parent.tag.name !== 'html') { context.report({ node, - message, + messageId: 'unescapedHtmlLiteral', }) } }, diff --git a/lib/url.js b/lib/url.js index 81e96b1d..e58f04a3 100644 --- a/lib/url.js +++ b/lib/url.js @@ -1,10 +1,15 @@ -const {homepage, version} = require('../package.json') -const path = require('path') +import {packageJson} from './utils/commonjs-json-wrappers.cjs' +import path from 'node:path' +import {fileURLToPath} from 'node:url' -module.exports = ({id}) => { +const {homepage, version} = packageJson + +const getUrl = id => { const url = new URL(homepage) - const rule = path.basename(id, '.js') + const rule = path.basename(fileURLToPath(id), '.js') url.hash = '' url.pathname += `/blob/v${version}/docs/rules/${rule}.md` return url.toString() } + +export default getUrl diff --git a/lib/utils/commonjs-json-wrappers.cjs b/lib/utils/commonjs-json-wrappers.cjs new file mode 100644 index 00000000..a8abbf54 --- /dev/null +++ b/lib/utils/commonjs-json-wrappers.cjs @@ -0,0 +1,5 @@ +const svgElementAttributes = require('svg-element-attributes') +const packageJson = require('../../package.json') + +module.exports.svgElementAttributes = svgElementAttributes +module.exports.packageJson = packageJson diff --git a/lib/utils/get-element-type.js b/lib/utils/get-element-type.js index 74e6fe39..3b100a17 100644 --- a/lib/utils/get-element-type.js +++ b/lib/utils/get-element-type.js @@ -1,4 +1,6 @@ -const {elementType, getProp, getLiteralPropValue} = require('jsx-ast-utils') +import jsxAstUtils from 'jsx-ast-utils' + +const {elementType, getProp, getLiteralPropValue} = jsxAstUtils /* Allows custom component to be mapped to an element type. @@ -7,7 +9,7 @@ If a prop determines the type, it can be specified with `props`. For now, we only support the mapping of one prop type to an element type, rather than combinations of props. */ -function getElementType(context, node, lazyElementCheck = false) { +export function getElementType(context, node, lazyElementCheck = false) { const {settings} = context if (lazyElementCheck) { @@ -33,5 +35,3 @@ function getElementType(context, node, lazyElementCheck = false) { // check if the default component is also defined in the configuration return checkConditionalMap ? settings.github.components[rawElement] : rawElement } - -module.exports = {getElementType} diff --git a/lib/utils/get-exported-name.js b/lib/utils/get-exported-name.js index 642f0a0c..7c35c704 100644 --- a/lib/utils/get-exported-name.js +++ b/lib/utils/get-exported-name.js @@ -14,7 +14,7 @@ function getNodeName(node, options) { } } -module.exports = function getExportedName(programNode, options) { +export default function getExportedName(programNode, options) { for (let i = 0; i < programNode.body.length; i += 1) { const node = programNode.body[i] diff --git a/lib/utils/get-role.js b/lib/utils/get-role.js index 54654ee8..39ed91ad 100644 --- a/lib/utils/get-role.js +++ b/lib/utils/get-role.js @@ -1,8 +1,9 @@ -const {getProp, getLiteralPropValue} = require('jsx-ast-utils') -const {elementRoles} = require('aria-query') -const {getElementType} = require('./get-element-type') -const ObjectMap = require('./object-map') +import jsxAstUtils from 'jsx-ast-utils' +import {elementRoles} from 'aria-query' +import {getElementType} from './get-element-type.js' +import ObjectMap from './object-map.js' +const {getProp, getLiteralPropValue} = jsxAstUtils const elementRolesMap = cleanElementRolesMap() /* @@ -41,7 +42,7 @@ function cleanElementRolesMap() { We construct a key and look up the element's role in `elementRolesMap`. If there is no match, we return undefined. */ -function getRole(context, node) { +export function getRole(context, node) { // Early return if role is explicitly set const explicitRole = getLiteralPropValue(getProp(node.attributes, 'role')) if (explicitRole) { @@ -107,5 +108,3 @@ function getRole(context, node) { // Get the elementβs implicit role return elementRolesMap.get(key)?.[0] } - -module.exports = {getRole} diff --git a/lib/utils/is-ignored-filename.js b/lib/utils/is-ignored-filename.js index 18f41153..e945f221 100644 --- a/lib/utils/is-ignored-filename.js +++ b/lib/utils/is-ignored-filename.js @@ -1,5 +1,5 @@ const ignoredFilenames = ['<text>', '<input>'] -module.exports = function isIgnoredFilename(filename) { +export default function isIgnoredFilename(filename) { return ignoredFilenames.indexOf(filename) !== -1 } diff --git a/lib/utils/object-map.js b/lib/utils/object-map.js index 5c54a8bf..08fdabf1 100644 --- a/lib/utils/object-map.js +++ b/lib/utils/object-map.js @@ -1,10 +1,10 @@ // @ts-check -const {isDeepStrictEqual} = require('util') +import {isDeepStrictEqual} from 'node:util' /** * ObjectMap extends Map, but determines key equality using Node.jsβ `util.isDeepStrictEqual` rather than using [SameValueZero](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#key_equality). This makes using objects as keys a bit simpler. */ -module.exports = class ObjectMap extends Map { +export default class ObjectMap extends Map { #data constructor(iterable = []) { diff --git a/lib/utils/parse-filename.js b/lib/utils/parse-filename.js index ce589c71..d36b1af8 100644 --- a/lib/utils/parse-filename.js +++ b/lib/utils/parse-filename.js @@ -1,6 +1,6 @@ -const path = require('path') +import path from 'node:path' -module.exports = function parseFilename(filename) { +export default function parseFilename(filename) { const ext = path.extname(filename) return { diff --git a/package-lock.json b/package-lock.json index 5e029148..06c58b13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,10 +26,11 @@ "eslint-plugin-no-only-tests": "^3.0.0", "eslint-plugin-prettier": "^5.2.1", "eslint-rule-documentation": ">=1.0.0", - "globals": "^15.12.0", + "globals": "^16.0.0", "jsx-ast-utils": "^3.3.2", "prettier": "^3.0.0", "svg-element-attributes": "^1.3.1", + "typescript": "^5.7.3", "typescript-eslint": "^8.14.0" }, "bin": { @@ -74,9 +75,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -110,10 +111,9 @@ } }, "node_modules/@eslint/compat": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.6.tgz", - "integrity": "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==", - "license": "Apache-2.0", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.9.tgz", + "integrity": "sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -148,9 +148,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -181,12 +181,14 @@ } }, "node_modules/@eslint/js": { - "version": "9.19.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", - "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", - "license": "MIT", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -428,14 +430,14 @@ } }, "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", + "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/pkgr" } }, "node_modules/@rtsao/scc": { @@ -465,20 +467,19 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz", - "integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz", + "integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/type-utils": "8.22.0", - "@typescript-eslint/utils": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/type-utils": "8.33.1", + "@typescript-eslint/utils": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -488,21 +489,28 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "engines": { + "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz", - "integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.1.tgz", + "integrity": "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==", + "dependencies": { + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/typescript-estree": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4" }, "engines": { @@ -514,17 +522,36 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.1.tgz", + "integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.33.1", + "@typescript-eslint/types": "^8.33.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz", - "integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz", + "integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0" + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -534,16 +561,30 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz", + "integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz", - "integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz", + "integrity": "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==", "dependencies": { - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/utils": "8.22.0", + "@typescript-eslint/typescript-estree": "8.33.1", + "@typescript-eslint/utils": "8.33.1", "debug": "^4.3.4", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -554,14 +595,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz", + "integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -571,19 +611,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz", + "integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==", + "dependencies": { + "@typescript-eslint/project-service": "8.33.1", + "@typescript-eslint/tsconfig-utils": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -593,14 +634,13 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -609,7 +649,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -621,10 +660,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "bin": { "semver": "bin/semver.js" }, @@ -633,15 +671,14 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz", - "integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.1.tgz", + "integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/typescript-estree": "8.33.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -652,16 +689,15 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz", + "integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.33.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -706,15 +742,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -738,19 +765,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -921,18 +935,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1048,10 +1050,11 @@ ] }, "node_modules/chai": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", - "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -1095,39 +1098,18 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/cliui": { @@ -1162,11 +1144,10 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" } @@ -1354,9 +1335,9 @@ } }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, "engines": { "node": ">=0.3.1" @@ -1706,28 +1687,29 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", - "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", - "license": "MIT", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "bin": { - "eslint-config-prettier": "build/bin/cli.js" + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" }, "peerDependencies": { "eslint": ">=7.0.0" } }, "node_modules/eslint-doc-generator": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eslint-doc-generator/-/eslint-doc-generator-2.0.2.tgz", - "integrity": "sha512-zdPXjnOKuxDf2Wn66aV86IvltboiNDBTgzYZKUmpGEx83anJG2ubptgvajfKhTidfL8QEfDcy9ha4M1uC0HwoQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/eslint-doc-generator/-/eslint-doc-generator-2.1.2.tgz", + "integrity": "sha512-4CzDcFiVaNDxaUYF01bnebGkxKvowp6dyX/USED+4GbKCNTcoopbXZ0Jtb0m4/xYS2ImOajDmgb8HA3njgVMPg==", "dev": true, - "license": "ISC", "dependencies": { "@typescript-eslint/utils": "^8.0.0", "ajv": "^8.11.2", "change-case": "^5.0.0", - "commander": "^12.1.0", + "commander": "^13.0.0", "cosmiconfig": "^9.0.0", "deepmerge": "^4.2.2", "dot-prop": "^9.0.0", @@ -1965,13 +1947,12 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", - "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", - "license": "MIT", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz", + "integrity": "sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==", "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" + "synckit": "^0.11.7" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -1982,7 +1963,7 @@ "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", - "eslint-config-prettier": "*", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "peerDependenciesMeta": { @@ -2237,20 +2218,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2384,10 +2351,9 @@ } }, "node_modules/globals": { - "version": "15.14.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", - "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", - "license": "MIT", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "engines": { "node": ">=18" }, @@ -2597,18 +2563,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3174,25 +3128,24 @@ } }, "node_modules/mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.5.0.tgz", + "integrity": "sha512-VKDjhy6LMTKm0WgNEdlY77YVsD49LZnPSXJAaPNL9NRYQADxvORsyG1DIQY6v53BKTnlNbEE2MbVCDbnxr4K3w==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", @@ -3219,15 +3172,18 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/supports-color": { @@ -3287,15 +3243,6 @@ "semver": "bin/semver" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -3722,9 +3669,9 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "bin": { "prettier": "bin/prettier.cjs" }, @@ -3841,15 +3788,16 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/regexp.prototype.flags": { @@ -4326,18 +4274,17 @@ } }, "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", + "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" + "@pkgr/core": "^0.2.4" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/synckit" } }, "node_modules/text-table": { @@ -4357,10 +4304,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", - "license": "MIT", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "engines": { "node": ">=18.12" }, @@ -4379,11 +4325,6 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4478,10 +4419,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "peer": true, + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4491,14 +4431,13 @@ } }, "node_modules/typescript-eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.22.0.tgz", - "integrity": "sha512-Y2rj210FW1Wb6TWXzQc5+P+EWI9/zdS57hLEc0gnyuvdzWo8+Y8brKlbj0muejonhMI/xAZCnZZwjbIfv1CkOw==", - "license": "MIT", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.1.tgz", + "integrity": "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.22.0", - "@typescript-eslint/parser": "8.22.0", - "@typescript-eslint/utils": "8.22.0" + "@typescript-eslint/eslint-plugin": "8.33.1", + "@typescript-eslint/parser": "8.33.1", + "@typescript-eslint/utils": "8.33.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4509,7 +4448,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/unbox-primitive": { diff --git a/package.json b/package.json index f0c53ac9..9e3f090b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "eslint-plugin-github", "version": "0.0.0-dev", + "type": "module", "description": "An opinionated collection of ESLint shared configs and rules used by GitHub.", "main": "lib/index.js", "entries": [ @@ -48,10 +49,11 @@ "eslint-plugin-no-only-tests": "^3.0.0", "eslint-plugin-prettier": "^5.2.1", "eslint-rule-documentation": ">=1.0.0", - "globals": "^15.12.0", + "globals": "^16.0.0", "jsx-ast-utils": "^3.3.2", "prettier": "^3.0.0", "svg-element-attributes": "^1.3.1", + "typescript": "^5.7.3", "typescript-eslint": "^8.14.0" }, "prettier": "@github/prettier-config", diff --git a/tests/a11y-aria-label-is-well-formatted.js b/tests/a11y-aria-label-is-well-formatted.js index cf244a7e..0dc5ca87 100644 --- a/tests/a11y-aria-label-is-well-formatted.js +++ b/tests/a11y-aria-label-is-well-formatted.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/a11y-aria-label-is-well-formatted') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-aria-label-is-well-formatted.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ parserOptions: { diff --git a/tests/a11y-no-generic-link-text.js b/tests/a11y-no-generic-link-text.js index d59d2034..a3f31ae7 100644 --- a/tests/a11y-no-generic-link-text.js +++ b/tests/a11y-no-generic-link-text.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/a11y-no-generic-link-text') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-no-generic-link-text.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ parserOptions: { diff --git a/tests/a11y-no-title-attribute.js b/tests/a11y-no-title-attribute.js index f87f043f..f2accacf 100644 --- a/tests/a11y-no-title-attribute.js +++ b/tests/a11y-no-title-attribute.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/a11y-no-title-attribute') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-no-title-attribute.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ parserOptions: { diff --git a/tests/a11y-no-visually-hidden-interactive-element.js b/tests/a11y-no-visually-hidden-interactive-element.js index 5879cf3e..c314a881 100644 --- a/tests/a11y-no-visually-hidden-interactive-element.js +++ b/tests/a11y-no-visually-hidden-interactive-element.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/a11y-no-visually-hidden-interactive-element') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-no-visually-hidden-interactive-element.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ parserOptions: { diff --git a/tests/a11y-role-supports-aria-props.js b/tests/a11y-role-supports-aria-props.js index 424c363a..74af5cd8 100644 --- a/tests/a11y-role-supports-aria-props.js +++ b/tests/a11y-role-supports-aria-props.js @@ -10,15 +10,17 @@ // // 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. -const rule = require('../lib/rules/a11y-role-supports-aria-props') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-role-supports-aria-props.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - ecmaFeatures: { - jsx: true, + languageOptions: { + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, }, }, }) diff --git a/tests/a11y-svg-has-accessible-name.js b/tests/a11y-svg-has-accessible-name.js index 62442132..11c2e5af 100644 --- a/tests/a11y-svg-has-accessible-name.js +++ b/tests/a11y-svg-has-accessible-name.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/a11y-svg-has-accessible-name') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/a11y-svg-has-accessible-name.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester({ parserOptions: { diff --git a/tests/array-foreach.js b/tests/array-foreach.js index 4bdac2e2..e75a1ed8 100644 --- a/tests/array-foreach.js +++ b/tests/array-foreach.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/array-foreach') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/array-foreach.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/async-currenttarget.js b/tests/async-currenttarget.js index e34e3dcd..df51e196 100644 --- a/tests/async-currenttarget.js +++ b/tests/async-currenttarget.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/async-currenttarget') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/async-currenttarget.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/async-preventdefault.js b/tests/async-preventdefault.js index f031cc3a..67e6b719 100644 --- a/tests/async-preventdefault.js +++ b/tests/async-preventdefault.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/async-preventdefault') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/async-preventdefault.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/authenticity-token.js b/tests/authenticity-token.js index 86bcfeda..45c40335 100644 --- a/tests/authenticity-token.js +++ b/tests/authenticity-token.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/authenticity-token') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/authenticity-token.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/check-rules.js b/tests/check-rules.js index a55e4725..d40b4c99 100644 --- a/tests/check-rules.js +++ b/tests/check-rules.js @@ -1,8 +1,8 @@ /* globals describe, it*/ -const config = require('../lib/index') -const fs = require('fs') -const assert = require('assert') -const path = require('path') +import config from '../lib/index.js' +import fs from 'node:fs' +import assert from 'node:assert' +import path from 'node:path' describe('smoke tests', () => { it('ensure all rules in lib/rules are included in index', () => { diff --git a/tests/get-attribute.js b/tests/get-attribute.js index 5ae1931d..214fd49e 100644 --- a/tests/get-attribute.js +++ b/tests/get-attribute.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/get-attribute') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/get-attribute.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/js-class-name.js b/tests/js-class-name.js index d02cb1c7..d2bf945a 100644 --- a/tests/js-class-name.js +++ b/tests/js-class-name.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/js-class-name') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/js-class-name.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-blur.js b/tests/no-blur.js index c5e9c380..0b5974fd 100644 --- a/tests/no-blur.js +++ b/tests/no-blur.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-blur') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-blur.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-d-none.js b/tests/no-d-none.js index 5078804a..1fb4cfb0 100644 --- a/tests/no-d-none.js +++ b/tests/no-d-none.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-d-none') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-d-none.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-dataset.js b/tests/no-dataset.js index 2a003b7c..97f0ef3e 100644 --- a/tests/no-dataset.js +++ b/tests/no-dataset.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-dataset') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-dataset.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-dynamic-script-tag.js b/tests/no-dynamic-script-tag.js index b86228ad..e85776a4 100644 --- a/tests/no-dynamic-script-tag.js +++ b/tests/no-dynamic-script-tag.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-dynamic-script-tag') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-dynamic-script-tag.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-implicit-buggy-globals.js b/tests/no-implicit-buggy-globals.js index 8b7bda15..c4399c13 100644 --- a/tests/no-implicit-buggy-globals.js +++ b/tests/no-implicit-buggy-globals.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-implicit-buggy-globals') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-implicit-buggy-globals.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-inner-html.js b/tests/no-inner-html.js index 39587be6..35e02b64 100644 --- a/tests/no-inner-html.js +++ b/tests/no-inner-html.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-inner-html') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-inner-html.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-innerText.js b/tests/no-innerText.js index d7510f90..7fbd59d6 100644 --- a/tests/no-innerText.js +++ b/tests/no-innerText.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-innerText') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-innerText.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-then.js b/tests/no-then.js index d1f71fc1..2013dfe1 100644 --- a/tests/no-then.js +++ b/tests/no-then.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-then') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-then.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/no-useless-passive.js b/tests/no-useless-passive.js index 4676509b..d6e0e084 100644 --- a/tests/no-useless-passive.js +++ b/tests/no-useless-passive.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/no-useless-passive') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/no-useless-passive.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/prefer-observers.js b/tests/prefer-observers.js index 3d7d26ee..e6907fac 100644 --- a/tests/prefer-observers.js +++ b/tests/prefer-observers.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/prefer-observers') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/prefer-observers.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/require-passive-events.js b/tests/require-passive-events.js index 1c15096f..19687264 100644 --- a/tests/require-passive-events.js +++ b/tests/require-passive-events.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/require-passive-events') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/require-passive-events.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/unescaped-html-literal.js b/tests/unescaped-html-literal.js index 78be2611..f9b66ef7 100644 --- a/tests/unescaped-html-literal.js +++ b/tests/unescaped-html-literal.js @@ -1,5 +1,5 @@ -const rule = require('../lib/rules/unescaped-html-literal') -const RuleTester = require('eslint').RuleTester +import rule from '../lib/rules/unescaped-html-literal.js' +import {RuleTester} from 'eslint' const ruleTester = new RuleTester() diff --git a/tests/utils/mocks.js b/tests/utils/mocks.js index 4c923890..090e3409 100644 --- a/tests/utils/mocks.js +++ b/tests/utils/mocks.js @@ -1,4 +1,4 @@ -function mockJSXAttribute(prop, propValue) { +export function mockJSXAttribute(prop, propValue) { return { type: 'JSXAttribute', name: { @@ -16,7 +16,7 @@ function mockJSXAttribute(prop, propValue) { e.g. <Box as={isNavigationOpen ? 'generic' : 'navigation'} /> can be by calling mockJSXConditionalAttribute('as', 'isNavigationOpen', 'generic', 'navigation') */ -function mockJSXConditionalAttribute(prop, expression, consequentValue, alternateValue) { +export function mockJSXConditionalAttribute(prop, expression, consequentValue, alternateValue) { return { type: 'JSXAttribute', name: { @@ -44,7 +44,7 @@ function mockJSXConditionalAttribute(prop, expression, consequentValue, alternat } } -function mockJSXOpeningElement(tagName, attributes = []) { +export function mockJSXOpeningElement(tagName, attributes = []) { return { type: 'JSXOpeningElement', name: { @@ -54,5 +54,3 @@ function mockJSXOpeningElement(tagName, attributes = []) { attributes, } } - -module.exports = {mockJSXAttribute, mockJSXOpeningElement, mockJSXConditionalAttribute}