-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lint): deprecation rule for
ESlMediaRuleList.parse
(#2509)
- Loading branch information
Showing
9 changed files
with
300 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import type * as ESTree from 'estree'; | ||
import type {Rule} from 'eslint'; | ||
|
||
const meta: Rule.RuleModule['meta'] = { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'replace deprecated class static methods with recommended ones', | ||
recommended: true | ||
}, | ||
fixable: 'code' | ||
}; | ||
|
||
export interface replacementMethodCfg { | ||
replacement?: string; | ||
message: string; | ||
} | ||
|
||
export interface ESLintDeprecationStaticMethodCfg { | ||
/** Class name */ | ||
className: string; | ||
/** Deprecated static method name */ | ||
deprecatedMethod: string; | ||
/** Function that returns recommended method */ | ||
getReplacemetMethod: (expression: ESTree.CallExpression) => replacementMethodCfg; | ||
} | ||
|
||
type StaticMethodNode = ESTree.MemberExpression & Rule.NodeParentExtension; | ||
|
||
/** Builds deprecation rule from {@link ESLintDeprecationStaticMethodCfg} object */ | ||
export function buildRule(config: ESLintDeprecationStaticMethodCfg): Rule.RuleModule { | ||
const create = (context: Rule.RuleContext): Rule.RuleListener => { | ||
return { | ||
MemberExpression(node: StaticMethodNode): null { | ||
if (isDeprecatedMethod(node, config)) handleCallExpression(node, context, config); | ||
return null; | ||
} | ||
}; | ||
}; | ||
|
||
return {meta, create}; | ||
} | ||
|
||
function isDeprecatedMethod(node: StaticMethodNode, config: ESLintDeprecationStaticMethodCfg): boolean { | ||
const {object, property} = node; | ||
return object.type === 'Identifier' && property.type === 'Identifier' && object.name === config.className && property.name === config.deprecatedMethod; | ||
} | ||
|
||
function handleCallExpression(node: StaticMethodNode, context: Rule.RuleContext, config: ESLintDeprecationStaticMethodCfg): void { | ||
const {replacement, message} = config.getReplacemetMethod(node.parent as ESTree.CallExpression); | ||
|
||
context.report({ | ||
node, | ||
message: `[ESL Lint]: Deprecated static method ${config.className}.${config.deprecatedMethod}, use ${config.className}.${message} instead`, | ||
fix: replacement ? (fixer): Rule.Fix => fixer.replaceText(node.property, replacement) : undefined | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {buildRule} from '../../core/deprecated-class-method'; | ||
import type {replacementMethodCfg} from '../../core/deprecated-class-method'; | ||
|
||
/** | ||
* Rule for deprecated 'parse' method of {@link ESLMediaRuleList} | ||
*/ | ||
export default buildRule({ | ||
className: 'ESLMediaRuleList', | ||
deprecatedMethod: 'parse', | ||
getReplacemetMethod: (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}; | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
import {RuleTester} from 'eslint'; | ||
import {buildRule} from '../src/core/deprecated-class-method'; | ||
|
||
import deprecatedMediaRuleListParse from '../src/rules/4/deprecated.media-rule-list-parse'; | ||
|
||
const VALID_CASES = [ | ||
{ | ||
code: ` | ||
ESLMediaRuleList.parseQuery('1 | 2'); | ||
` | ||
}, { | ||
code: ` | ||
ESLMediaRuleList.parseQuery('1 | 2', String); | ||
` | ||
}, { | ||
code: ` | ||
ESLMediaRuleList.parseTuple('1 | 2', '3|4'); | ||
` | ||
}, { | ||
code: ` | ||
ESLMediaRuleList.parseTuple('1 | 2', '3|4', String); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.newMethodNoArgs(); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.newMethodOneArg('test'); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.newMethodMultipleArgs('test', 42); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.newMethodMultipleArgsNonLiteral(1, 2); | ||
` | ||
}, { | ||
code: ` | ||
AnotherClass.modernMethod(); | ||
` | ||
}, { | ||
code: ` | ||
AnotherClass.modernMethodForManyArgs(1, 2, 3); | ||
` | ||
}, { | ||
code: ` | ||
AnotherClass.modernMethod; | ||
` | ||
}, { | ||
code: ` | ||
const method = AnotherClass.modernMethod; | ||
` | ||
} | ||
]; | ||
|
||
const INVALID_CASES_TEST_CLASS = [ | ||
{ | ||
code: ` | ||
TestClass.oldMethod(); | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodNoArgs instead' | ||
], | ||
output: ` | ||
TestClass.oldMethod(); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.oldMethod(1, () => {}); | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodMultipleArgsNonLiteral instead' | ||
], | ||
output: ` | ||
TestClass.newMethodMultipleArgsNonLiteral(1, () => {}); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.oldMethod('test'); | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodOneArg instead' | ||
], | ||
output: ` | ||
TestClass.newMethodOneArg('test'); | ||
` | ||
}, { | ||
code: ` | ||
TestClass.oldMethod('test', 42); | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method TestClass.oldMethod, use TestClass.newMethodMultipleArgs instead' | ||
], | ||
output: ` | ||
TestClass.newMethodMultipleArgs('test', 42); | ||
` | ||
} | ||
]; | ||
|
||
const INVALID_CASES_RULE_LIST = [ | ||
{ | ||
code: ` | ||
const t = ESLMediaRuleList.parse; | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or parseTuple instead' | ||
], | ||
output: ` | ||
const t = ESLMediaRuleList.parse; | ||
` | ||
}, { | ||
code: ` | ||
ESLMediaRuleList.parse; | ||
`, | ||
errors: [ | ||
'[ESL Lint]: Deprecated static method ESLMediaRuleList.parse, use ESLMediaRuleList.parseQuery or 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', 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'); | ||
`, | ||
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', | ||
deprecatedMethod: 'oldMethod', | ||
getReplacemetMethod: (expression) => { | ||
const args = expression.arguments; | ||
if (args.length === 0) return {message: 'newMethodNoArgs'}; | ||
|
||
let methodName; | ||
if (args.length === 1) methodName = 'newMethodOneArg'; | ||
else if (args.length > 1 && args[args.length - 1].type !== 'Literal' && args[args.length - 1].type !== 'TemplateLiteral') { | ||
methodName = 'newMethodMultipleArgsNonLiteral'; | ||
} | ||
else methodName = 'newMethodMultipleArgs'; | ||
return {message: methodName, replacement: methodName}; | ||
} | ||
}); | ||
|
||
const ruleTester = new RuleTester({ | ||
parser: require.resolve('@typescript-eslint/parser') | ||
}); | ||
|
||
ruleTester.run('deprecated-static-method', rule, {valid: VALID_CASES, invalid: INVALID_CASES_TEST_CLASS}); | ||
}); | ||
|
||
describe('ESL Migration Rules: Deprecated Static Method: valid', () => { | ||
const rule = deprecatedMediaRuleListParse; | ||
|
||
const ruleTester = new RuleTester({ | ||
parser: require.resolve('@typescript-eslint/parser') | ||
}); | ||
|
||
ruleTester.run('deprecated-static-method', rule, {valid: VALID_CASES, invalid: INVALID_CASES_RULE_LIST}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.