diff --git a/src/rules/converters.ts b/src/rules/converters.ts index d7846f633..0ce0b08f8 100644 --- a/src/rules/converters.ts +++ b/src/rules/converters.ts @@ -12,7 +12,6 @@ import { convertClassName } from "./converters/class-name"; import { convertCurly } from "./converters/curly"; import { convertCyclomaticComplexity } from "./converters/cyclomatic-complexity"; import { convertEofline } from "./converters/eofline"; -import { convertMemberAccess } from "./converters/member-access"; import { convertFileNameCasing } from "./converters/file-name-casing"; import { convertForin } from "./converters/forin"; import { convertFunctionConstructor } from "./converters/function-constructor"; @@ -25,6 +24,7 @@ import { convertLinebreakStyle } from "./converters/linebreak-style"; import { convertMaxClassesPerFile } from "./converters/max-classes-per-file"; import { convertMaxFileLineCount } from "./converters/max-file-line-count"; import { convertMaxLineLength } from "./converters/max-line-length"; +import { convertMemberAccess } from "./converters/member-access"; import { convertMemberOrdering } from "./converters/member-ordering"; import { convertNewlineBeforeReturn } from "./converters/newline-before-return"; import { convertNewlinePerChainedCall } from "./converters/newline-per-chained-call"; @@ -105,12 +105,14 @@ import { convertPreferObjectSpread } from "./converters/prefer-object-spread"; import { convertPreferReadonly } from "./converters/prefer-readonly"; import { convertPreferTemplate } from "./converters/prefer-template"; import { convertPromiseFunctionAsync } from "./converters/promise-function-async"; +import { convertQuotemark } from "./converters/quotemark"; import { convertRadix } from "./converters/radix"; import { convertRestrictPlusOperands } from "./converters/restrict-plus-operands"; import { convertSemicolon } from "./converters/semicolon"; import { convertSpaceBeforeFunctionParen } from "./converters/space-before-function-paren"; import { convertSpaceWithinParens } from "./converters/space-within-parens"; import { convertSwitchDefault } from "./converters/switch-default"; +import { convertTripleEquals } from "./converters/triple-equals"; import { convertTypedefWhitespace } from "./converters/typedef-whitespace"; import { convertTypeLiteralDelimiter } from "./converters/type-literal-delimiter"; import { convertTypeofCompare } from "./converters/typeof-compare"; @@ -119,8 +121,7 @@ import { convertUnnecessaryBind } from "./converters/unnecessary-bind"; import { convertUnnecessaryConstructor } from "./converters/unnecessary-constructor"; import { convertUseDefaultTypeParameter } from "./converters/use-default-type-parameter"; import { convertUseIsnan } from "./converters/use-isnan"; -import { convertQuotemark } from "./converters/quotemark"; -import { convertTripleEquals } from "./converters/triple-equals"; +import { convertVariableName } from "./converters/variable-name"; /** * Keys TSLint rule names to their ESLint rule converters. @@ -249,6 +250,7 @@ export const converters = new Map([ ["unnecessary-constructor", convertUnnecessaryConstructor], ["use-default-type-parameter", convertUseDefaultTypeParameter], ["use-isnan", convertUseIsnan], + ["variable-name", convertVariableName], // These converters are all for rules that need more complex option conversions. // Some of them will likely need to have notices about changed lint behaviors... @@ -262,7 +264,6 @@ export const converters = new Map([ // ["no-void-expression", convertNoVoidExpression], // (no exact equivalent) // ["quotemark", convertQuotemark], // quotes // ["triple-equals", convertTripleEquals], // eqeqeq - // ["variable-name", convertVariableName], // a bunch of rules... // tslint-microsoft-contrib rules: // ["max-func-body-length", convertMaxFuncBodyLength], diff --git a/src/rules/converters/tests/variable-name.test.ts b/src/rules/converters/tests/variable-name.test.ts new file mode 100644 index 000000000..e98201c20 --- /dev/null +++ b/src/rules/converters/tests/variable-name.test.ts @@ -0,0 +1,331 @@ +import { + convertVariableName, + IgnoreLeadingTrailingUnderscoreMsg, + ForbiddenLeadingTrailingIdentifierMsg, + IgnoreLeadingTrailingIdentifierMsg, + ForbiddenPascalSnakeMsg, + ConstRequiredForAllCapsMsg, + IgnoreOnlyLeadingUnderscoreMsg, + IgnoreOnlyTrailingUnderscoreMsg, +} from "../variable-name"; + +describe(convertVariableName, () => { + test("conversion without arguments", () => { + const result = convertVariableName({ + ruleArguments: [], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with require-const-for-all-caps argument", () => { + const result = convertVariableName({ + ruleArguments: ["require-const-for-all-caps"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg, ConstRequiredForAllCapsMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-pascal-case argument", () => { + const result = convertVariableName({ + ruleArguments: ["allow-pascal-case"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg, ForbiddenPascalSnakeMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-snake-case argument", () => { + const result = convertVariableName({ + ruleArguments: ["allow-snake-case"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg, ForbiddenPascalSnakeMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-leading-underscore without check-format argument", () => { + const result = convertVariableName({ + ruleArguments: ["allow-leading-underscore"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-trailing-underscore without check-format argument", () => { + const result = convertVariableName({ + ruleArguments: ["allow-trailing-underscore"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with check-format argument", () => { + const result = convertVariableName({ + ruleArguments: ["check-format"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreLeadingTrailingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: [], + notices: [ForbiddenLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-leading-underscore and check-format argument", () => { + const result = convertVariableName({ + ruleArguments: ["check-format", "allow-leading-underscore"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreOnlyLeadingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: ["off"], + notices: [IgnoreLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-trailing-underscore and check-format argument", () => { + const result = convertVariableName({ + ruleArguments: ["check-format", "allow-trailing-underscore"], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [IgnoreOnlyTrailingUnderscoreMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: ["off"], + notices: [IgnoreLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with allow-leading-underscore, allow-trailing-underscore and check-format argument", () => { + const result = convertVariableName({ + ruleArguments: [ + "check-format", + "allow-leading-underscore", + "allow-trailing-underscore", + ], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: ["off"], + notices: [IgnoreLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [], + }, + { + ruleName: "id-match", + }, + ], + }); + }); + + test("conversion with all arguments", () => { + const result = convertVariableName({ + ruleArguments: [ + "check-format", + "allow-leading-underscore", + "allow-pascal-case", + "allow-snake-case", + "allow-trailing-underscore", + "require-const-for-all-caps", + "ban-keywords", + ], + }); + + expect(result).toEqual({ + rules: [ + { + ruleName: "camelcase", + notices: [ConstRequiredForAllCapsMsg, ForbiddenPascalSnakeMsg], + }, + { + ruleName: "no-underscore-dangle", + ruleArguments: ["off"], + notices: [IgnoreLeadingTrailingIdentifierMsg], + }, + { + ruleName: "id-blacklist", + ruleArguments: [ + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined", + ], + }, + { + ruleName: "id-match", + }, + ], + }); + }); +}); diff --git a/src/rules/converters/variable-name.ts b/src/rules/converters/variable-name.ts new file mode 100644 index 000000000..1a10009a3 --- /dev/null +++ b/src/rules/converters/variable-name.ts @@ -0,0 +1,109 @@ +import { RuleConverter } from "../converter"; + +export const IgnoreLeadingTrailingUnderscoreMsg = + "Leading and trailing underscores (_) in variable names will now be ignored."; +export const IgnoreOnlyLeadingUnderscoreMsg = + "Leading undescores in variable names will now be ignored."; +export const IgnoreOnlyTrailingUnderscoreMsg = + "Trailing undescores in variable names will now be ignored."; +export const ConstRequiredForAllCapsMsg = + "ESLint's camel-case will throw a warning if const name is not uppercase."; +export const ForbiddenPascalSnakeMsg = + "ESLint's camel-case rule does not allow pascal or snake case variable names. Those cases are reserved for class names and static methods."; +export const IgnoreLeadingTrailingIdentifierMsg = + "Leading and trailing underscores (_) on identifiers will now be ignored."; +export const ForbiddenLeadingTrailingIdentifierMsg = + "Leading or trailing underscores (_) on identifiers will now be forbidden."; + +export const convertVariableName: RuleConverter = tslintRule => { + const hasCheckFormat = tslintRule.ruleArguments.includes("check-format"); + const allowedLeadingUnderscore = tslintRule.ruleArguments.includes("allow-leading-underscore"); + const allowedTrailingUnderscore = tslintRule.ruleArguments.includes( + "allow-trailing-underscore", + ); + const constRequiredForAllCaps = tslintRule.ruleArguments.includes("require-const-for-all-caps"); + const allowPascalSnakeCase = + tslintRule.ruleArguments.includes("allow-pascal-case") || + tslintRule.ruleArguments.includes("allow-snake-case"); + + const getCamelCaseRuleOptions = () => { + const camelCaseOptionNotice: string[] = []; + + if (hasCheckFormat) { + if (!allowedLeadingUnderscore && !allowedTrailingUnderscore) { + camelCaseOptionNotice.push(IgnoreLeadingTrailingUnderscoreMsg); + } else if (allowedLeadingUnderscore && !allowedTrailingUnderscore) { + camelCaseOptionNotice.push(IgnoreOnlyLeadingUnderscoreMsg); + } else if (!allowedLeadingUnderscore && allowedTrailingUnderscore) { + camelCaseOptionNotice.push(IgnoreOnlyTrailingUnderscoreMsg); + } + } else { + camelCaseOptionNotice.push(IgnoreLeadingTrailingUnderscoreMsg); + } + + if (constRequiredForAllCaps) { + camelCaseOptionNotice.push(ConstRequiredForAllCapsMsg); + } + + if (allowPascalSnakeCase) { + camelCaseOptionNotice.push(ForbiddenPascalSnakeMsg); + } + + return { + ruleName: "camelcase", + notices: camelCaseOptionNotice, + }; + }; + + const getUnderscoreDangleRuleOptions = () => { + const underscoreDangleOptionArguments: string[] = []; + const underscoreDangleOptionNotice: string[] = []; + + if (hasCheckFormat && (allowedLeadingUnderscore || allowedTrailingUnderscore)) { + underscoreDangleOptionArguments.push("off"); + underscoreDangleOptionNotice.push(IgnoreLeadingTrailingIdentifierMsg); + } else { + underscoreDangleOptionNotice.push(ForbiddenLeadingTrailingIdentifierMsg); + } + + return { + ruleName: "no-underscore-dangle", + ruleArguments: underscoreDangleOptionArguments, + notices: underscoreDangleOptionNotice, + }; + }; + + const getBlackListRuleOptions = () => { + const blackListOptionArguments: string[] = []; + + if (tslintRule.ruleArguments.includes("ban-keywords")) { + blackListOptionArguments.push( + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined", + ); + } + + return { + ruleName: "id-blacklist", + ruleArguments: blackListOptionArguments, + }; + }; + + return { + rules: [ + getCamelCaseRuleOptions(), + getUnderscoreDangleRuleOptions(), + getBlackListRuleOptions(), + { + ruleName: "id-match", + }, + ], + }; +};