Skip to content

Commit

Permalink
Merge pull request #2510 from exadel-inc/fix/eslint-media-parse-rule
Browse files Browse the repository at this point in the history
refactor(lint): fix deprecated-4/media-rule-list-parse rule according live testing notes and introduced utilities
  • Loading branch information
ala-n committed Jul 12, 2024
2 parents 40045dd + 81dae45 commit 93607ec
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 47 deletions.
24 changes: 11 additions & 13 deletions eslint/src/core/check-version.ts
Original file line number Diff line number Diff line change
@@ -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');
}
10 changes: 6 additions & 4 deletions eslint/src/core/deprecated-class-method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const meta: Rule.RuleModule['meta'] = {
fixable: 'code'
};

export interface replacementMethodCfg {
export interface ESLintReplacementMethodCfg {
replacement?: string;
message: string;
}
Expand All @@ -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;
Expand All @@ -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
});
}
29 changes: 29 additions & 0 deletions eslint/src/core/log.ts
Original file line number Diff line number Diff line change
@@ -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 => ({})
};
}
5 changes: 2 additions & 3 deletions eslint/src/index.ts
Original file line number Diff line number Diff line change
@@ -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<string, Rule.RuleModule>, level: logLevel): Record<string, logLevel> => {
const config: Record<string, logLevel> = {};
for (const name of Object.keys(definition)) {
Expand Down
34 changes: 23 additions & 11 deletions eslint/src/rules/4/deprecated.media-rule-list-parse.ts
Original file line number Diff line number Diff line change
@@ -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.`);
22 changes: 6 additions & 16 deletions eslint/test/deprecated-class-method.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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, () => {});
Expand All @@ -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');
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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');
Expand Down

0 comments on commit 93607ec

Please sign in to comment.