To provide information for DAS clients the server_plugin
plugin contributes several extensions.
- Angular analysis errors are automatically merged into normal
errors
notifications for Dart and HTML files.
Check the pubspec.yaml in your project for transformers. They are not supported. You must manually add CORE_DIRECTIVES to your components right now for this plugin to work.
Download chrome depot tools, and clone this repository.
Then run
./tools/get_deps.sh
cd server_plugin/bin
./make_snapshot
Back up sdk_path/snapshots/analysis_server.dart.snapshot
and replace it with server.snapshot
. Restart the dart analysis server by clicking the skull.
Under the next system, you will not need to build to install (woo hoo!). However, these steps currently don't produce anything usable. Installation steps will come once its ready.
Download chrome depot tools, and clone this repository.
Then run
./tools/get_deps.sh
cd analyze_angular/tools/plugin
cp pubspec.yaml.defaults pubspec.yaml
Modify pubspec.yaml
in this folder to fix the absolute paths. They must be absolute for the moment! Once they can be relative this step will not be required.
Then run pub get
.
You can now use this in projects on your local system which a correctly configured pubspec. For instance, playground/
. Note that you must import 'package:analyze_angular/'
in your project to get the analysis.
We plug into many editors with varying degrees of support. In theory anything that supports Dart analysis also supports our plugin, but in practice that's not always the case.
Bootstrapping | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
IntelliJ | ✅ | ✅ | 🚷 | |
Vim (special setup required) | ✅ | ✅ | ✅ | 🚷 |
others | ❓ let us know! | ❓ let us know! | ❓ let us know! | ❓ let us know! |
If you are using an editor with Dart support that's not in this list, then please let us know what does or doesn't work. We can sometimes contribute fixes, too!
Bootstrapping | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
bootstrap(AppComponent, [MyService, provide(...)]); |
🚷 | 🚷 | 🚷 | 🚷 |
Template syntax | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
<div stringInput="string"> |
✅ typecheck is string input on component | ✅ | ❌ | ❌ |
<input [value]="firstName"> |
✅ soundness of expression, type of expression, existence of value on element or directive |
✅ | ❌ | ❌ |
<input bind-value="firstName"> |
✅ | 💀 | ❌ | ❌ |
<div [attr.role]="myAriaRole"> |
🌗 soundness of expression, but no other validation | 🌗 complete inside binding but binding not suggested | ❌ | ❌ |
<div [class.extra-sparkle]="isDelightful"> |
✅ validity of clasname, soundness of expression, type of expression must be bool | 🌗 complete inside binding but binding not suggested | ❌ | ❌ |
<div [style.width.px]="mySize"> |
🌖 soundness of expression, css properties are generally checked but not against a dictionary, same for units, expression must type to int if units are present |
🌗 complete inside binding but binding not suggested | ❌ | ❌ |
<button (click)="readRainbow($event)"> |
✅ soundness of expression, type of $event , existence of output on component/element and DOM events which propagate can be tracked anywhere |
✅ | ❌ | ❌ |
<button on-click="readRainbow($event)"> |
✅ | 💀 | ❌ | ❌ |
<div title="Hello {{ponyName}}"> |
✅ soundness of expression, matching mustache delimiters | ✅ | ❌ | ❌ |
<p>Hello {{ponyName}}</p> |
✅ soundness of expression, matching mustache delimiters | ✅ | ❌ | ❌ |
<my-cmp></my-cmp> |
✅ existence of directive | ✅ | ❌ | ❌ |
<my-cmp [(title)]="name"> |
✅ soundness of expression, existence of title input and titleChange output on directive or component with proper type |
✅ | ❌ | ❌ |
<video #movieplayer ...></video><button (click)="movieplayer.play()"> |
✅ type of new variable tracked and checked in other expressions | ✅ | ❌ | ❌ |
<video directiveWithExportAs #moviePlayer="exportAsValue"> |
✅ existence of exportAs value checked within bound directives | ✅ | ❌ | ❌ |
<video ref-movieplayer ...></video><button (click)="movieplayer.play()"> |
✅ | ✅ | ❌ | ❌ |
<p *myUnless="myExpression">...</p> |
✅ desugared to <template [myUnless]="myExpression"><p>... and checked from there |
✅ | ❌ | ❌ |
<p>Card No.: {{cardNumber | myCardNumberFormatter}}</p> |
❌ Pipes are not typechecked yet | ❌ | ❌ | ❌ |
<my-component @deferred> |
❌ | ❌ | ❌ | ❌ |
Built-in directives | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
<section *ngIf="showSection"> |
✅ type checking, check for the star | ✅ | ❌ | ❌ |
<li *ngFor="let item of list"> |
✅ type checking and new var, check for the star, catch accidental usage of #item |
✅ | ❌ | ❌ |
<div [ngClass]="{active: isActive, disabled: isDisabled}"> |
✅ | ❌ | ❌ |
Forms | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
<input [(ngModel)]="userName"> |
✅ | ✅ | ❌ | ❌ |
<form #myform="ngForm"> |
✅ if ngForm is not an exported directive |
✅ | ❌ | ❌ |
Class decorators | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
@Component(...) class MyComponent {} |
✅ Validates directives list is all directives, that the template file exists, that a template is specified via string or URL but not both, requires a valid selector | 🚷 | 🚷 | 🚷 |
@View(...) class MyComponent {} |
@Directive or @Component , but doesn't catch ambigous cases such as templates defined in the @View as well as @Component |
🚷 | 🚷 | 🚷 |
@Directive(...) class MyDirective {} |
✅ Validates directives list is all directives, that the template file exists, that a template is specified via string or URL but not both, requires a valid selector | 🚷 | 🚷 | 🚷 |
@Pipe(...) class MyPipe {} |
❌ | 🚷 | 🚷 | ❌ |
@Injectable() class MyService {} |
❌ | 🚷 | 🚷 | ❌ |
Directive configuration | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
@Directive(property1: value1, ...) |
🚷 | 🚷 | 🚷 | |
selector: '.cool-button:not(a)' |
✅ | 🚷 | ❌ | ❌ |
providers: [MyService, provide(...)] |
❌ | ❌ | ❌ | ❌ |
inputs: ['myprop', 'myprop2: byname'] |
✅ | ❌ | ❌ | ❌ |
outputs: ['myprop', 'myprop2: byname'] |
✅ | ❌ | ❌ | ❌ |
@Component extends @Directive, so the @Directive configuration applies to components as well
Component Configuration | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
viewProviders: [MyService, provide(...)] |
❌ | ❌ | ❌ | ❌ |
template: 'Hello {{name}}' |
✅ | ✅ | ❌ | ❌ |
templateUrl: 'my-component.html' |
✅ | ❌ | ❌ | ❌ |
styles: ['.primary {color: red}'] |
❌ | 🚷 | 🚷 | 🚷 |
styleUrls: ['my-component.css'] |
❌ | ❌ | ❌ | ❌ |
directives: [MyDirective, MyComponent] |
✅ must be directives or lists of directives, configuration affects view errors | ❌ | ❌ | ❌ |
pipes: [MyPipe, OtherPipe] |
❌ | ❌ | ❌ | ❌ |
exports: [Class, Enum, staticFn] |
✅ | ✅ | ❌ | ❌ |
Class field decorators for directives and components | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
@Input() myProperty; |
✅ | 🚷 | ❌ | ❌ |
@Input("name") myProperty; |
✅ | 🚷 | ❌ | ❌ |
@Output() myEvent = new Stream<X>(); |
✅ Subtype of Stream<T> required, streamed type determines $event type |
🚷 | ❌ | ❌ |
@Output("name") myEvent = new Stream<X>(); |
✅ | 🚷 | ❌ | ❌ |
@Attribute("name") String ctorArg |
✅ | ❌ | ❌ | ❌ |
@HostBinding('[class.valid]') isValid; |
❌ | 🚷 | 🚷 | 🚷 |
@HostListener('click', ['$event']) onClick(e) {...} |
❌ | ❌ | ❌ | ❌ |
@ContentChild(myPredicate) myChildComponent; |
❌ | 🚷 | ❌ | ❌ |
@ContentChildren(myPredicate) myChildComponents; |
❌ | 🚷 | ❌ | ❌ |
@ViewChild(myPredicate) myChildComponent; |
❌ | 🚷 | ❌ | ❌ |
@ViewChildren(myPredicate) myChildComponents; |
❌ | 🚷 | ❌ | ❌ |
Transclusions | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
<ng-content></ng-content> |
✅ | 🚷 | 🚷 | 🚷 |
<my-comp>text content</my-comp> |
✅ | ❌ | ❌ | ❌ |
<ng-content select="foo"></ng-content> |
✅ | ✅ | ❌ | ❌ |
<my-comp><foo></foo></my-comp> |
✅ | ✅ | ❌ | ❌ |
<ng-content select=".foo[bar]"></ng-content> |
✅ | ✅ | ❌ | ❌ |
<my-comp><div class="foo" bar></div></my-comp> |
✅ | ✅ | ❌ | ❌ |
Directive and component change detection and lifecycle hooks (implemented as class methods) | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
MyAppComponent(MyService myService, ...) { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngOnChanges(changeRecord) { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngOnInit() { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngDoCheck() { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngAfterContentInit() { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngAfterContentChecked() { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngAfterViewInit() { ... } |
❌ | 🚷 | 🚷 | ❌ |
ngAfterViewChecked() { ... } |
🚷 | 🚷 | ❌ | ❌ |
ngOnDestroy() { ... } |
❌ | 🚷 | 🚷 | ❌ |
Dependency injection configuration | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
provide(MyService, useClass: MyMockService) |
❌ | 🚷 | 🚷 | ❌ |
provide(MyService, useFactory: myFactory) |
❌ | 🚷 | 🚷 | ❌ |
provide(MyValue, useValue: 41) |
❌ | 🚷 | 🚷 | ❌ |
Routing and navigation | Validation | Auto-Complete | Navigation | Refactoring |
---|---|---|---|---|
@RouteConfig(const [ const Route(...) ]) |
❌ | 🚷 | 🚷 | 🚷 |
<router-outlet></router-outlet> |
🚷 | ❌ | 🚷 | 🚷 |
<a [routerLink]="[ '/MyCmp', {myParam: 'value' } ]"> |
❓ | ❌ | 🚷 | 🚷 |
@CanActivate(() => ...)class MyComponent() {} |
❌ | 🚷 | 🚷 | 🚷 |
routerOnActivate(nextInstruction, prevInstruction) { ... } |
❌ | 🚷 | 🚷 | 🚷 |
routerCanReuse(nextInstruction, prevInstruction) { ... } |
❌ | 🚷 | 🚷 | 🚷 |
routerOnReuse(nextInstruction, prevInstruction) { ... } |
❌ | ❌ | 🚷 | 🚷 |
routerCanDeactivate(nextInstruction, prevInstruction) { ... } |
❌ | 🚷 | 🚷 | 🚷 |
routerOnDeactivate(nextInstruction, prevInstruction) { ... } |
❌ | 🚷 | 🚷 | 🚷 |