@@ -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+ */
5862function 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+ */
6880function 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+ */
80101function 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+ */
87111function 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+ */
91121function 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+ */
102138function 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+ */
106148function 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+ */
110158function 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+ */
114168function 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+ */
118178function 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+ */
122188function 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+ */
126198function 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+ */
130210function 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+ */
134234function 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+ */
138249function 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+ */
144261function 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+ */
150273function 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+ */
156309function 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+ */
167326function 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+ */
173338function 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+ */
181369function 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+ */
189399function 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+ */
195417function 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+ */
205439function 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+ */
215457function 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+ */
228478function getControllerDefinition ( context , node ) {
229479 var controllerArg = node . arguments [ 1 ] ;
230480
0 commit comments