mgechev / codelyzer Goto Github PK
View Code? Open in Web Editor NEWStatic analysis for Angular projects.
Home Page: http://codelyzer.com/
License: MIT License
Static analysis for Angular projects.
Home Page: http://codelyzer.com/
License: MIT License
The official Angular Style Guide has a rule called "Import Destructuring Spacing" that says that one space should be present after the opening brace and before the closing brace of import
statements. For example:
Bad
import {Component, EventEmitter} from '@angular/core';
Good
import { Component, EventEmitter } from '@angular/core';
This rule should probably also be applied to export
statements inside barrels.
I got a report that something like import * as foo from './foo'
makes it cry.
So a reminder to fix it.
A non-typescript version would be nice! is this on your roadmap?
contribution guidelines are missing :)
when #31 will be merged, I can add basic guideline, because it will be easy as
I'm a fan of concise code and naming (not obscure acronyms , just short names). So I like to keep my component names short. For example:
@Component({
selector: 'transaction'
})
This throws a no-kebab-case warning. IMO a simple string without any capitalisation or special characters should pass this rule and not fail.
@mgechev, bug or just different opinions?
Create Angular 2 specific visitor which extends SyntaxWalker
with methods like:
visitDecorator
visitDirective
visitComponent
visitHostListener
visitHostBinding
visitInput
visitOutput
/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/codelyzer/noAttributeParameterDecoratorRule.js:30
var parentName = node.parent.name.text;
^
TypeError: Cannot read property 'text' of undefined
at ConstructorMetadataWalker.visitConstructorDeclaration (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/codelyzer/noAttributeParameterDecoratorRule.js:30:42)
at ConstructorMetadataWalker.SyntaxWalker.visitNode (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/tslint/lib/language/walker/syntaxWalker.js:264:22)
at /Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/tslint/lib/language/walker/syntaxWalker.js:441:63
at visitEachNode (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/typescript/lib/typescript.js:7255:30)
at Object.forEachChild (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/typescript/lib/typescript.js:7484:21)
at ConstructorMetadataWalker.SyntaxWalker.walkChildren (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/tslint/lib/language/walker/syntaxWalker.js:441:12)
at ConstructorMetadataWalker.SyntaxWalker.visitNode (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/tslint/lib/language/walker/syntaxWalker.js:435:22)
at /Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/tslint/lib/language/walker/syntaxWalker.js:441:63
at visitNode (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/typescript/lib/typescript.js:7243:20)
at Object.forEachChild (/Users/bsmith/Development/git/qasymphony/kitsune-ui/node_modules/typescript/lib/typescript.js:7303:21)
A gist of the file: here
tslint.json: here
tsc -v
Version 1.8.10
tslint -v
3.9.0
If we force our prefix to be my
it will accept mys-foo
or any string that starts with my
actually.
Perhaps I am a bit nitpick here, but I just realized this when I was trying to report anything else :P
If I have the following, would it be possible for the rule use-life-cycle-interface
to not throw a lint error?
class Parent implements OnInit {
public ngOnInit() {
}
}
class Child extends Parent {
public ngOnInit() {
super.ngOnInit();
}
}
This selector is not passing the checker:
@Component({
selector: 'abc.xyz'
})
class Foo {...}
it supposed to target <abc class="xyz"></abc>
.
We currently need typescript@next to have a bug with Promise.all fixed (among others). But codelyzer does not work with that Typescript version:
The following error message is printed:
Error: Unsupported TypeScript version: 2.1.0-dev.20160725
at Object.current (D:\...\node_modules\codelyzer\util\syntaxKind.js:1796:23)
at ClassMetadataWalker.visitClassDeclaration (D:\...\node_modules\codelyzer\useLifeCycleInterfaceRule.js:40:37)
at ClassMetadataWalker.SyntaxWalker.visitNode (D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:264:22)
at D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:459:63
at visitEachNode (D:\...\node_modules\typescript\lib\typescript.js:8115:30)
at Object.forEachChild (D:\...\node_modules\typescript\lib\typescript.js:8273:24)
at ClassMetadataWalker.SyntaxWalker.walkChildren (D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:459:12)
at ClassMetadataWalker.SyntaxWalker.visitSourceFile (D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:190:14)
at ClassMetadataWalker.SyntaxWalker.visitNode (D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:414:22)
at ClassMetadataWalker.SyntaxWalker.walk (D:\...\node_modules\tslint\lib\language\walker\syntaxWalker.js:7:14)
npm ERR! Windows_NT 6.1.7601
npm ERR! argv "c:\\Program Files\\nodejs\\node.exe" "C:\\Users\\...\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "run" "tslint"
npm ERR! node v6.3.1
npm ERR! npm v3.10.6
npm ERR! code ELIFECYCLE
npm ERR! [email protected] tslint: `tslint -c ./node_modules/.../tslint.json --force ./app/**/*.ts`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] tslint script 'tslint -c ./node_modules/.../tslint.json --force ./app/**/*.ts'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the ... package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! tslint -c ./node_modules/.../tslint.json --force ./app/**/*.ts
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs ...
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls ...
npm ERR! There is likely additional logging output above.
I'm sorry if this is already available, but I can't find the right configuration in my tslint.json
file to get this working.
For components and directives, when using a class selector, I think it would be better to keep to the Google CSS style guides in mind and not use camelCase
but kebab-case
, with or without a prefix.
It would be cool to have usage in docs, because it is not immediately obvious how to use this tool. :)
@chuckjaz implemented much more advanced metadata reader which soon will land in the Angular 2 official repository angular/angular#7492.
We can use both:
MetadataReader
, for the module which warns/ensures correctness of the program.Evaluator
for the linting module, which can help us get "foldable" values.// cc @preslavsh
Error: Unsupported TypeScript version: 2.0.0-dev.20160703
please :)
On a code like this one
import {Component, Provider, forwardRef} from "@angular/core";
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
CORE_DIRECTIVES
} from "@angular/common";
const noop = () => {
};
const TAGS_INPUT_CONTROL_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, {
useExisting: forwardRef(() => TagsInput),
multi: true
});
noForwardRefRule throws an exception :
TypeError: Cannot read property 'text' of undefined
at ExpressionCallMetadataWalker.validateCallExpression
((..)/node_modules/codelyzer/noForwardRefRule.js:36:50)
seems that failureConfig is using a currentNode without name : from codelyzer/noForwardRefRule.js
ExpressionCallMetadataWalker.prototype.validateCallExpression = function (callExpression) {
if (callExpression.expression.text === 'forwardRef') {
var currentNode = callExpression;
while (currentNode.parent.parent) {
currentNode = currentNode.parent;
}
var failureConfig = [currentNode.name.text]; // <<<<<<<< HERE
/// quick fix below without understanding of tslint/codelyzer internals :)
/// var failureConfig = [currentNode.name ? currentNode.name.text : "" ];
failureConfig.unshift(Rule.FAILURE_STRING);
this.addFailure(this.createFailure(callExpression.getStart(), callExpression.getWidth(), sprintf_js_1.sprintf.apply(this, failureConfig)));
}
};
There is currently no way to lint the templates and check whether the selectors are correctly written or even if they are closed. for example if I have a component Sample with selector sample and then in a different file I have :
Import Sample from './sample.ts';
@Component({
selector: 'example',
template: `<samples></samples>`
})
This currently doesn't produce any linting errors, although samples is neither a native html selector nor the selector of the imported file sample.ts.
another example is having template: '<sampl></sample>'
. I believe that there should be simple parsing for the templates (at least the inline ones).
first thanks for this I have been struggling on how to enforce this rules, I just installed this and tried it it worked without the Recommended configuration, but once I add those it gives me this error (with tslint cli):
global tslint v: 3.9.0
/home/yahya/.nvm/versions/node/v5.10.1/lib/node_modules/tslint/lib/ruleLoader.js:29
throw new Error(errorMessage);
^
Error: Could not find the following rules specified in the configuration:
directive-selector-prefix
component-selector-prefix
use-input-property-decorator
use-output-property-decorator
use-host-property-decorator
no-attribute-parameter-decorator
no-input-rename
no-output-rename
no-forward-ref
use-life-cycle-interface
use-pipe-transform-interface
pipe-naming
component-class-suffix
directive-class-suffix
at Object.loadRules (/home/yahya/.nvm/versions/node/v5.10.1/lib/node_modules/tslint/lib/ruleLoader.js:29:15)
at Linter.lint (/home/yahya/.nvm/versions/node/v5.10.1/lib/node_modules/tslint/lib/tslint.js:25:44)
at processFile (/home/yahya/.nvm/versions/node/v5.10.1/lib/node_modules/tslint/lib/tslint-cli.js:118:29)
at Array.forEach (native)
at Object. (/home/yahya/.nvm/versions/node/v5.10.1/lib/node_modules/tslint/lib/tslint-cli.js:128:41)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Module.require (module.js:367:17)
with gulp tslint:
local tslint v: 3.9.0
gulp-tslint v:5.0.0
/var/www/Work/card/node_modules/gulp-tslint/node_modules/tslint/lib/ruleLoader.js:29
throw new Error(errorMessage);
^
Error: Could not find the following rules specified in the configuration:
no-trailing-comma
directive-selector-prefix
component-selector-prefix
use-input-property-decorator
use-output-property-decorator
use-host-property-decorator
no-attribute-parameter-decorator
no-input-rename
no-output-rename
no-forward-ref
use-life-cycle-interface
use-pipe-transform-interface
pipe-naming
component-class-suffix
directive-class-suffix
at Object.loadRules (/var/www/Work/card/node_modules/gulp-tslint/node_modules/tslint/lib/ruleLoader.js:29:15)
at Linter.lint (/var/www/Work/card/node_modules/gulp-tslint/node_modules/tslint/lib/tslint.js:25:44)
at /var/www/Work/card/node_modules/gulp-tslint/index.js:95:34
at respond (/var/www/Work/card/node_modules/gulp-tslint/node_modules/rcloader/index.js:68:7)
at respond (/var/www/Work/card/node_modules/gulp-tslint/node_modules/rcloader/node_modules/rcfinder/index.js:140:7)
at /var/www/Work/card/node_modules/gulp-tslint/node_modules/rcloader/node_modules/rcfinder/index.js:124:17
at /var/www/Work/card/node_modules/gulp-tslint/node_modules/rcloader/node_modules/rcfinder/index.js:77:13
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
In case the file looks like:
@Directive(...)
class Foo {
@Input('bar') bar;
}
This is not a rename but the rule will throw an error. The assertion should be slightly refactored.
Latest update of this library is confusing the following 2 rules:
So if you have a selector app, the error you get is the the kebab-case (05-02) error instead of the custom prefix error. Could it be updated so that kebab-case is proper checking where app would not fail? That way if a user would want to turn off the custom prefix rule but keep the kebab case rule, they could.
I'd like to forbid imports to a certain file to avoid that too much code is loaded even if not all is used. As an example I want to import rxjs. I do that through
import {Observable} from 'rxjs/Rx';
and wow, I have all the operators available and no further import statement has to be made. But this loads all the 100 operators event if I just need the 'map' operator. What I should import is only
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/map';
I'd like to tell codelyzer that 'rxjs/Rx' is a forbidden import.
According to https://angular.io/docs/ts/latest/guide/dependency-injection.html
ALWAYS INCLUDE THE PARENTHESES
Always write @Injectable(), not just @Injectable. Our application will fail mysteriously if we forget the parentheses.
It would be great if codelyzer could enforce this as a tslint rule (unless it's already enforced somehow?)
I was giving a try to the new import-destructuring-spacing
rule, and it breaks in our codebase on imports that use an alias:
import * as moment from 'moment';
produces You need to leave whitespaces inside of the import statement's curly braces
.
It would be better if that was ignored (but perhaps I'm missing something).
I've started a fork with some changes around creating a fileNameBase rule with the idea of eventually getting to supporting the styleguide's concept of kebab-case (configurable of course) with .component.ts suffix's.
I've never written any sort of linting rule before so this is all new to me, so I appologize if I seem like a newb but i'm running into some trouble. First off I recognize that my rule right now will just always fail, that's just my first step...
After transpiling the rule and getting it to run i hit the following error:
TypeError: Cannot read property 'call' of undefined
at FileNameValidatorWalker.visitClassDeclaration (C:\extras\projectx\authoring-ui\node_modules\ng2lint\dist\src\fileNameBase.js:44:37)
at FileNameValidatorWalker.SyntaxWalker.visitNode (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:255:22)
at C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:441:63
at visitEachNode (C:\extras\projectx\authoring-ui\node_modules\typescript\lib\typescript.js:7209:30)
at Object.forEachChild (C:\extras\projectx\authoring-ui\node_modules\typescript\lib\typescript.js:7360:24)
at FileNameValidatorWalker.SyntaxWalker.walkChildren (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:441:12)
at FileNameValidatorWalker.SyntaxWalker.visitSourceFile (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:181:14)
at FileNameValidatorWalker.SyntaxWalker.visitNode (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:396:22)
at FileNameValidatorWalker.SyntaxWalker.walk (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\walker\syntaxWalker.js:7:14)
at Rule.AbstractRule.applyWithWalker (C:\extras\projectx\authoring-ui\node_modules\tslint\lib\language\rule\abstractRule.js:19:16)
which is just:
_super.visitClassDeclaration.call(this, node);
which is exactly the same as what is in (transpiled version of) the selectorNameBase.ts
file that I based this on.
Thoughts?
In the Ng2Walker
verify that the decorators to visit are imported from angular2/core
.
Using Typescript 1.8.10, tslint 3.10.2 and codelyzer 0.0.19, I get a crash when evaluating the following code:
const CUSTOM_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => CountryListValueAccessor)});
This is what appears in the log, executed via Webstorm:
2016-06-03 09:28:23,062 [421353309] INFO - avascript.linter.tslint.TsLint - TsLint inner error. TsLint version: 3.10.2
/usr/local/lib/node_modules/codelyzer/noForwardRefRule.js:36
var failureConfig = [currentNode.name.text];
^
TypeError: Cannot read property 'text' of undefined
at ExpressionCallMetadataWalker.validateCallExpression (/usr/local/lib/node_modules/codelyzer/noForwardRefRule.js:36:50)
at ExpressionCallMetadataWalker.visitCallExpression (/usr/local/lib/node_modules/codelyzer/noForwardRefRule.js:27:14)
at ExpressionCallMetadataWalker.SyntaxWalker.visitNode (/usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:249:22)
at /usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:447:63
at visitNode (/usr/local/lib/node_modules/typescript/lib/typescript.js:7243:20)
at Object.forEachChild (/usr/local/lib/node_modules/typescript/lib/typescript.js:7303:21)
at ExpressionCallMetadataWalker.SyntaxWalker.walkChildren (/usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:447:12)
at ExpressionCallMetadataWalker.SyntaxWalker.visitPropertyAssignment (/usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:166:14)
at ExpressionCallMetadataWalker.SyntaxWalker.visitNode (/usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:384:22)
at /usr/local/lib/node_modules/tslint/lib/language/walker/syntaxWalker.js:447:63
I want to enable tslint's "no-console" rule. I tried by adding this line "no-console": [true, ["log", "error"]]
to my tslint.json file but it didn't work.
Does codelyzer override tslint's built-in rules or it just adds spcefic rules?
Regards!
When doing npm install --save-dev codelyzer I don't have any js file created for the importDestructingSpacing rules which causes that rule to fail when added to tsconfig
Once a stable version of the metadata reader lands in the advanced
branch, pass more descriptive information to:
visitNg2Component
visitNg2Directive
I would like a way to allow using the host property in component/directive decorators as long as the keys are being set to string
values. For example, this code:
@Component({
selector: 'my-component',
host: {
class: 'some-base-class some-modifier-class other-modifier-class'
}
})
class MyComponent {}
seems more readable than:
@Component({
selector: 'my-component'
})
class MyComponent {
@HostBinding('class.some-base-class')
someBaseClass = true;
@HostBinding('class.some-modifier-class')
someModifierClass = true;
@HostBinding('class.other-modifier-class')
otherModifierClass = true;
}
I have custom email validator like below
@Directive({`
selector: '[validateEmail][ngControl],[validateEmail][ngModel],[validateEmail][ngFormControl]',
providers: [
provide(NG_VALIDATORS, {
useClass: EmailValidatorDirective, multi: true
})
]
})
but it gives
The selector of the directive "EmailValidatorDirective" should be named camelCase (https://goo.gl/rdGf2b)
even it is in camel case
Hi @mgechev - just wanted to let you know that I've added your repository to the TSLint README and documentation as a place to find custom rules for TSLint. Neat idea to make a collection of Angular2 rules!
Currently the selectors' validators are not compatible with spec.
Is the ng lint command supposed to tell me what the lint errors actually are? Right now when I run it, it just says "Lint errors found in the listed files" and does not tell me what the lint errors are
I have a tslint.json in my base directory with
"rulesDirectory": ["node_modules/codelyzer/dist/src"]
But I get constant errors from Atom saying Could not find custom rule directory: /node_modules/codelyzer/dist/src
I saved codelyzer to both global and as a dev dependency
Hi @mgechev , thanks for a great Codelyzer!
I would like to integrate it with my starter, so far no issue, but I found some rules value is repetitive, for example:
"directive-selector-prefix": [true, "as"],
"component-selector-prefix": [true, "as"],
"pipe-naming": [true, "camelCase", "as"],
the repetitive part is "as"
one, it'd be cool if I can store the prefix default in variable like
"prefix-default": "as",
"directive-selector-prefix": [true],
"component-selector-prefix": [true],
"pipe-naming": [true, "camelCase"]
so I need to change only one part to reflect all of them, of course we can override the default one with usual way
It'd be great to have this feature
Thank you!
Having this class:
export class Heroes implements Iterable<Hero> {
...
[Symbol.iterator]() {
return this.currentHeroes.values();
}
...
}
I get this error:
TypeError: Cannot read property 'substr' of undefined
at useLifeCycleInterfaceRule.js:58:44
Is not the interface itself, is the Symbol.iterator.
With the current configuration, this lints all of the components to match only one feature. The Angular2 styleguide encourages use of prefixes for some selectors that may be otherwise ambiguous. These prefixes are supposed to be centered around the specific feature the component is associated with. For example, toh-heroes or admin-users. The current configuration makes the desired prefix static, which doesn't make sense. Instead, it should simply check the presence of a prefix at all and remind the user to name it after the feature, perhaps checking the context making sure other components in the same directory with potentially colliding names across the app also use the same prefix.
As Style Guide says, a component name should be named in kebab-case. And it should follow Custom Elements spec.
Style 05-02
Do use kebab-case for naming the element selectors of our components.
Why? Keeps the element names consistent with the specification for Custom Elements.
Custom Elements spec says the following:
The custom element type identifies a custom element interface and is a sequence of characters that must match the NCName production [XML-NAMES], must contain a U+002D HYPHEN-MINUS character, and must not contain any uppercase ASCII letters [HTML]. The custom element type must not be one of the following values:
But currently codelyzer allows a name doesn't contain hyphen as kebab-case.
selector: "foobar"
: passedselector: "foo-bar"
: passedselector: "fooBar"
: invalidExpected
selector: "foobar"
should be an error in kebab-case rule.
Hi,
is it possible to export codelyzer's rules e.g. space around import statements to a IDE's auto-formatting e.g. intelliJ?
As using window
and document
prevents the app to be run in a web worker there should be a rule to prohibit the use of them.
This aligns with the rule of not using ElementRef.nativeElement
for the same reason.
Additionally, but I don't know whether this is possible, the rule should also detect if window
is implicitly accessed.
I think node_modules/codelyzer/dist/src
is not intuitive. Mainly dist/src part.
I'd like to import rules from node_modules/codelyzer/dist/rules
or .../dist/ng2lint
Hi @mgechev,
since it is possible to write the very same* syntax in js with babel-plugin-angular2-annotations i wonder if it is possible to modify codelyzer to also support eslint.
I have to admit i haven't looked into how to create custom eslint, tslint rules. If they have similar APIs or if it is possible to re-create each rule with eslint at all.
I think at the moment there is only one prefix allowed. Should we have more than one for a project?
The example styleguide seems to say yes
https://angular.io/docs/ts/latest/guide/style-guide.html#!#style-02-07
The links do not resolve to the proper guide section anchor:
Example:
[11, 1]: Implement lifecycle hook interfaces (https://goo.gl/uhVsrr)
links to
https://angular.io/docs/ts/latest/guide/style-guide.html#!#style-09-01
should link to
https://angular.io/docs/ts/latest/guide/style-guide.html#!#09-01
Since Angular 2 applications can be written in Javascript and can use the same syntax as Typescript is it a viable option to Codelyzer supports Javascript projects through custom ESLint rules?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.