Skip to content

Commit

Permalink
Merge pull request #401 from wKoza/fix_desugared_directive
Browse files Browse the repository at this point in the history
Fix desugared directive
  • Loading branch information
mgechev authored Sep 8, 2017
2 parents 1aa647e + c71fac8 commit 4721aca
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 77 deletions.
1 change: 1 addition & 0 deletions src/angular/ngWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface NgWalkerConfig {
}

export class NgWalker extends Lint.RuleWalker {

constructor(sourceFile: ts.SourceFile,
protected _originalOptions: Lint.IOptions,
private _config?: NgWalkerConfig,
Expand Down
11 changes: 11 additions & 0 deletions src/angular/sourceMappingVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ function computeLineStarts(text: string): number[] {
}

export class SourceMappingVisitor extends RuleWalker {

parentAST: any;
private consumer: SourceMapConsumer;

constructor(sourceFile: ts.SourceFile, options: IOptions, protected codeWithMap: CodeWithSourceMap, protected basePosition: number) {
Expand Down Expand Up @@ -127,9 +129,18 @@ export class SourceMappingVisitor extends RuleWalker {
console.log(e);
}
}

if (this.parentAST && this.parentAST.templateName) {
pos = pos - this.parentAST.value.ast.span.start;
}
return pos + this.basePosition;
}

addParentAST(parentAST: any): any {
this.parentAST = parentAST;
return this;
}

private getMappedInterval(start: number, length: number) {
let end = start + length;
start = this.getSourcePosition(start);
Expand Down
19 changes: 11 additions & 8 deletions src/angular/templates/basicTemplateAstVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ExpTypes } from '../expressionTypes';
import { ComponentMetadata } from '../metadata';
import { RecursiveAngularExpressionVisitor } from './recursiveAngularExpressionVisitor';
import { SourceMappingVisitor } from '../sourceMappingVisitor';
import { NgWalker } from '../ngWalker';


const getExpressionDisplacement = (binding: any) => {
Expand Down Expand Up @@ -49,18 +50,19 @@ const getExpressionDisplacement = (binding: any) => {
// Total length of the attribute value
if (binding instanceof ast.BoundEventAst) {
valLen = binding.handler.span.end;
} else if (binding instanceof ast.BoundDirectivePropertyAst && binding.templateName === 'ngForOf') {
} else if (binding instanceof ast.BoundDirectivePropertyAst &&
( binding.templateName === 'ngForOf' || binding.templateName === 'ngIf')) {
// Handling everything except [ngForOf] differently
// [ngForOf] requires different logic because it gets desugered from *ngFor
// [ngForOf] and [ngIf] require different logic because it gets desugered
const content = binding.sourceSpan.end.file.content;
const ngForSubstr = content.substring(binding.sourceSpan.start.offset, binding.sourceSpan.end.offset);
result = ngForSubstr.lastIndexOf((binding.value as any).source) + '*ngFor'.length;
result = binding.sourceSpan.start.file.content.lastIndexOf((binding.value as any).source);
} else {
valLen = binding.value.span.end;
}

// Handling everything except [ngForOf]
if (!(binding instanceof ast.BoundDirectivePropertyAst) || binding.templateName !== 'ngForOf') {
if (!(binding instanceof ast.BoundDirectivePropertyAst) ||
( binding.templateName !== 'ngForOf' && binding.templateName !== 'ngIf')) {
// Total length of the entire part of the template AST corresponding to this AST.
totalLength = binding.sourceSpan.end.offset - binding.sourceSpan.start.offset;
// The whitespace are possible only in:
Expand Down Expand Up @@ -139,7 +141,7 @@ export class BasicTemplateAstVisitor extends SourceMappingVisitor implements ast
visitElementProperty(prop: ast.BoundElementPropertyAst, context: any): any {
const ast: any = (<e.ASTWithSource>prop.value).ast;
ast.interpolateExpression = (<any>prop.value).source;
this.visitNgTemplateAST(prop.value, this.templateStart + getExpressionDisplacement(prop));
this.visitNgTemplateAST(prop.value, this.templateStart + getExpressionDisplacement(prop), prop);
}

visitAttr(ast: ast.AttrAst, context: any): any {}
Expand All @@ -164,14 +166,15 @@ export class BasicTemplateAstVisitor extends SourceMappingVisitor implements ast

visitDirectiveProperty(prop: ast.BoundDirectivePropertyAst, context: any): any {
if (ExpTypes.ASTWithSource(prop.value)) {
this.visitNgTemplateAST(prop.value, this.templateStart + getExpressionDisplacement(prop));
this.visitNgTemplateAST(prop.value, this.templateStart + getExpressionDisplacement(prop), prop);
}
}

protected visitNgTemplateAST(ast: e.AST, templateStart: number) {
protected visitNgTemplateAST(ast: e.AST, templateStart: number, prop?: any) {
const templateVisitor =
new this.expressionVisitorCtrl(this.getSourceFile(), this._originalOptions, this.context, templateStart);
templateVisitor.preDefinedVariables = this._variables;
templateVisitor.parentAST = prop;
templateVisitor.visit(ast);
templateVisitor.getFailures().forEach(f => this.addFailure(f));
}
Expand Down
15 changes: 10 additions & 5 deletions src/angularWhitespaceRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,15 @@ class WhitespaceTemplateVisitor extends BasicTemplateAstVisitor {

class PipeWhitespaceVisitor extends RecursiveAngularExpressionVisitor implements ConfigurableVisitor {
visitPipe(ast: ast.BindingPipe, context: RecursiveAngularExpressionVisitor): any {
const start = ast.span.start;
const exprStart = context.getSourcePosition(ast.exp.span.start);
const exprEnd = context.getSourcePosition(ast.exp.span.end);
const sf = context.getSourceFile().getFullText();
const exprText = sf.substring(exprStart, exprEnd);

let exprStart, exprEnd, exprText, sf;

exprStart = context.getSourcePosition(ast.exp.span.start);
exprEnd = context.getSourcePosition(ast.exp.span.end);
sf = context.getSourceFile().getFullText();
exprText = sf.substring(exprStart, exprEnd);


const replacements = [];
// Handling the right side of the pipe
let leftBeginning = exprEnd + 1; // exprEnd === '|'
Expand Down Expand Up @@ -214,6 +218,7 @@ class TemplateExpressionVisitor extends RecursiveAngularExpressionVisitor {
visitPipe(expr: ast.BindingPipe, context: any): any {
const options = this.getOptions();
this.visitors
.map(v => v.addParentAST(this.parentAST))
.filter(v => options.indexOf(v.getOption()) >= 0)
.map(v => v.visitPipe(expr, this))
.filter(f => !!f)
Expand Down
6 changes: 3 additions & 3 deletions src/contextualLifeCycleRule.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as Lint from 'tslint';
import * as ts from 'typescript';
import {sprintf} from 'sprintf-js';
import { sprintf } from 'sprintf-js';
import SyntaxKind = require('./util/syntaxKind');
import {NgWalker} from './angular/ngWalker';
import {ComponentMetadata, DirectiveMetadata} from './angular/metadata';
import { NgWalker } from './angular/ngWalker';
import { ComponentMetadata, DirectiveMetadata } from './angular/metadata';


export class Rule extends Lint.Rules.AbstractRule {
Expand Down
50 changes: 18 additions & 32 deletions src/noAccessMissingMemberRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,9 @@ import * as ts from 'typescript';
import { sprintf } from 'sprintf-js';
import { stringDistance } from './util/utils';
import { NgWalker } from './angular/ngWalker';
import {
RecursiveAngularExpressionVisitor,
FlatSymbolTable
} from './angular/templates/recursiveAngularExpressionVisitor';
import { RecursiveAngularExpressionVisitor, FlatSymbolTable } from './angular/templates/recursiveAngularExpressionVisitor';
import { ExpTypes } from './angular/expressionTypes';
import {
getDeclaredMethodNames,
getDeclaredPropertyNames
} from './util/classDeclarationUtils';
import { getDeclaredMethodNames, getDeclaredPropertyNames } from './util/classDeclarationUtils';
import * as e from '@angular/compiler/src/expression_parser/ast';

import { Config } from './angular/config';
Expand Down Expand Up @@ -50,8 +44,7 @@ class SymbolAccessValidator extends RecursiveAngularExpressionVisitor {
symbolType = 'property';
}

available = Object.assign(
{},
available = Object.assign({},
getDeclaredMethodNames(this.context.controller),
getDeclaredPropertyNames(this.context.controller),
this.preDefinedVariables
Expand Down Expand Up @@ -81,11 +74,7 @@ class SymbolAccessValidator extends RecursiveAngularExpressionVisitor {
}

if (ast.name && !available[ast.name]) {
let failureString = sprintf.apply(this, [
Rule.FAILURE,
symbolType,
ast.name
]);
let failureString = sprintf.apply(this, [Rule.FAILURE, symbolType, ast.name]);
const top = this.getTopSuggestion(Object.keys(available), ast.name);
const getSuggestion = (list: string[]) => {
if (list.length === 1) {
Expand All @@ -99,9 +88,7 @@ class SymbolAccessValidator extends RecursiveAngularExpressionVisitor {
return result;
};
if (top.length && top[0].distance <= 2) {
failureString += ` Probably you mean: ${getSuggestion(
top.map(s => s.element)
)}.`;
failureString += ` Probably you mean: ${getSuggestion(top.map(s => s.element))}.`;
}
const width = ast.name.length;
this.addFailure(this.createFailure(ast.span.start, width, failureString));
Expand All @@ -111,21 +98,19 @@ class SymbolAccessValidator extends RecursiveAngularExpressionVisitor {

private getTopSuggestion(list: string[], current: string) {
const result = [];
const tmp = list
.map(e => {
return {
element: e,
distance: stringDistance(e, current)
};
})
.sort((a, b) => a.distance - b.distance);
const tmp = list.map(e => {
return {
element: e,
distance: stringDistance(e, current)
};
}).sort((a, b) => a.distance - b.distance);
const first = tmp.shift();
if (!first) {
return [];
} else {
result.push(first);
let current: any;
while ((current = tmp.shift())) {
while (current = tmp.shift()) {
if (current.distance !== first.distance) {
return result;
} else {
Expand All @@ -145,16 +130,17 @@ export class Rule extends Lint.Rules.AbstractRule {
rationale: `Such occurances in code are most likely a result of a typo.`,
options: null,
optionsDescription: `Not configurable.`,
typescriptOnly: true
typescriptOnly: true,
};

static FAILURE: string = 'The %s "%s" that you\'re trying to access does not exist in the class declaration.';

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
expressionVisitorCtrl: SymbolAccessValidator
})
);
new NgWalker(sourceFile,
this.getOptions(), {
expressionVisitorCtrl: SymbolAccessValidator
}));
}
}

Loading

0 comments on commit 4721aca

Please sign in to comment.