UNPKG

5.55 kBJavaScriptView Raw
1/**
2 * require a consistent DI syntax
3 *
4 * All your DI should use the same syntax : the Array, function, or $inject syntaxes ("di": [2, "array, function, or $inject"])
5 *
6 * @version 0.1.0
7 * @category conventions
8 * @sinceAngularVersion 1.x
9 */
10'use strict';
11
12var utils = require('./utils/utils');
13
14var angularRule = require('./utils/angular-rule');
15
16
17module.exports = {
18 meta: {
19 schema: [{
20 enum: [
21 'function',
22 'array',
23 '$inject'
24 ]
25 }, {
26 type: 'object',
27 properties: {
28 matchNames: {
29 type: 'boolean'
30 },
31 stripUnderscores: {
32 type: 'boolean'
33 }
34 }
35 }]
36 },
37 create: angularRule(function(context) {
38 var syntax = context.options[0] || 'function';
39
40 var extra = context.options[1] || {};
41 var matchNames = extra.matchNames !== false;
42 var stripUnderscores = extra.stripUnderscores === true;
43
44 function report(node) {
45 context.report(node, 'You should use the {{syntax}} syntax for DI', {
46 syntax: syntax
47 });
48 }
49
50 var $injectProperties = {};
51
52 function maybeNoteInjection(node) {
53 if (syntax === '$inject' && node.left && node.left.property &&
54 ((utils.isLiteralType(node.left.property) && node.left.property.value === '$inject') ||
55 (utils.isIdentifierType(node.left.property) && node.left.property.name === '$inject'))) {
56 $injectProperties[node.left.object.name] = node.right;
57 }
58 }
59
60 function normalizeParameter(param) {
61 return param.replace(/^_(.+)_$/, function(match, p1) {
62 return p1;
63 });
64 }
65
66 function checkDi(callee, fn) {
67 if (!fn) {
68 return;
69 }
70
71 if (syntax === 'array') {
72 if (utils.isArrayType(fn.parent)) {
73 if (fn.parent.elements.length - 1 !== fn.params.length) {
74 context.report(fn, 'The signature of the method is incorrect', {});
75 return;
76 }
77
78 if (matchNames) {
79 var invalidArray = fn.params.filter(function(e, i) {
80 var name = e.name;
81
82 if (stripUnderscores) {
83 name = normalizeParameter(name);
84 }
85
86 return name !== fn.parent.elements[i].value;
87 });
88 if (invalidArray.length > 0) {
89 context.report(fn, 'You have an error in your DI configuration. Each items of the array should match exactly one function parameter', {});
90 return;
91 }
92 }
93 } else {
94 if (fn.params.length === 0) {
95 return;
96 }
97 report(fn);
98 }
99 }
100
101 if (syntax === 'function') {
102 if (utils.isArrayType(fn.parent)) {
103 report(fn);
104 }
105 }
106
107 if (syntax === '$inject') {
108 if (fn && fn.id && utils.isIdentifierType(fn.id)) {
109 var $injectArray = $injectProperties[fn.id.name];
110
111 if ($injectArray && utils.isArrayType($injectArray)) {
112 if ($injectArray.elements.length !== fn.params.length) {
113 context.report(fn, 'The signature of the method is incorrect', {});
114 return;
115 }
116
117 if (matchNames) {
118 var invalidInjectArray = fn.params.filter(function(e, i) {
119 var name = e.name;
120
121 if (stripUnderscores) {
122 name = normalizeParameter(name);
123 }
124
125 return name !== $injectArray.elements[i].value;
126 });
127 if (invalidInjectArray.length > 0) {
128 context.report(fn, 'You have an error in your DI configuration. Each items of the array should match exactly one function parameter', {});
129 return;
130 }
131 }
132 } else if (fn.params.length > 0) {
133 report(fn);
134 }
135 } else if (fn.params && fn.params.length !== 0) {
136 report(fn);
137 }
138 }
139 }
140
141 return {
142 'angular?animation': checkDi,
143 'angular?config': checkDi,
144 'angular?controller': checkDi,
145 'angular?directive': checkDi,
146 'angular?factory': checkDi,
147 'angular?filter': checkDi,
148 'angular?inject': checkDi,
149 'angular?run': checkDi,
150 'angular?service': checkDi,
151 'angular?provider': function(callee, providerFn, $get) {
152 checkDi(null, providerFn);
153 checkDi(null, $get);
154 },
155 AssignmentExpression: function(node) {
156 maybeNoteInjection(node);
157 }
158 };
159 })
160};