1 | var Promise = require('promise');
|
2 | var lodash = require('lodash'),
|
3 | Parser = require('./parser'),
|
4 | knife = require('./knife'),
|
5 | presets = require('./presets'),
|
6 | RuleList = require('./rule_list'),
|
7 | InlineConfig = require('./inline_config');
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | var Linter = function (rules) {
|
15 | this.rules = RuleList.fromRuleMap(rules);
|
16 | this.parser = new Parser();
|
17 | this.inlineConfig = new InlineConfig();
|
18 | };
|
19 | module.exports = Linter;
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | Linter.prototype.use = function (plugin) {
|
26 | if (plugin.rules) {
|
27 | plugin.rules.forEach(function (rule) {
|
28 | this.rules.addRule(rule);
|
29 | }.bind(this));
|
30 | }
|
31 | };
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | Linter.prototype.lint = function (html) {
|
38 | var opts = Linter.getOptions(arguments),
|
39 | lines = knife.shred(html),
|
40 | dom = this.parser.parse(html),
|
41 | issues = null,
|
42 | maxerr = (!opts.maxerr && opts.maxerr !== 0 ? Infinity : opts.maxerr);
|
43 |
|
44 | this.setupSubscriptions();
|
45 |
|
46 | this.setupInlineConfigs(dom);
|
47 |
|
48 | issues = this.lintByLine(lines, opts);
|
49 | issues = issues.concat(this.lintDom(dom, opts));
|
50 |
|
51 | issues = issues.concat(this.resetRules(opts));
|
52 | this.inlineConfig.clear();
|
53 |
|
54 | if (maxerr >= 0) {
|
55 | issues = lodash.first(issues, maxerr);
|
56 | }
|
57 |
|
58 | return Promise.all(issues)
|
59 | .then(function (resolved) {
|
60 | return lodash.flatten(resolved);
|
61 | });
|
62 | };
|
63 | Linter.prototype.lint = Promise.nodeify(Linter.prototype.lint);
|
64 |
|
65 | Linter.getOptions = function (args) {
|
66 | var optList = Array.prototype.slice.call(args, 1);
|
67 | optList = lodash.flatten(optList);
|
68 |
|
69 | optList.unshift('default');
|
70 |
|
71 | return presets.flattenOpts(optList);
|
72 | };
|
73 |
|
74 | Linter.prototype.setupSubscriptions = function () {
|
75 | this.rules.forEach(function (rule) {
|
76 | rule.subscribers = this.rules.getSubscribers(rule.name);
|
77 | }.bind(this));
|
78 | };
|
79 |
|
80 | Linter.prototype.lintByLine = function (lines, opts) {
|
81 | return this.rules.getRule('line').lint(lines, opts, this.inlineConfig);
|
82 | };
|
83 |
|
84 | Linter.prototype.lintDom = function (dom, opts) {
|
85 | return this.rules.getRule('dom').lint(dom, opts, this.inlineConfig);
|
86 | };
|
87 |
|
88 | Linter.prototype.resetRules = function (opts) {
|
89 | var issues = [];
|
90 |
|
91 | this.rules.forEach(function (rule) {
|
92 | if (!rule.end) {
|
93 | return;
|
94 | }
|
95 |
|
96 | var result = rule.end(opts);
|
97 | if (result) {
|
98 | issues.push(result);
|
99 | }
|
100 | });
|
101 |
|
102 | return lodash.flatten(issues);
|
103 | };
|
104 |
|
105 | Linter.prototype.setupInlineConfigs = function (dom) {
|
106 | var comments = [];
|
107 | var feedComments = function (element) {
|
108 | if (element.type === 'comment') {
|
109 | comments.push(element);
|
110 | this.inlineConfig.feedComment(element);
|
111 | }
|
112 | if (element.children && element.children.length > 0) {
|
113 | element.children.forEach(function (child) {
|
114 | feedComments(child);
|
115 | });
|
116 | }
|
117 | }.bind(this);
|
118 | if (dom.length) {
|
119 | dom.forEach(feedComments);
|
120 | }
|
121 | };
|