Skip to content

Commit ed9daee

Browse files
committed
Add documentation for utils
1 parent 0ebd36d commit ed9daee

File tree

1 file changed

+252
-2
lines changed

1 file changed

+252
-2
lines changed

rules/utils/utils.js

Lines changed: 252 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ module.exports = {
5454
};
5555

5656

57-
// this will recursively grab the callee until it hits an Identifier
57+
/**
58+
* Recursively grab the callee until an Identifier is found.
59+
*
60+
* @todo Needs better documentation.
61+
*/
5862
function getCallingIdentifier(calleeObject) {
5963
if (calleeObject.type && calleeObject.type === 'Identifier') {
6064
return calleeObject;
@@ -65,6 +69,14 @@ function getCallingIdentifier(calleeObject) {
6569
return null;
6670
}
6771

72+
/**
73+
* Convert a prefix string to a RegExp.
74+
*
75+
* `'/app/'` → `/app.*\/`
76+
*
77+
* @param {string} prefix
78+
* @returns {RegExp}
79+
*/
6880
function convertPrefixToRegex(prefix) {
6981
if (typeof prefix !== 'string') {
7082
return prefix;
@@ -77,17 +89,35 @@ function convertPrefixToRegex(prefix) {
7789
return new RegExp(prefix + '.*');
7890
}
7991

92+
/**
93+
* Convert a string to a RegExp.
94+
*
95+
* `'app'` → `/app/`
96+
* `'/app/'` → `/app/`
97+
*
98+
* @param {string} prefix
99+
* @returns {RegExp}
100+
*/
80101
function convertStringToRegex(string) {
81102
if (string[0] === '/' && string[string.length - 1] === '/') {
82103
string = string.substring(1, string.length - 2);
83104
}
84105
return new RegExp(string);
85106
}
86107

108+
/**
109+
* @todo Missing documentation
110+
*/
87111
function isTypeOfStatement(node) {
88112
return node.type === 'Identifier' || (node.type === 'UnaryExpression' && node.operator === 'typeof');
89113
}
90114

115+
/**
116+
* @todo Missing documentation
117+
*
118+
* @param {Object} node The node to check.
119+
* @returns {boolean} Whether or not the node is a `toString` statement.
120+
*/
91121
function isToStringStatement(node) {
92122
return node.type === 'CallExpression' &&
93123
node.callee.type === 'MemberExpression' &&
@@ -99,60 +129,183 @@ function isToStringStatement(node) {
99129
node.callee.object.object.property.name === 'prototype';
100130
}
101131

132+
/**
133+
* Check whether or not a node is an ArrayExpression.
134+
*
135+
* @param {Object} node The node to check.
136+
* @returns {boolean} Whether or not the node is an ArrayExpression.
137+
*/
102138
function isArrayType(node) {
103139
return node !== undefined && node.type === 'ArrayExpression';
104140
}
105141

142+
/**
143+
* Check whether or not a node is an FunctionExpression.
144+
*
145+
* @param {Object} node The node to check.
146+
* @returns {boolean} Whether or not the node is an FunctionExpression.
147+
*/
106148
function isFunctionType(node) {
107149
return node !== undefined && node.type === 'FunctionExpression';
108150
}
109151

152+
/**
153+
* Check whether or not a node is an Identifier.
154+
*
155+
* @param {Object} node The node to check.
156+
* @returns {boolean} Whether or not the node is an Identifier.
157+
*/
110158
function isIdentifierType(node) {
111159
return node !== undefined && node.type === 'Identifier';
112160
}
113161

162+
/**
163+
* Check whether or not a node is an MemberExpression.
164+
*
165+
* @param {Object} node The node to check.
166+
* @returns {boolean} Whether or not the node is an MemberExpression.
167+
*/
114168
function isMemberExpression(node) {
115169
return node !== undefined && node.type === 'MemberExpression';
116170
}
117171

172+
/**
173+
* Check whether or not a node is an Literal.
174+
*
175+
* @param {Object} node The node to check.
176+
* @returns {boolean} Whether or not the node is an Literal.
177+
*/
118178
function isLiteralType(node) {
119179
return node !== undefined && node.type === 'Literal';
120180
}
121181

182+
/**
183+
* Check whether or not a node is an isEmptyFunction.
184+
*
185+
* @param {Object} node The node to check.
186+
* @returns {boolean} Whether or not the node is an isEmptyFunction.
187+
*/
122188
function isEmptyFunction(fn) {
123189
return fn.body.body.length === 0;
124190
}
125191

192+
/**
193+
* Check whether or not an object is a RegExp object.
194+
*
195+
* @param regexp The object for which to check if it is a RegExp object.
196+
* @returns {boolean} Shether or not an object is a RegExp object.
197+
*/
126198
function isRegexp(regexp) {
127199
return toString.call(regexp) === '[object RegExp]';
128200
}
129201

202+
/**
203+
* Check whether or not a string resembles a regular expression.
204+
*
205+
* A string is considered a regular expression if it starts and ends with `/`.
206+
*
207+
* @param {string} The string to check.
208+
* @returns {boolean} Whether or not a string resembles a regular expression.
209+
*/
130210
function isStringRegexp(string) {
131211
return string[0] === '/' && string[string.length - 1] === '/';
132212
}
133213

214+
/**
215+
* Check if a CallExpression node somewhat resembles an Angular component.
216+
*
217+
* The following are considered Angular components
218+
* ```js
219+
* app.factory('kittenService', function() {})
220+
* ^^^^^^^
221+
* app.factory('kittenService', kittenService)
222+
* ^^^^^^^
223+
* app.factory('kittenService', [])
224+
* ^^^^^^^
225+
* asyncFn('value', callback)
226+
* ^^^^^^^
227+
* ```
228+
*
229+
* @todo FIXME
230+
*
231+
* @param {Object} node The CallExpression node to check.
232+
* @returns {boolean} Whether or not the node somewhat resembles an Angular component.
233+
*/
134234
function isAngularComponent(node) {
135-
return node.arguments !== undefined && node.arguments.length === 2 && isLiteralType(node.arguments[0]) && (isIdentifierType(node.arguments[1]) || isFunctionType(node.arguments[1]) || isArrayType(node.arguments[1]));
235+
return node.arguments !== undefined &&
236+
node.arguments.length === 2 &&
237+
isLiteralType(node.arguments[0]) &&
238+
(isIdentifierType(node.arguments[1]) ||
239+
isFunctionType(node.arguments[1]) ||
240+
isArrayType(node.arguments[1]));
136241
}
137242

243+
/**
244+
* Check whether a CallExpression node defines an Angular controller.
245+
*
246+
* @param {Object} node The CallExpression node to check.
247+
* @returns {boolean} Whether or not the node defines an Angular controller.
248+
*/
138249
function isAngularControllerDeclaration(node) {
139250
return isAngularComponent(node) &&
140251
isMemberExpression(node.callee) &&
141252
node.callee.property.name === 'controller';
142253
}
143254

255+
/**
256+
* Check whether a CallExpression node defines an Angular filter.
257+
*
258+
* @param {Object} node The CallExpression node to check.
259+
* @returns {boolean} Whether or not the node defines an Angular filter.
260+
*/
144261
function isAngularFilterDeclaration(node) {
145262
return isAngularComponent(node) &&
146263
isMemberExpression(node.callee) &&
147264
node.callee.property.name === 'filter';
148265
}
149266

267+
/**
268+
* Check whether a CallExpression node defines an Angular directive.
269+
*
270+
* @param {Object} node The CallExpression node to check.
271+
* @returns {boolean} Whether or not the node defines an Angular directive.
272+
*/
150273
function isAngularDirectiveDeclaration(node) {
151274
return isAngularComponent(node) &&
152275
isMemberExpression(node.callee) &&
153276
node.callee.property.name === 'directive';
154277
}
155278

279+
/**
280+
* Check whether a node defines an Angular service.
281+
*
282+
* The following are considered services
283+
* ```js
284+
* app.provider('kittenServiceProvider', function() {})
285+
* ^^^^^^^^
286+
* app.factory('kittenService', function() {})
287+
* ^^^^^^^
288+
* app.service('kittenService', function() {})
289+
* ^^^^^^^
290+
* app.constant('KITTENS', function() {})
291+
* ^^^^^^^^
292+
* app.value('KITTENS', function() {})
293+
* ^^^^^
294+
* ```
295+
*
296+
* The following are not considered services
297+
* ```js
298+
* $provide.factory('kittenService', function() {})
299+
* app.constant('KITTENS', 'meow')
300+
* app.value('KITTENS', 'purr')
301+
* this.$get = function() {}
302+
* ```
303+
*
304+
* @todo FIXME
305+
*
306+
* @param {Object} node The CallExpression node to check.
307+
* @returns {boolean} Whether or not the node defines an Angular controller.
308+
*/
156309
function isAngularServiceDeclaration(node) {
157310
return isAngularComponent(node) &&
158311
isMemberExpression(node.callee) &&
@@ -164,12 +317,24 @@ function isAngularServiceDeclaration(node) {
164317
node.callee.property.name === 'value');
165318
}
166319

320+
/**
321+
* Check whether a CallExpression node declares an Angular module.
322+
*
323+
* @param {Object} node The CallExpression node to check.
324+
* @returns {boolean} Whether or not the node declares an Angular module.
325+
*/
167326
function isAngularModuleDeclaration(node) {
168327
return isAngularComponent(node) &&
169328
isMemberExpression(node.callee) &&
170329
node.callee.property.name === 'module';
171330
}
172331

332+
/**
333+
* Check whether a CallExpression node gets or declares an Angular module.
334+
*
335+
* @param {Object} node The CallExpression node to check.
336+
* @returns {boolean} Whether or not the node gets or declares an Angular module.
337+
*/
173338
function isAngularModuleGetter(node) {
174339
return node.arguments !== undefined &&
175340
node.arguments.length > 0 &&
@@ -178,6 +343,29 @@ function isAngularModuleGetter(node) {
178343
node.callee.property.name === 'module';
179344
}
180345

346+
/**
347+
* Check whether a CallExpression node defines an Angular run function.
348+
*
349+
* The following are considered run functions
350+
* ```js
351+
* app.run()
352+
* ^^^
353+
* app.run(function() {})
354+
* ^^^
355+
* ```
356+
*
357+
* The following are not considered run functions
358+
* ```js
359+
* angular.module('myApp').run(function() {})
360+
* angular.module('myApp', []).run(function() {})
361+
* mocha.run()
362+
* ```
363+
*
364+
* @todo FIXME
365+
*
366+
* @param {Object} node The CallExpression node to check.
367+
* @returns {boolean} Whether or not the node defines an Angular run function.
368+
*/
181369
function isAngularRunSection(node) {
182370
return isMemberExpression(node.callee) &&
183371
node.callee.property.type === 'Identifier' &&
@@ -186,12 +374,46 @@ function isAngularRunSection(node) {
186374
node.callee.object.name !== 'mocha');
187375
}
188376

377+
/**
378+
* Check whether a CallExpression node defines an Angular config function.
379+
*
380+
* The following are considered config functions
381+
* ```js
382+
* app.config()
383+
* ^^^^^^
384+
* app.config(function() {})
385+
* ^^^^^^
386+
* ```
387+
*
388+
* The following are not considered run functions
389+
* ```js
390+
* angular.module('myApp').config(function() {})
391+
* angular.module('myApp', []).config(function() {})
392+
* ```
393+
*
394+
* @todo FIXME
395+
*
396+
* @param {Object} node The CallExpression node to check.
397+
* @returns {boolean} Whether or not the node defines an Angular config function.
398+
*/
189399
function isAngularConfigSection(node) {
190400
return isMemberExpression(node.callee) &&
191401
node.callee.property.type === 'Identifier' &&
192402
node.callee.property.name === 'config';
193403
}
194404

405+
/**
406+
* Check whether a CallExpression node defines a route using $routeProvider.
407+
*
408+
* The following are considered routes:
409+
* ```js
410+
* $routeProvider.when()
411+
* ^^^^
412+
* ```
413+
*
414+
* @param {Object} node The CallExpression node to check.
415+
* @returns {boolean} Whether or not the node defines a route.
416+
*/
195417
function isRouteDefinition(node) {
196418
// the route def function is .when(), so when we find that, go up through the chain and make sure
197419
// $routeProvider is the calling object
@@ -202,6 +424,18 @@ function isRouteDefinition(node) {
202424
return false;
203425
}
204426

427+
/**
428+
* Check whether a CallExpression node defines a state using $stateProvider.
429+
*
430+
* The following are considered states:
431+
* ```js
432+
* $stateProvider.state()
433+
* ^^^^^
434+
* ```
435+
*
436+
* @param {Object} node The CallExpression node to check.
437+
* @returns {boolean} Whether or not the node defines a state.
438+
*/
205439
function isUIRouterStateDefinition(node) {
206440
// the state def function is .state(), so when we find that, go up through the chain and make sure
207441
// $stateProvider is the calling object
@@ -212,6 +446,14 @@ function isUIRouterStateDefinition(node) {
212446
return false;
213447
}
214448

449+
/**
450+
* Find an identifier node in the current scope.
451+
*
452+
* @param {Object} context The context to use to get the scope.
453+
* @param {Object} identifier The identifier node to look up.
454+
*
455+
* @returns {Object} The node declaring the identifier.
456+
*/
215457
function findIdentiferInScope(context, identifier) {
216458
var identifierNode = null;
217459
context.getScope().variables.forEach(function(variable) {
@@ -225,6 +467,14 @@ function findIdentiferInScope(context, identifier) {
225467
return identifierNode;
226468
}
227469

470+
/**
471+
* Find the function definition of a controller in the current context.
472+
*
473+
* @param {Object} context The context to use to find the controller declaration.
474+
* @param {Object} node The Angular controller call to look up the declaration for.
475+
*
476+
* @returns {Object} The identifier declaring the controller function.
477+
*/
228478
function getControllerDefinition(context, node) {
229479
var controllerArg = node.arguments[1];
230480

0 commit comments

Comments
 (0)