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');