From e7b2fa724eb53bde48c17edc56cbe4530a82aa58 Mon Sep 17 00:00:00 2001 From: Rafael Santana Date: Sat, 9 Feb 2019 17:31:51 -0300 Subject: [PATCH] refactor(rule): drop deprecated 'pipe-naming' (#745) --- README.md | 1 - src/index.ts | 1 - src/pipeNamingRule.ts | 133 -------------------------------- test/pipeNamingRule.spec.ts | 149 ------------------------------------ 4 files changed, 284 deletions(-) delete mode 100644 src/pipeNamingRule.ts delete mode 100644 test/pipeNamingRule.spec.ts diff --git a/README.md b/README.md index de5a0c1e6..a091c71e6 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,6 @@ Below you can find a recommended configuration which is based on the [Angular St | `no-unused-css` | _Experimental_ | | `template-conditional-complexity` | _Experimental_ | | `angular-whitespace` | _Deprecated_ | -| `pipe-naming` | _Deprecated_ | ## Disable a rule that validates Template or Styles diff --git a/src/index.ts b/src/index.ts index c3e49e849..4a2e192b3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,6 @@ export { Rule as NoQueriesParameterRule } from './noQueriesParameterRule'; export { Rule as NoTemplateCallExpressionRule } from './noTemplateCallExpressionRule'; export { Rule as NoUnusedCssRule } from './noUnusedCssRule'; export { Rule as PipeImpureRule } from './pipeImpureRule'; -export { Rule as PipeNamingRule } from './pipeNamingRule'; export { Rule as PipePrefixRule } from './pipePrefixRule'; export { Rule as PreferInlineDecorator } from './preferInlineDecoratorRule'; export { Rule as PreferOutputReadonlyRule } from './preferOutputReadonlyRule'; diff --git a/src/pipeNamingRule.ts b/src/pipeNamingRule.ts deleted file mode 100644 index a52c58322..000000000 --- a/src/pipeNamingRule.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { sprintf } from 'sprintf-js'; -import * as Lint from 'tslint'; -import * as ts from 'typescript'; -import { NgWalker } from './angular/ngWalker'; -import { SelectorValidator } from './util/selectorValidator'; -import { getDecoratorArgument } from './util/utils'; - -const OPTION_ATTRIBUTE = 'attribute'; -const OPTION_CAMEL_CASE = 'camelCase'; -const OPTION_KEBAB_CASE = 'kebab-case'; - -export class Rule extends Lint.Rules.AbstractRule { - static readonly metadata: Lint.IRuleMetadata = { - deprecationMessage: `You can name your pipes only ${OPTION_CAMEL_CASE}. If you try to use snake-case then your application will not compile. For prefix validation use pipe-prefix rule.`, - description: 'Enforce consistent case and prefix for pipes.', - optionExamples: [ - [true, OPTION_CAMEL_CASE, 'myPrefix'], - [true, OPTION_CAMEL_CASE, 'myPrefix', 'myOtherPrefix'], - [true, OPTION_KEBAB_CASE, 'my-prefix'] - ], - options: { - items: [ - { - enum: [OPTION_KEBAB_CASE, OPTION_ATTRIBUTE] - }, - { - type: 'string' - } - ], - minLength: 1, - type: 'array' - }, - optionsDescription: Lint.Utils.dedent` - * The first item in the array is \`${OPTION_CAMEL_CASE}\` or \`${OPTION_KEBAB_CASE}\`, which allows you to pick a case. - * The rest of the arguments are supported prefixes (given as strings). They are optional. - `, - rationale: 'Consistent conventions make it easy to quickly identify and reference assets of different types.', - ruleName: 'pipe-naming', - type: 'style', - typescriptOnly: true - }; - - static FAILURE_WITHOUT_PREFIX = `The name of the Pipe decorator of class %s should be named ${OPTION_CAMEL_CASE}, however its value is "%s"`; - - static FAILURE_WITH_PREFIX = `The name of the Pipe decorator of class %s should be named ${OPTION_CAMEL_CASE} with prefix %s, however its value is "%s"`; - - prefix!: string; - hasPrefix!: boolean; - private prefixChecker!: Function; - private validator!: Function; - - constructor(options: Lint.IOptions) { - super(options); - - let args = options.ruleArguments; - if (!(args instanceof Array)) { - args = [args]; - } - if (args[0] === OPTION_CAMEL_CASE) { - this.validator = SelectorValidator.camelCase; - } - if (args.length > 1) { - this.hasPrefix = true; - let prefixExpression = (args.slice(1) || []).join('|'); - this.prefix = (args.slice(1) || []).join(','); - this.prefixChecker = SelectorValidator.prefix(prefixExpression, OPTION_CAMEL_CASE); - } - } - - apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new ClassMetadataWalker(sourceFile, this)); - } - - isEnabled(): boolean { - const { - metadata: { - options: { minLength } - } - } = Rule; - const { length } = this.ruleArguments; - - return super.isEnabled() && length >= minLength; - } - - validateName(name: string): boolean { - return this.validator(name); - } - - validatePrefix(prefix: string): boolean { - return this.prefixChecker(prefix); - } -} - -export class ClassMetadataWalker extends NgWalker { - constructor(sourceFile: ts.SourceFile, private rule: Rule) { - super(sourceFile, rule.getOptions()); - } - - protected visitNgPipe(controller: ts.ClassDeclaration, decorator: ts.Decorator) { - let className = controller.name!.text; - this.validateProperties(className, decorator); - super.visitNgPipe(controller, decorator); - } - - private validateProperties(className: string, pipe: ts.Decorator) { - const argument = getDecoratorArgument(pipe)!; - - argument.properties - .filter(p => p.name && ts.isIdentifier(p.name) && p.name.text === 'name') - .forEach(this.validateProperty.bind(this, className)); - } - - private validateProperty(className: string, property: ts.Node) { - const initializer = ts.isPropertyAssignment(property) ? property.initializer : undefined; - - if (initializer && ts.isStringLiteral(initializer)) { - const propName = initializer.text; - const isValidName = this.rule.validateName(propName); - const isValidPrefix = this.rule.hasPrefix ? this.rule.validatePrefix(propName) : true; - - if (!isValidName || !isValidPrefix) { - this.addFailureAtNode(property, this.getFailureMessage(className, propName)); - } - } - } - - private getFailureMessage(className: string, pipeName: string): string { - if (this.rule.hasPrefix) { - return sprintf(Rule.FAILURE_WITH_PREFIX, className, this.rule.prefix, pipeName); - } - return sprintf(Rule.FAILURE_WITHOUT_PREFIX, className, pipeName); - } -} diff --git a/test/pipeNamingRule.spec.ts b/test/pipeNamingRule.spec.ts deleted file mode 100644 index 55c3e7ad6..000000000 --- a/test/pipeNamingRule.spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { assertSuccess, assertAnnotated } from './testHelper'; - -describe('pipe-naming', () => { - describe('invalid pipe name', () => { - it('should fail when Pipe is named camelCase without prefix ng', () => { - let source = ` - @Pipe({ - name: 'foo-bar' - ~~~~~~~~~~~~~~~ - }) - class Test {} - `; - assertAnnotated({ - ruleName: 'pipe-naming', - message: - 'The name of the Pipe decorator of class Test should be named ' + 'camelCase with prefix ng, however its value is "foo-bar"', - source, - options: ['camelCase', 'ng'] - }); - }); - - it('should fail when Pipe is named camelCase without prefix applying multiple prefixes', () => { - let source = ` - @Pipe({ - name: 'foo-bar' - ~~~~~~~~~~~~~~~ - }) - class Test {} - `; - assertAnnotated({ - ruleName: 'pipe-naming', - message: - 'The name of the Pipe decorator of class Test should be named camelCase' + - ' with prefix ng,mg,sg, however its value is "foo-bar"', - source, - options: ['camelCase', 'ng', 'mg', 'sg'] - }); - }); - - it('should fail when Pipe is named camelCase and has longer prefix', () => { - let source = ` - @Pipe({ - name: 'fooBar' - ~~~~~~~~~~~~~~ - }) - class Test {} - `; - assertAnnotated({ - ruleName: 'pipe-naming', - message: - 'The name of the Pipe decorator of class Test should be named camelCase ' + 'with prefix fo,mg,sg, however its value is "fooBar"', - source, - options: ['camelCase', 'fo', 'mg', 'sg'] - }); - }); - - it('should fail when Pipe is not named camelCase without prefix', () => { - let source = ` - @Pipe({ - name: 'foo-bar' - ~~~~~~~~~~~~~~~ - }) - class Test {} - `; - assertAnnotated({ - ruleName: 'pipe-naming', - message: 'The name of the Pipe decorator of class Test should be named camelCase,' + ' however its value is "foo-bar"', - source, - options: 'camelCase' - }); - }); - }); - - describe('empty pipe', () => { - it('should not fail when @Pipe not invoked', () => { - let source = ` - @Pipe - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase', 'ng']); - }); - }); - - describe('pipe with name as variable', () => { - it('should ignore the rule when the name is a variable', () => { - const source = ` - export function mockPipe(name: string): any { - @Pipe({ name }) - class MockPipe implements PipeTransform { - transform(input: any): any { - return input; - } - } - return MockPipe; - } - `; - assertSuccess('pipe-naming', source, ['camelCase', 'ng']); - }); - }); - - describe('valid pipe name', () => { - it('should succeed when set valid name with prefix ng in @Pipe', () => { - let source = ` - @Pipe({ - name: 'ngBarFoo' - }) - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase', 'ng']); - }); - - it('should succeed when set valid name applying multiple prefixes in @Pipe', () => { - let source = ` - @Pipe({ - name: 'ngBarFoo' - }) - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase', 'ng', 'sg', 'mg']); - }); - - it('should succeed when set valid name in @Pipe', () => { - let source = ` - @Pipe({ - name: 'barFoo' - }) - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase']); - }); - - it('should succeed when the class is not a Pipe', () => { - let source = ` - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase']); - }); - it('should do nothing if the name of the pipe is not a literal', () => { - let source = ` - const pipeName = 'foo-bar'; - @Pipe({ - name: pipeName - }) - class Test {} - `; - assertSuccess('pipe-naming', source, ['camelCase']); - }); - }); -});