1 | 'use strict';
|
2 |
|
3 | var collection = require('../lib/collection'),
|
4 | debug = require('debug')('analyze-css:duplicated'),
|
5 | format = require('util').format;
|
6 |
|
7 | function rule(analyzer) {
|
8 | var selectors = new collection(),
|
9 | mediaQueryStack = [],
|
10 | browserPrefixRegEx = /^-(moz|o|webkit|ms)-/;
|
11 |
|
12 | analyzer.setMetric('duplicatedSelectors');
|
13 | analyzer.setMetric('duplicatedProperties');
|
14 |
|
15 |
|
16 | analyzer.on('media', function(query) {
|
17 | mediaQueryStack.push(query);
|
18 | debug('push: %j', mediaQueryStack);
|
19 | });
|
20 |
|
21 | analyzer.on('mediaEnd', function(query) {
|
22 | mediaQueryStack.pop(query);
|
23 | debug('pop: %j', mediaQueryStack);
|
24 | });
|
25 |
|
26 |
|
27 | analyzer.on('rule', function(rule) {
|
28 | selectors.push(
|
29 |
|
30 | (mediaQueryStack.length > 0 ? '@media ' + mediaQueryStack.join(' @media ') + ' ' : '') +
|
31 |
|
32 | rule.selectors.join(', ')
|
33 | );
|
34 | });
|
35 |
|
36 |
|
37 | analyzer.on('rule', function(rule) {
|
38 | var propertiesHash = {};
|
39 |
|
40 | if (rule.declarations) {
|
41 | rule.declarations.forEach(function(declaration) {
|
42 | var propertyName;
|
43 |
|
44 | if (declaration.type === 'declaration') {
|
45 | propertyName = declaration.property;
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | if (browserPrefixRegEx.test(declaration.value) === true) {
|
51 | return;
|
52 | }
|
53 |
|
54 |
|
55 | if (propertiesHash[propertyName] === true) {
|
56 |
|
57 | analyzer.setCurrentPosition(declaration.position);
|
58 |
|
59 | analyzer.incrMetric('duplicatedProperties');
|
60 | analyzer.addOffender('duplicatedProperties', format('%s {%s: %s}', rule.selectors.join(', '), declaration.property, declaration.value));
|
61 | } else {
|
62 |
|
63 | propertiesHash[propertyName] = true;
|
64 | }
|
65 | }
|
66 | });
|
67 | }
|
68 | });
|
69 |
|
70 |
|
71 |
|
72 | analyzer.on('font-face', function(rule) {
|
73 | rule.declarations.forEach(function(declaration) {
|
74 | if (declaration.property === 'src') {
|
75 | selectors.push('@font-face src: ' + declaration.value);
|
76 |
|
77 | debug('special handling for @font-face, provided src: %s', declaration.value);
|
78 | return false;
|
79 | }
|
80 | });
|
81 | });
|
82 |
|
83 | analyzer.on('report', function() {
|
84 | analyzer.setCurrentPosition(undefined);
|
85 |
|
86 | selectors.sort().forEach(function(selector, cnt) {
|
87 | if (cnt > 1) {
|
88 | analyzer.incrMetric('duplicatedSelectors');
|
89 | analyzer.addOffender('duplicatedSelectors', format('%s (%d times)', selector, cnt));
|
90 | }
|
91 | });
|
92 | });
|
93 | }
|
94 |
|
95 | rule.description = 'Reports duplicated CSS selectors and properties';
|
96 | module.exports = rule;
|