Last active
August 30, 2016 15:55
-
-
Save milichev/ee687279027b349cf2ce0fbc6e8c86db to your computer and use it in GitHub Desktop.
TsList ng2-intfs rule: Requires the class to declare Angular 2 interfaces if implements their methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var __extends = (this && this.__extends) || function (d, b) { | |
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | |
function __() { this.constructor = d; } | |
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | |
}; | |
var ts = require('typescript'); | |
var Lint = require('tslint/lib/lint'); | |
var abstractRule_1 = require('tslint/lib/language/rule/abstractRule'); | |
var Rule = (function (_super) { | |
__extends(Rule, _super); | |
function Rule() { | |
_super.apply(this, arguments); | |
} | |
Rule.prototype.apply = function (sourceFile) { | |
return this.applyWithWalker(new Ng2InterfacesWalker(sourceFile, this.getOptions())); | |
}; | |
Rule.metadata = { | |
ruleName: 'ng2-intfs', | |
type: 'typescript', | |
description: 'Requires the class to declare Angular 2 interfaces if implements their methods', | |
rationale: '', | |
options: undefined, | |
optionExamples: ['true'] | |
}; | |
return Rule; | |
}(abstractRule_1.AbstractRule)); | |
exports.Rule = Rule; | |
var memberDefs = { | |
OnChanges: [{ name: 'ngOnChanges', kind: ts.SyntaxKind.MethodDeclaration }], | |
OnInit: [{ name: 'ngOnInit', kind: ts.SyntaxKind.MethodDeclaration }], | |
DoCheck: [{ name: 'ngDoCheck', kind: ts.SyntaxKind.MethodDeclaration }], | |
AfterContentInit: [{ name: 'ngAfterContentInit', kind: ts.SyntaxKind.MethodDeclaration }], | |
AfterContentChecked: [{ name: 'ngAfterContentChecked', kind: ts.SyntaxKind.MethodDeclaration }], | |
AfterViewInit: [{ name: 'ngAfterViewInit', kind: ts.SyntaxKind.MethodDeclaration }], | |
AfterViewChecked: [{ name: 'ngAfterViewChecked', kind: ts.SyntaxKind.MethodDeclaration }], | |
OnDestroy: [{ name: 'ngOnDestroy', kind: ts.SyntaxKind.MethodDeclaration }] | |
}; | |
var memberMap = new Map(); | |
Object.keys(memberDefs).forEach(function (nm) { | |
memberDefs[nm].forEach(function (d) { return memberMap.set(d.name, { | |
type: nm, | |
kind: d.kind | |
}); }); | |
}); | |
var Ng2InterfacesWalker = (function (_super) { | |
__extends(Ng2InterfacesWalker, _super); | |
function Ng2InterfacesWalker() { | |
_super.apply(this, arguments); | |
} | |
Ng2InterfacesWalker.prototype.visitClassDeclaration = function (node) { | |
var _this = this; | |
var implementsClause = node.heritageClauses && | |
node.heritageClauses.filter(function (cl) { return cl.token === ts.SyntaxKind.ImplementsKeyword; })[0] || { types: [] }; | |
var extendsClause = node.heritageClauses && | |
node.heritageClauses.filter(function (cl) { return cl.token === ts.SyntaxKind.ExtendsKeyword; })[0] || { types: [] }; | |
var implementsNames = new Set(implementsClause.types.map(function (t) { return t.expression.text; })); | |
var extendsNames = new Set(extendsClause.types.map(function (t) { return t.expression.text; })); | |
node.members | |
.filter(function (m) { return m.kind === ts.SyntaxKind.MethodDeclaration; }) | |
.forEach(function (m) { | |
var meth = m; | |
var def = memberMap.get(meth.name.text); | |
if (def && def.kind === meth.kind) { | |
if (!implementsNames.has(def.type)) { | |
_this.addFailure(_this.createFailure(meth.name.pos + 4, meth.name.end - meth.name.pos, "The class " + node.name.text + " has member " + meth.name.text + ", but does not specify " + def.type + " type in implements clause")); | |
} | |
} | |
}); | |
_super.prototype.visitClassDeclaration.call(this, node); | |
}; | |
return Ng2InterfacesWalker; | |
}(Lint.RuleWalker)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as ts from 'typescript'; | |
import * as Lint from 'tslint/lib/lint'; | |
import {AbstractRule} from 'tslint/lib/language/rule/abstractRule'; | |
import {RuleType} from 'tslint/lib/language/rule/rule'; | |
export class Rule extends AbstractRule { | |
public static metadata = { | |
ruleName: 'ng2-intfs', | |
type: <RuleType>'typescript', | |
description: 'Requires the class to declare Angular 2 interfaces if implements their methods', | |
rationale: '', | |
options: undefined, | |
optionExamples: ['true'] | |
}; | |
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | |
return this.applyWithWalker(new Ng2InterfacesWalker(sourceFile, this.getOptions())); | |
} | |
} | |
const memberDefs = { | |
OnChanges: [{name: 'ngOnChanges', kind: ts.SyntaxKind.MethodDeclaration}], | |
OnInit: [{name: 'ngOnInit', kind: ts.SyntaxKind.MethodDeclaration}], | |
DoCheck: [{name: 'ngDoCheck', kind: ts.SyntaxKind.MethodDeclaration}], | |
AfterContentInit: [{name: 'ngAfterContentInit', kind: ts.SyntaxKind.MethodDeclaration}], | |
AfterContentChecked: [{name: 'ngAfterContentChecked', kind: ts.SyntaxKind.MethodDeclaration}], | |
AfterViewInit: [{name: 'ngAfterViewInit', kind: ts.SyntaxKind.MethodDeclaration}], | |
AfterViewChecked: [{name: 'ngAfterViewChecked', kind: ts.SyntaxKind.MethodDeclaration}], | |
OnDestroy: [{name: 'ngOnDestroy', kind: ts.SyntaxKind.MethodDeclaration}] | |
}; | |
let memberMap = new Map(); | |
Object.keys(memberDefs).forEach(nm => { | |
memberDefs[nm].forEach(d => memberMap.set(d.name, { | |
type: nm, | |
kind: d.kind | |
})); | |
}); | |
class Ng2InterfacesWalker extends Lint.RuleWalker { | |
public visitClassDeclaration(node: ts.ClassDeclaration) { | |
let implementsClause = node.heritageClauses && | |
node.heritageClauses.filter(cl => cl.token === ts.SyntaxKind.ImplementsKeyword)[0] || {types: []}; | |
let extendsClause = node.heritageClauses && | |
node.heritageClauses.filter(cl => cl.token === ts.SyntaxKind.ExtendsKeyword)[0] || {types: []}; | |
let implementsNames = new Set(implementsClause.types.map(t => t.expression.text)); | |
let extendsNames = new Set(extendsClause.types.map(t => t.expression.text)); | |
node.members | |
.filter(m => m.kind === ts.SyntaxKind.MethodDeclaration) | |
.forEach(m => { | |
let meth = <ts.ClassElement> m; | |
let def = memberMap.get(meth.name.text); | |
if (def && def.kind === meth.kind) { | |
if (!implementsNames.has(def.type)) { | |
this.addFailure(this.createFailure( | |
meth.name.pos + 4, meth.name.end - meth.name.pos, | |
`The class ${node.name.text} has member ${meth.name.text}, but does not specify ${ | |
def.type} type in implements clause`)); | |
} | |
} | |
}); | |
super.visitClassDeclaration(node); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"rules": { | |
"ng2-intfs": true | |
}, | |
"rulesDirectory": ["tslint/"] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment