diff --git a/CHANGELOG(legacy-4.0.0).md b/CHANGELOG(legacy-4.0.0).md index 7b1aa40d4..58caab092 100644 --- a/CHANGELOG(legacy-4.0.0).md +++ b/CHANGELOG(legacy-4.0.0).md @@ -1,3 +1,21 @@ +# [4.18.0](https://github.com/exadel-inc/esl/compare/v4.17.1...v4.18.0) (2024-07-12) + + +### Bug Fixes + +* **deps:** bump puppeteer from 22.11.1 to 22.11.2 ([8a824cf](https://github.com/exadel-inc/esl/commit/8a824cffc9ba70a56bc877fcf6683fb5a80d9b6f)) +* **deps:** bump puppeteer from 22.11.2 to 22.12.0 ([2a5c371](https://github.com/exadel-inc/esl/commit/2a5c3713c51b55efa37d676d89e815708431072c)) +* **deps:** bump puppeteer from 22.12.0 to 22.12.1 ([56ebbfa](https://github.com/exadel-inc/esl/commit/56ebbfa67a90695aa43c867705bcd16fe5fcc5d6)) +* **deps:** bump webpack from 5.92.0 to 5.92.1 ([6909d17](https://github.com/exadel-inc/esl/commit/6909d1709e32b570af9d8cffb7c0ba509d724ae6)) +* **deps:** bump ws from 7.5.9 to 7.5.10 ([330fd97](https://github.com/exadel-inc/esl/commit/330fd97664ba5276e89ef723e4ca388a201424db)) +* **esl-mixin-element:** major fix for nested hierarchy mixin disconnection ([d360da0](https://github.com/exadel-inc/esl/commit/d360da0e61e90c2ef71ba219256505e741429ca3)), closes [#2505](https://github.com/exadel-inc/esl/issues/2505) + + +### Features + +* **lint:** deprecation rule for `ESlMediaRuleList.parse` ([#2509](https://github.com/exadel-inc/esl/issues/2509)) ([a1f916a](https://github.com/exadel-inc/esl/commit/a1f916ae4cf9a7d618516646e6629ae3a58f3d68)) + + ## [4.17.1](https://github.com/exadel-inc/esl/compare/v4.17.0...v4.17.1) (2024-06-17) diff --git a/e2e/tests/__image_snapshots__/homepage-feature-feature-homepage-looks-fine-test-homepage-footer-on-mobile-1-snap.png b/e2e/tests/__image_snapshots__/homepage-feature-feature-homepage-looks-fine-test-homepage-footer-on-mobile-1-snap.png index 2bef66ade..3fe967ca1 100644 Binary files a/e2e/tests/__image_snapshots__/homepage-feature-feature-homepage-looks-fine-test-homepage-footer-on-mobile-1-snap.png and b/e2e/tests/__image_snapshots__/homepage-feature-feature-homepage-looks-fine-test-homepage-footer-on-mobile-1-snap.png differ diff --git a/eslint/src/core/check-version.ts b/eslint/src/core/check-version.ts index b5447a547..be590963a 100644 --- a/eslint/src/core/check-version.ts +++ b/eslint/src/core/check-version.ts @@ -1,25 +1,23 @@ import {lt} from 'semver'; -import color from 'kleur'; +import {log} from './log'; -const ESL_PACKAGE = '@exadel/esl'; -const PLUGIN_PACKAGE = '@exadel/eslint-plugin-esl'; +export const ESL_PACKAGE = '@exadel/esl'; +export const PLUGIN_PACKAGE = '@exadel/eslint-plugin-esl'; -function getInstalledVersion(packageName: string): string | null { +export function getInstalledVersion(packageName: string): string { try { // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires return require(`${packageName}/package.json`).version; } catch (error) { - return null; + return ''; } } -export function checkVersion(): void { - const eslintVersion = getInstalledVersion(PLUGIN_PACKAGE); - const eslVersion = getInstalledVersion(ESL_PACKAGE); - if (!(eslintVersion && eslVersion && lt(eslintVersion, eslVersion))) return; +export const ESL_PACKAGE_VERSION = getInstalledVersion(ESL_PACKAGE); +export const PLUGIN_PACKAGE_VERSION = getInstalledVersion(PLUGIN_PACKAGE); - console.log(`\n${color.yellow('⚠️ Warning:')} - Your installed version of ${color.yellow(PLUGIN_PACKAGE)} (${color.red(eslintVersion)}) \ -is lower than version of main package ${color.yellow(ESL_PACKAGE)} (${color.green(eslVersion)}). - Please update ${color.yellow(PLUGIN_PACKAGE)} to the latest version ${color.green(eslVersion)}\n`); +if (lt(PLUGIN_PACKAGE_VERSION, ESL_PACKAGE_VERSION)) { + log(`Your installed version of ${PLUGIN_PACKAGE} (${PLUGIN_PACKAGE_VERSION})\ +is lower than version of main package ${ESL_PACKAGE} (${ESL_PACKAGE_VERSION}). +Please update ${PLUGIN_PACKAGE} to the latest version ${ESL_PACKAGE_VERSION}`, 'warn'); } diff --git a/eslint/src/core/deprecated-class-method.ts b/eslint/src/core/deprecated-class-method.ts index b48720981..06a32f863 100644 --- a/eslint/src/core/deprecated-class-method.ts +++ b/eslint/src/core/deprecated-class-method.ts @@ -10,7 +10,7 @@ const meta: Rule.RuleModule['meta'] = { fixable: 'code' }; -export interface replacementMethodCfg { +export interface ESLintReplacementMethodCfg { replacement?: string; message: string; } @@ -21,7 +21,7 @@ export interface ESLintDeprecationStaticMethodCfg { /** Deprecated static method name */ deprecatedMethod: string; /** Function that returns recommended method */ - getReplacementMethod: (expression: ESTree.CallExpression) => replacementMethodCfg; + getReplacementMethod: (expression: ESTree.CallExpression) => ESLintReplacementMethodCfg | string; } type StaticMethodNode = ESTree.MemberExpression & Rule.NodeParentExtension; @@ -46,11 +46,13 @@ function isDeprecatedMethod(node: StaticMethodNode, config: ESLintDeprecationSta } function handleCallExpression(node: StaticMethodNode, context: Rule.RuleContext, config: ESLintDeprecationStaticMethodCfg): void { - const {replacement, message} = config.getReplacementMethod(node.parent as ESTree.CallExpression); + const replCfg = config.getReplacementMethod(node.parent as ESTree.CallExpression); + const message = typeof replCfg === 'string' ? `${config.className}.${replCfg}` : replCfg.message; + const replacement = typeof replCfg === 'string' ? replCfg : replCfg.replacement; context.report({ node, - message: `[ESL Lint]: Deprecated static method ${config.className}.${config.deprecatedMethod}, use ${config.className}.${message} instead`, + message: `[ESL Lint]: Deprecated static method ${config.className}.${config.deprecatedMethod}, use ${message} instead`, fix: replacement ? (fixer): Rule.Fix => fixer.replaceText(node.property, replacement) : undefined }); } diff --git a/eslint/src/core/log.ts b/eslint/src/core/log.ts new file mode 100644 index 000000000..1879bb879 --- /dev/null +++ b/eslint/src/core/log.ts @@ -0,0 +1,29 @@ +import color from 'kleur'; +import type {Rule} from 'eslint'; + +const LOGGERS = { + error: console.error, + warn: console.warn, + off: console.info, +}; +const HEADERS = { + error: color.red('[ESL Lint Plugin] ❌ Error:'), + warn: color.yellow('[ESL Lint Plugin] ⚠️ Warning:'), + off: color.blue('[ESL Lint Plugin] ℹ️ Info:'), +}; + +export function log(msg: string, severity: 'error' | 'warn' | 'off' = 'off'): void { + LOGGERS[severity](`\n${HEADERS[severity]}\n${msg}`); +} + +export function buildLoggingRule(msg: string, severity: 'error' | 'warn' | 'off' = 'off'): Rule.RuleModule { + log(msg, severity); + return { + meta: { + docs: { + description: msg, + } + }, + create: (): Rule.RuleListener => ({}) + }; +} diff --git a/eslint/src/index.ts b/eslint/src/index.ts index 02de6529c..9b4dea5a4 100644 --- a/eslint/src/index.ts +++ b/eslint/src/index.ts @@ -1,13 +1,12 @@ +import './core/check-version'; + import DEPRECATED_4_RULES from './rules/4/all.rules'; import DEPRECATED_5_RULES from './rules/5/all.rules'; -import {checkVersion} from './core/check-version'; import type {Rule} from 'eslint'; export type logLevel = 'warn' | 'error'; -checkVersion(); - const buildDefault = (definition: Record, level: logLevel): Record => { const config: Record = {}; for (const name of Object.keys(definition)) { diff --git a/eslint/src/rules/4/deprecated.media-rule-list-parse.ts b/eslint/src/rules/4/deprecated.media-rule-list-parse.ts index 48e4b1255..2dc15e368 100644 --- a/eslint/src/rules/4/deprecated.media-rule-list-parse.ts +++ b/eslint/src/rules/4/deprecated.media-rule-list-parse.ts @@ -1,16 +1,28 @@ +import {lte} from 'semver'; +import {ESL_PACKAGE_VERSION} from '../../core/check-version'; +import {buildLoggingRule} from '../../core/log'; import {buildRule} from '../../core/deprecated-class-method'; -import type {replacementMethodCfg} from '../../core/deprecated-class-method'; + +import type * as ESTree from 'estree'; +import type {ESLintReplacementMethodCfg} from '../../core/deprecated-class-method'; + +const AVAILABLE_SINCE = '5.0.0-beta.24'; +const isActual = lte(ESL_PACKAGE_VERSION, AVAILABLE_SINCE); /** * Rule for deprecated 'parse' method of {@link ESLMediaRuleList} */ -export default buildRule({ - className: 'ESLMediaRuleList', - deprecatedMethod: 'parse', - getReplacementMethod: (expression): replacementMethodCfg => { - const args = expression.arguments; - if (expression.type !== 'CallExpression') return {message: 'parseQuery or parseTuple'}; - const methodName = args.length === 1 || (args[1]?.type !== 'Literal' && args[1]?.type !== 'TemplateLiteral') ? 'parseQuery' : 'parseTuple'; - return {message: methodName, replacement: methodName}; - } -}); +export default isActual ? + buildRule({ + className: 'ESLMediaRuleList', + deprecatedMethod: 'parse', + getReplacementMethod: (expression): ESLintReplacementMethodCfg | string => { + const args = expression.arguments; + const isLiteral = (node: ESTree.Expression | ESTree.SpreadElement): boolean => node?.type === 'Literal' || node?.type === 'TemplateLiteral'; + if (expression.type === 'CallExpression' && args.length === 1) return 'parseQuery'; + if (expression.type === 'CallExpression' && args.length === 2 && isLiteral(args[1])) return 'parseTuple'; + if (expression.type === 'CallExpression' && args.length === 3) return 'parseTuple'; + return {message: 'ESLMediaRuleList.parseQuery or ESLMediaRuleList.parseTuple'}; + } + }) : + buildLoggingRule(`'ESLMediaRuleList.parse' was updated in v${AVAILABLE_SINCE}. Rule 'deprecated-4/media-rule-list-parse' is skipped.`); diff --git a/eslint/test/deprecated-class-method.test.ts b/eslint/test/deprecated-class-method.test.ts index 3d1ef0d70..bbc4cc217 100644 --- a/eslint/test/deprecated-class-method.test.ts +++ b/eslint/test/deprecated-class-method.test.ts @@ -61,7 +61,7 @@ const INVALID_CASES_TEST_CLASS = [ TestClass.oldMethod(); `, errors: [ - '[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodNoArgs instead' + '[ESL Lint]: Deprecated static method TestClass.oldMethod, use newMethodNoArgs instead' ], output: ` TestClass.oldMethod(); @@ -71,7 +71,7 @@ const INVALID_CASES_TEST_CLASS = [ TestClass.oldMethod(1, () => {}); `, errors: [ - '[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodMultipleArgsNonLiteral instead' + '[ESL Lint]: Deprecated static method TestClass.oldMethod, use newMethodMultipleArgsNonLiteral instead' ], output: ` TestClass.newMethodMultipleArgsNonLiteral(1, () => {}); @@ -81,7 +81,7 @@ const INVALID_CASES_TEST_CLASS = [ TestClass.oldMethod('test'); `, errors: [ - '[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodOneArg instead' + '[ESL Lint]: Deprecated static method TestClass.oldMethod, use newMethodOneArg instead' ], output: ` TestClass.newMethodOneArg('test'); @@ -91,7 +91,7 @@ const INVALID_CASES_TEST_CLASS = [ TestClass.oldMethod('test', 42); `, errors: [ - '[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodMultipleArgs instead' + '[ESL Lint]: Deprecated static method TestClass.oldMethod, use newMethodMultipleArgs instead' ], output: ` TestClass.newMethodMultipleArgs('test', 42); @@ -105,7 +105,7 @@ const INVALID_CASES_RULE_LIST = [ const t = ESLMediaRuleList.parse; `, errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or parseTuple instead' + '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or ESLMediaRuleList.parseTuple instead' ], output: ` const t = ESLMediaRuleList.parse; @@ -115,7 +115,7 @@ const INVALID_CASES_RULE_LIST = [ ESLMediaRuleList.parse; `, errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or parseTuple instead' + '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or ESLMediaRuleList.parseTuple instead' ], output: ` ESLMediaRuleList.parse; @@ -130,16 +130,6 @@ const INVALID_CASES_RULE_LIST = [ output: ` ESLMediaRuleList.parseQuery('1 | 2'); ` - }, { - code: ` - ESLMediaRuleList.parse('1 | 2', String); - `, - errors: [ - '[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery instead' - ], - output: ` - ESLMediaRuleList.parseQuery('1 | 2', String); - ` }, { code: ` ESLMediaRuleList.parse('1 | 2', '3|4');