type2docfx
Version:
A tool to convert json format output from TypeDoc to universal reference model for DocFx to consume.
276 lines (275 loc) • 11.1 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Lint = require("tslint");
var ngWalker_1 = require("./angular/ngWalker");
var utils_1 = require("./util/utils");
var basicCssAstVisitor_1 = require("./angular/styles/basicCssAstVisitor");
var basicTemplateAstVisitor_1 = require("./angular/templates/basicTemplateAstVisitor");
var compiler_1 = require("@angular/compiler");
var templateParser_1 = require("./angular/templates/templateParser");
var logger_1 = require("./util/logger");
var ngVersion_1 = require("./util/ngVersion");
var CssSelectorTokenizer = require('css-selector-tokenizer');
var getSymbolName = function (t) {
var expr = t;
if (t.expression) {
expr = t.expression;
}
if (t.expression && t.expression.name) {
expr = t.expression.name;
}
return expr.text;
};
var isEncapsulationEnabled = function (encapsulation) {
if (!encapsulation) {
return true;
}
else {
if (getSymbolName(encapsulation) !== 'ViewEncapsulation') {
return false;
}
else {
var encapsulationType = encapsulation.name.text;
if (/^(Emulated|Native)$/.test(encapsulationType)) {
return true;
}
}
}
return false;
};
var lang = require('cssauron')({
tag: function (node) {
return (node.name || '').toLowerCase();
},
contents: function (node) { return ''; },
id: function (node) {
return this.attr(node, 'id');
},
'class': function (node) {
var classBindings = (node.inputs || [])
.filter(function (b) { return b.type === compiler_1.PropertyBindingType.Class; })
.map(function (b) { return b.name; }).join(' ');
var classAttr = node.attrs.filter(function (a) { return a.name.toLowerCase() === 'class'; }).pop();
var staticClasses = '';
if (classAttr) {
staticClasses = classAttr.value + ' ';
}
return staticClasses + classBindings;
},
parent: function (node) {
return node.parentNode;
},
children: function (node) {
return node.children;
},
attr: function (node, attr) {
var targetAttr = node.attrs.filter(function (a) { return a.name === attr; }).pop();
if (targetAttr) {
return targetAttr.value;
}
return undefined;
}
});
var ElementVisitor = (function (_super) {
__extends(ElementVisitor, _super);
function ElementVisitor() {
return _super !== null && _super.apply(this, arguments) || this;
}
ElementVisitor.prototype.visitElement = function (ast, fn) {
var _this = this;
fn(ast);
ast.children.forEach(function (c) {
if (c instanceof compiler_1.ElementAst) {
c.parentNode = ast;
}
_this.visit(c, fn);
});
};
return ElementVisitor;
}(basicTemplateAstVisitor_1.BasicTemplateAstVisitor));
var hasSelector = function (s, type) {
if (!s) {
return false;
}
if (s.type === 'selector' || s.type === 'selectors') {
return (s.nodes || []).some(function (n) { return hasSelector(n, type); });
}
else {
return s.type === type;
}
};
var dynamicFilters = {
id: function (ast, selector) {
return (ast.inputs || []).some(function (i) { return i.name === 'id'; });
},
attribute: function (ast, selector) {
return (ast.inputs || []).some(function (i) { return i.type === compiler_1.PropertyBindingType.Attribute; });
},
'class': function (ast, selector) {
return (ast.inputs || []).some(function (i) { return i.name === 'className' || i.name === 'ngClass'; });
}
};
var ElementFilterVisitor = (function (_super) {
__extends(ElementFilterVisitor, _super);
function ElementFilterVisitor() {
return _super !== null && _super.apply(this, arguments) || this;
}
ElementFilterVisitor.prototype.shouldVisit = function (ast, strategies, selectorTypes) {
var _this = this;
return Object.keys(strategies).every(function (s) {
var strategy = strategies[s];
return !selectorTypes[s] || !strategy(ast);
}) && (ast.children || [])
.every(function (c) { return ast instanceof compiler_1.ElementAst && _this.shouldVisit(c, strategies, selectorTypes)
|| ast instanceof compiler_1.EmbeddedTemplateAst &&
(ast.children || []).every(function (c) { return _this.shouldVisit(c, strategies, selectorTypes); }); });
};
return ElementFilterVisitor;
}(basicTemplateAstVisitor_1.BasicTemplateAstVisitor));
var Rule = (function (_super) {
__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.apply = function (sourceFile) {
return this.applyWithWalker(new UnusedCssNgVisitor(sourceFile, this.getOptions(), {
cssVisitorCtrl: UnusedCssVisitor
}));
};
Rule.metadata = {
ruleName: 'no-unused-css',
type: 'maintainability',
description: 'Disallows having an unused CSS rule in the component\'s stylesheet.',
options: null,
optionsDescription: 'Not configurable.',
typescriptOnly: true,
hasFix: true
};
return Rule;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
var UnusedCssVisitor = (function (_super) {
__extends(UnusedCssVisitor, _super);
function UnusedCssVisitor(sourceFile, originalOptions, context, style, templateStart) {
var _this = _super.call(this, sourceFile, originalOptions, context, style, templateStart) || this;
_this.style = style;
return _this;
}
UnusedCssVisitor.prototype.visitCssSelectorRule = function (ast) {
var _this = this;
try {
var match = ast.selectors.some(function (s) { return _this.visitCssSelector(s); });
if (!match) {
var start = ast.start.offset;
var end = ast.end.offset;
var length_1 = end - ast.start.offset + 1;
this.addFailure(this.createFailure(start, length_1, 'Unused styles', this.createReplacement(start, length_1, '')));
}
}
catch (e) {
logger_1.logger.error(e);
}
return true;
};
UnusedCssVisitor.prototype.visitCssSelector = function (ast) {
var parts = [];
for (var i = 0; i < ast.selectorParts.length; i += 1) {
var c = ast.selectorParts[i];
c.strValue = c.strValue.split('::').shift();
if (c.strValue.endsWith('/') ||
c.strValue.endsWith('>')) {
parts.push(c.strValue);
break;
}
else if (!c.strValue.startsWith(':')) {
parts.push(c.strValue);
}
}
if (!parts.length || !this.templateAst) {
return true;
}
var strippedSelector = parts.map(function (s) { return s.replace(/\/|>$/, '').trim(); }).join(' ');
var elementFilterVisitor = new ElementFilterVisitor(this.getSourceFile(), this._originalOptions, this.context, 0);
var tokenized = CssSelectorTokenizer.parse(strippedSelector);
var selectorTypesCache = Object.keys(dynamicFilters).reduce(function (a, key) {
a[key] = hasSelector(tokenized, key);
return a;
}, {});
if (!elementFilterVisitor.shouldVisit(this.templateAst, dynamicFilters, selectorTypesCache)) {
return true;
}
var matchFound = false;
var selector = function (element) {
if (lang(strippedSelector)(element)) {
matchFound = true;
return true;
}
return false;
};
var visitor = new ElementVisitor(this.getSourceFile(), this._originalOptions, this.context, 0);
visitor.visit(this.templateAst, selector);
return matchFound;
};
return UnusedCssVisitor;
}(basicCssAstVisitor_1.BasicCssAstVisitor));
var UnusedCssNgVisitor = (function (_super) {
__extends(UnusedCssNgVisitor, _super);
function UnusedCssNgVisitor() {
return _super !== null && _super.apply(this, arguments) || this;
}
UnusedCssNgVisitor.prototype.visitClassDeclaration = function (declaration) {
var _this = this;
var d = utils_1.getComponentDecorator(declaration);
if (d) {
var meta_1 = this._metadataReader.read(declaration);
this.visitNgComponent(meta_1);
if (meta_1.template && meta_1.template.template) {
try {
var ElementAstCtr_1 = compiler_1.ElementAst;
ngVersion_1.SemVerDSL
.gte('4.0.0-beta.8', function () {
_this.templateAst =
new ElementAstCtr_1('*', [], [], [], [], [], [], false, [], templateParser_1.parseTemplate(meta_1.template.template.code), 0, null, null);
})
.else(function () {
_this.templateAst =
new ElementAstCtr_1('*', [], [], [], [], [], [], false, templateParser_1.parseTemplate(meta_1.template.template.code), 0, null, null);
});
}
catch (e) {
logger_1.logger.error('Cannot parse the template', e);
}
}
}
_super.prototype.visitClassDeclaration.call(this, declaration);
};
UnusedCssNgVisitor.prototype.visitNgStyleHelper = function (style, context, styleMetadata, baseStart) {
var _this = this;
if (!style) {
return;
}
else {
var file = this.getContextSourceFile(styleMetadata.url, styleMetadata.style.source);
var visitor = new UnusedCssVisitor(file, this._originalOptions, context, styleMetadata, baseStart);
visitor.templateAst = this.templateAst;
var d = utils_1.getComponentDecorator(context.controller);
var encapsulation = utils_1.getDecoratorPropertyInitializer(d, 'encapsulation');
if (isEncapsulationEnabled(encapsulation)) {
style.visit(visitor);
visitor.getFailures().forEach(function (f) { return _this.addFailure(f); });
}
}
};
return UnusedCssNgVisitor;
}(ngWalker_1.NgWalker));
exports.UnusedCssNgVisitor = UnusedCssNgVisitor;