From 93c90d2678d463c2e5c4c1d3c141db68eb1982fb Mon Sep 17 00:00:00 2001 From: "ala'n (Alexey Stsefanovich)" Date: Thu, 26 Sep 2024 20:36:59 +0200 Subject: [PATCH 1/3] feat(lint): adapt eslint plugin to be used with ESLint 9 --- eslint.config.js | 5 ++++- eslint/package.json | 4 ++-- eslint/src/index.ts | 25 ++++++++++++++++++++++--- eslint/src/rules/4/all.rules.ts | 14 +++++++------- eslint/src/rules/5/all.rules.ts | 8 ++++---- package-lock.json | 4 ++-- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index ebf7b8060..e1eba2183 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,5 +13,8 @@ module.exports = [ ...require('./linting/eslint.config.stylistic'), ...require('./linting/eslint.config.editorconfig'), ...require('./linting/eslint.config.import'), - ...require('./linting/eslint.config.tsdoc') + ...require('./linting/eslint.config.tsdoc'), + + // ESL ESLint Plugin + ...require('@exadel/eslint-plugin-esl').configs.recommended ]; diff --git a/eslint/package.json b/eslint/package.json index 765886d82..477ef1454 100644 --- a/eslint/package.json +++ b/eslint/package.json @@ -27,7 +27,7 @@ "@types/eslint": "^9.6.1" }, "peerDependencies": { - "@exadel/esl": "*", - "eslint": ">=8.0.0" + "@exadel/esl": "^5.0.0 || ^5.0.0-beta.0", + "eslint": ">=8.0.0 || >=9.0.0" } } diff --git a/eslint/src/index.ts b/eslint/src/index.ts index 9b4dea5a4..c70a61e8b 100644 --- a/eslint/src/index.ts +++ b/eslint/src/index.ts @@ -7,11 +7,10 @@ import type {Rule} from 'eslint'; export type logLevel = 'warn' | 'error'; -const buildDefault = (definition: Record, level: logLevel): Record => { +const buildDefault = (definition: Record, level: logLevel, prefix = '@exadel/esl'): Record => { const config: Record = {}; for (const name of Object.keys(definition)) { - const rule = `@exadel/esl/${name}`; - config[rule] = level; + config[`${prefix}/${name}`] = level; } return config; }; @@ -36,3 +35,23 @@ export const configs = { } } }; + +const plugin = { + rules, + configs +}; + +// ESLint 9 compatibility +Object.assign(plugin.configs, { + 'recommended': [{ + plugins: { + '@exadel/esl': plugin + }, + rules: { + ...buildDefault(DEPRECATED_4_RULES, 'error'), + ...buildDefault(DEPRECATED_5_RULES, 'warn') + } + }] +}); + +export default plugin; diff --git a/eslint/src/rules/4/all.rules.ts b/eslint/src/rules/4/all.rules.ts index ead4003a9..121192134 100644 --- a/eslint/src/rules/4/all.rules.ts +++ b/eslint/src/rules/4/all.rules.ts @@ -10,12 +10,12 @@ import deprecatedMediaRuleListParse from './deprecated.media-rule-list-parse'; export default { // Aliases - 'deprecated-4/generate-uid': deprecatedGenerateUid, - 'deprecated-4/deep-compare': deprecatedDeepCompare, - 'deprecated-4/event-utils': deprecatedEventUtils, - 'deprecated-4/traversing-query': deprecatedTraversingQuery, - 'deprecated-4/toggleable-action-params': deprecatedToggleableActionParams, - 'deprecated-4/media-rule-list-parse': deprecatedMediaRuleListParse, + 'deprecated-4-generate-uid': deprecatedGenerateUid, + 'deprecated-4-deep-compare': deprecatedDeepCompare, + 'deprecated-4-event-utils': deprecatedEventUtils, + 'deprecated-4-traversing-query': deprecatedTraversingQuery, + 'deprecated-4-toggleable-action-params': deprecatedToggleableActionParams, + 'deprecated-4-media-rule-list-parse': deprecatedMediaRuleListParse, // Paths - 'deprecated-4/base-decorators-path': deprecatedBaseDecoratorsPath + 'deprecated-4-base-decorators-path': deprecatedBaseDecoratorsPath }; diff --git a/eslint/src/rules/5/all.rules.ts b/eslint/src/rules/5/all.rules.ts index bc1070cf7..edb682750 100644 --- a/eslint/src/rules/5/all.rules.ts +++ b/eslint/src/rules/5/all.rules.ts @@ -4,8 +4,8 @@ import deprecatedPopupActionParams from './deprecated.popup-action-params'; import deprecatedTooltipActionParams from './deprecated.tooltip-action-params'; export default { - 'deprecated-5/alert-action-params': deprecatedAlertActionParams, - 'deprecated-5/panel-action-params': deprecatedPanelActionParams, - 'deprecated-5/popup-action-params': deprecatedPopupActionParams, - 'deprecated-5/tooltip-action-params': deprecatedTooltipActionParams + 'deprecated-5-alert-action-params': deprecatedAlertActionParams, + 'deprecated-5-panel-action-params': deprecatedPanelActionParams, + 'deprecated-5-popup-action-params': deprecatedPopupActionParams, + 'deprecated-5-tooltip-action-params': deprecatedTooltipActionParams }; diff --git a/package-lock.json b/package-lock.json index 678cfb08e..711e751c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,8 +90,8 @@ "@types/eslint": "^9.6.1" }, "peerDependencies": { - "@exadel/esl": "*", - "eslint": ">=8.0.0" + "@exadel/esl": "^5.0.0 || ^5.0.0-beta.0", + "eslint": ">=8.0.0 || >=9.0.0" } }, "node_modules/@11ty/dependency-tree": { From 1dc17076c844113c8b25f80001140753fbe1730d Mon Sep 17 00:00:00 2001 From: "ala'n (Alexey Stsefanovich)" Date: Thu, 26 Sep 2024 21:28:05 +0200 Subject: [PATCH 2/3] test(lint): fix custom plugin lint tests --- eslint/jest.config.js | 1 - eslint/package.json | 2 +- eslint/test/deprecated-alias.invalid.test.ts | 5 +- eslint/test/deprecated-alias.valid.test.ts | 8 +-- eslint/test/deprecated-class-method.test.ts | 74 +------------------- 5 files changed, 6 insertions(+), 84 deletions(-) diff --git a/eslint/jest.config.js b/eslint/jest.config.js index 967a11efe..c65642df0 100644 --- a/eslint/jest.config.js +++ b/eslint/jest.config.js @@ -2,7 +2,6 @@ module.exports = { transform: { '^.+\\.tsx?$': 'ts-jest' }, - testEnvironment: 'jsdom', testRegex: '/test/(.+)\\.test\\.ts$', moduleFileExtensions: ['ts', 'js', 'json'] }; diff --git a/eslint/package.json b/eslint/package.json index 477ef1454..7cf8298f5 100644 --- a/eslint/package.json +++ b/eslint/package.json @@ -15,7 +15,7 @@ ], "scripts": { "prepare": "npm run build", - "test": "", + "test": "jest", "clean": "rimraf dist", "build": "npm run clean && tsc --project tsconfig.build.json" }, diff --git a/eslint/test/deprecated-alias.invalid.test.ts b/eslint/test/deprecated-alias.invalid.test.ts index 6a257ca43..040ee0862 100644 --- a/eslint/test/deprecated-alias.invalid.test.ts +++ b/eslint/test/deprecated-alias.invalid.test.ts @@ -183,10 +183,7 @@ describe('ESL Migration Rules: Deprecated Alias: invalid', () => { deprecation: 'DeprecatedClassName', }); - const ruleTester = new RuleTester({ - // @ts-ignore - parser: require.resolve('@typescript-eslint/parser') - }); + const ruleTester = new RuleTester(); ruleTester.run('../base-rules/deprecated-alias', rule, {valid: [], invalid: INVALID_CASES}); }); diff --git a/eslint/test/deprecated-alias.valid.test.ts b/eslint/test/deprecated-alias.valid.test.ts index d635734c7..d6ec85cb9 100644 --- a/eslint/test/deprecated-alias.valid.test.ts +++ b/eslint/test/deprecated-alias.valid.test.ts @@ -69,10 +69,6 @@ describe('ESL Migration Rules: Deprecated Alias: valid', () => { deprecation: 'DeprecatedClassName', }); - const ruleTester = new RuleTester({ - // @ts-ignore - parser: require.resolve('@typescript-eslint/parser') - }); - - ruleTester.run('../base-rules/deprecated-alias', rule, {valid: VALID_CASES, invalid: []}); + const ruleTester = new RuleTester(); + ruleTester.run('deprecated-alias', rule, {valid: VALID_CASES, invalid: []}); }); diff --git a/eslint/test/deprecated-class-method.test.ts b/eslint/test/deprecated-class-method.test.ts index 1260df8c0..f77a6f369 100644 --- a/eslint/test/deprecated-class-method.test.ts +++ b/eslint/test/deprecated-class-method.test.ts @@ -60,10 +60,7 @@ const INVALID_CASES_TEST_CLASS = [ `, errors: [ '[ESL Lint]: Deprecated static method TestClass.oldMethod, use newMethodNoArgs instead' - ], - output: ` - TestClass.oldMethod(); - ` + ] }, { code: ` TestClass.oldMethod(1, () => {}); @@ -97,70 +94,6 @@ const INVALID_CASES_TEST_CLASS = [ } ]; -const INVALID_CASES_RULE_LIST = [ - { - code: ` - const t = ESLMediaRuleList.parse; - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or ESLMediaRuleList.parseTuple instead' - ], - output: ` - const t = ESLMediaRuleList.parse; - ` - }, { - code: ` - ESLMediaRuleList.parse; - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or ESLMediaRuleList.parseTuple instead' - ], - output: ` - ESLMediaRuleList.parse; - ` - }, { - code: ` - ESLMediaRuleList.parse('1 | 2'); - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery instead' - ], - output: ` - ESLMediaRuleList.parseQuery('1 | 2'); - ` - }, { - code: ` - ESLMediaRuleList.parse('1 | 2', '3|4'); - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseTuple instead' - ], - output: ` - ESLMediaRuleList.parseTuple('1 | 2', '3|4'); - ` - }, { - code: ` - ESLMediaRuleList.parse('1 | 2', \`3|4\`); - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseTuple instead' - ], - output: ` - ESLMediaRuleList.parseTuple('1 | 2', \`3|4\`); - ` - }, { - code: ` - ESLMediaRuleList.parse('1 | 2', '3|4', String); - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseTuple instead' - ], - output: ` - ESLMediaRuleList.parseTuple('1 | 2', '3|4', String); - ` - } -]; - describe('ESL Migration Rules: Deprecated Static Method: valid', () => { const rule = buildRule({ className: 'TestClass', @@ -179,10 +112,7 @@ describe('ESL Migration Rules: Deprecated Static Method: valid', () => { } }); - const ruleTester = new RuleTester({ - // @ts-ignore - parser: require.resolve('@typescript-eslint/parser') - }); + const ruleTester = new RuleTester(); ruleTester.run('deprecated-static-method', rule, {valid: VALID_CASES, invalid: INVALID_CASES_TEST_CLASS}); }); From 334556429dc2f976c669d0662654056ab0876e90 Mon Sep 17 00:00:00 2001 From: "ala'n (Alexey Stsefanovich)" Date: Thu, 26 Sep 2024 21:49:46 +0200 Subject: [PATCH 3/3] fix(lint): fix Literal import processing & update eslint 9.11.1 --- eslint/src/core/deprecated-alias.ts | 4 +++- eslint/src/core/deprecated-path.ts | 2 ++ package-lock.json | 36 +++++++++++++++-------------- package.json | 2 +- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/eslint/src/core/deprecated-alias.ts b/eslint/src/core/deprecated-alias.ts index d8b2e2ada..aa8f721dc 100644 --- a/eslint/src/core/deprecated-alias.ts +++ b/eslint/src/core/deprecated-alias.ts @@ -27,7 +27,7 @@ export function buildRule({deprecation, alias}: ESLintDeprecationCfg): Rule.Rule const create = (context: Rule.RuleContext): Rule.RuleListener => ({ ImportSpecifier(node: ImportNode): null { const importedValue = node.imported; - if (importedValue.name === deprecation) { + if (importedValue.type === 'Identifier' && importedValue.name === deprecation) { context.report({ node, message: `[ESL Lint]: Deprecated alias ${deprecation} for ${alias}`, @@ -61,6 +61,8 @@ function buildFixer(node: ImportNode, context: Rule.RuleContext, alias: string): // eslint-disable-next-line sonarjs/cognitive-complexity function getIdentifierRanges(importNode: ImportNode, context: Rule.RuleContext): (AST.Range | undefined)[] { const root = findRoot(importNode); + if (importNode.imported.type !== 'Identifier' || !root) return []; + const {name} = importNode.imported; const identifiers = findAllBy(context, root, {type: 'Identifier', name}); diff --git a/eslint/src/core/deprecated-path.ts b/eslint/src/core/deprecated-path.ts index 2d69fb74b..393da7bb2 100644 --- a/eslint/src/core/deprecated-path.ts +++ b/eslint/src/core/deprecated-path.ts @@ -26,6 +26,8 @@ export function buildRule(configs: ESLintDeprecationImportCfg | ESLintDeprecatio const create = (context: Rule.RuleContext): Rule.RuleListener => ({ ImportSpecifier(node: ImportNode): null { const importedValue = node.imported; + if (importedValue.type !== 'Identifier') return null; + const importedSource = (node.parent as ESTree.ImportDeclaration).source.value; for (const cfg of configs) { diff --git a/package-lock.json b/package-lock.json index 711e751c6..27121f8fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "concurrently": "^9.0.1", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", - "eslint": "^9.11.0", + "eslint": "^9.11.1", "eslint-plugin-editorconfig": "^4.0.3", "eslint-plugin-import-x": "^4.3.0", "eslint-plugin-sonarjs": "^1.0.4", @@ -1392,6 +1392,14 @@ "node": "*" } }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -1463,7 +1471,6 @@ "version": "9.11.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==", - "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -3930,9 +3937,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -7819,19 +7826,22 @@ } }, "node_modules/eslint": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", - "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz", + "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.0", + "@eslint/js": "9.11.1", "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -8356,14 +8366,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", - "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", diff --git a/package.json b/package.json index 461befe87..e82ebd8b2 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "concurrently": "^9.0.1", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", - "eslint": "^9.11.0", + "eslint": "^9.11.1", "eslint-plugin-editorconfig": "^4.0.3", "eslint-plugin-import-x": "^4.3.0", "eslint-plugin-sonarjs": "^1.0.4",