UNPKG

6.73 kBJavaScriptView Raw
1/**
2 * require a consistent order of module dependencies
3 *
4 * Module dependencies should be sorted in a logical manner.
5 * This rule provides two ways to sort modules, grouped or ungrouped.
6 * In grouped mode the modules should be grouped in the order: standard modules - third party modules - custom modules.
7 * The modules should be sorted alphabetically within its group.
8 * A prefix can be specified to determine which prefix the custom modules have.
9 * Without grouped set to `false` all dependencies combined should be sorted alphabetically.
10 * ('module-dependency-order', [2, {grouped: true, prefix: "app"}])
11 *
12 * @version 0.12.0
13 * @category conventions
14 * @sinceAngularVersion 1.x
15 */
16'use strict';
17
18var utils = require('./utils/utils');
19
20module.exports = {
21 meta: {
22 schema: [{
23 type: 'object',
24 properties: {
25 grouped: {
26 type: 'boolean'
27 },
28 prefix: {
29 type: ['string', 'null']
30 }
31 }
32 }]
33 },
34 create: function(context) {
35 var options = context.options[0] || {};
36 var groupedMode = options.grouped !== false;
37 var moduleRegex;
38 if (groupedMode) {
39 moduleRegex = utils.convertPrefixToRegex(options.prefix);
40 }
41
42 var standard = [
43 // Libraries in the angular.js repository
44 'ng',
45 'ngAnimate',
46 'ngAria',
47 'ngCookies',
48 'ngLocale',
49 'ngMessageFormat',
50 'ngMessages',
51 'ngMock',
52 'ngResource',
53 'ngRoute',
54 'ngSanitize',
55 'ngTouch',
56
57 // Libraries maintained by the angular team, but in another repository
58 'ngMaterial',
59 'ngNewRouter'
60 ];
61
62 function checkLiteral(node) {
63 if (node && node.type !== 'Literal' && node.type !== 'Identifier') {
64 context.report(node, 'Unexpected non-literal or identifier value' + node.type);
65 return false;
66 }
67 if (!node) {
68 return false;
69 }
70 return true;
71 }
72
73 function checkCombined(deps) {
74 var lastCorrect;
75 deps.elements.forEach(function(node) {
76 if (!checkLiteral(node)) {
77 return;
78 }
79 var value = node.value || node.name;
80 if (lastCorrect === undefined || lastCorrect.localeCompare(value) < 0) {
81 lastCorrect = value;
82 } else {
83 context.report(node, '{{current}} should be sorted before {{last}}', {
84 current: value,
85 last: lastCorrect
86 });
87 }
88 });
89 }
90
91 function isStandardModule(value) {
92 return standard.indexOf(value) !== -1;
93 }
94
95 function isCustomModule(value) {
96 return moduleRegex && moduleRegex.test(value);
97 }
98
99 function checkGrouped(deps) {
100 var lastCorrect;
101 var group = 'standard';
102 deps.elements.forEach(function loop(node) {
103 if (!checkLiteral(node)) {
104 return;
105 }
106 var value = node.value || node.name;
107 if (lastCorrect === undefined) {
108 lastCorrect = value;
109 if (isCustomModule(value)) {
110 group = 'custom';
111 } else if (standard.indexOf(value) === -1) {
112 group = 'third party';
113 }
114 return;
115 }
116 if (group === 'standard') {
117 if (isStandardModule(value)) {
118 if (lastCorrect.localeCompare(value) > 0) {
119 context.report(node, '{{current}} should be sorted before {{last}}', {
120 current: value,
121 last: lastCorrect
122 });
123 } else {
124 lastCorrect = value;
125 }
126 } else {
127 if (isCustomModule(value)) {
128 group = 'custom';
129 } else {
130 group = 'third party';
131 }
132 lastCorrect = value;
133 }
134 }
135 if (group === 'third party') {
136 if (isStandardModule(value)) {
137 context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
138 current: value,
139 last: lastCorrect
140 });
141 } else if (isCustomModule(value)) {
142 group = 'custom';
143 lastCorrect = value;
144 } else if (lastCorrect.localeCompare(value) > 0) {
145 context.report(node, '{{current}} should be sorted before {{last}}', {
146 current: value,
147 last: lastCorrect
148 });
149 } else {
150 lastCorrect = value;
151 }
152 }
153 if (group === 'custom') {
154 if (isStandardModule(value)) {
155 context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
156 current: value,
157 last: lastCorrect
158 });
159 } else if (!isCustomModule(value)) {
160 context.report(node, '{{current}} is a third party module and should be sorted before {{last}}', {
161 current: value,
162 last: lastCorrect
163 });
164 }
165 }
166 });
167 }
168
169 return {
170 CallExpression: function(node) {
171 if (!utils.isAngularModuleDeclaration(node)) {
172 return;
173 }
174 var deps = node.arguments[1];
175 if (deps.type !== 'ArrayExpression') {
176 context.report(deps, 'Dependencies should be a literal array');
177 return;
178 }
179 if (groupedMode) {
180 checkGrouped(deps);
181 } else {
182 checkCombined(deps);
183 }
184 }
185 };
186 }
187};