Skip to content

Commit 08ec447

Browse files
committed
Add support for analyzing function expressions
1 parent 1bd74f4 commit 08ec447

13 files changed

Lines changed: 229 additions & 13 deletions

File tree

lib/node_modules/@stdlib/_tools/js/program-summary/README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ var summary = analyze( 'var beep = "boop";' );
9090
"data": [] // for...in statement content summaries
9191
},
9292
"var": 1, // total number of variable declarations
93-
"function": { // function declaration summary
94-
"count": 0, // total number of function declarations
95-
"data": [] // function declaration content summaries
93+
"function": { // function summary
94+
"count": 0, // total number of functions
95+
"data": [] // function content summaries
9696
}
9797
}
9898
*/
@@ -391,7 +391,11 @@ var summary = analyze( 'var beep = "boop";' );
391391
...
392392
```
393393
394-
- A function declaration summary includes a `params` field which is the number of function parameters for a given function and a `name` field which is the function identifier. For anonymous functions, the `name` is `(anonymous)`.
394+
- A function summary includes the following additional fields:
395+
396+
- `type`: function type. One of either `declaration` or `expression`.
397+
- `name`: function identifier. For anonymous functions, the `name` is `(anonymous)`.
398+
- `params`: number of function parameters.
395399
396400
```text
397401
...,
@@ -418,6 +422,7 @@ var summary = analyze( 'var beep = "boop";' );
418422
"forin": {...},
419423
"var": 0,
420424
"function": {...},
425+
"type": "declaration", // function type
421426
"name": "foo", // function identifier
422427
"params": 2 // number of parameters
423428
}

lib/node_modules/@stdlib/_tools/js/program-summary/lib/analyze.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
var parse = require( 'acorn' ).parse;
66
var contains = require( '@stdlib/assert/contains' );
7+
var trim = require( '@stdlib/string/trim' );
78
var RE_EOL = require( '@stdlib/regexp/eol' );
89
var flatten = require( './flatten.js' );
910
var sloc = require( './sloc.js' );
@@ -70,12 +71,28 @@ function analyze( results, ast, src, lines, scope, opts ) {
7071
type = node.type;
7172
scope = node.__scope__; // eslint-disable-line no-underscore-dangle
7273
if ( contains( recurseNodes, type ) ) {
74+
key = type2key( type );
75+
7376
// Initialize a new results object:
7477
res = resultsObject();
7578

7679
// Isolate the source code containing the AST node:
77-
str = src.substring( node.start, node.end );
78-
80+
if ( type === 'FunctionExpression' ) {
81+
str = src.substring( node.body.start+1, node.body.end-1 ); // everything inside `{}`
82+
83+
// Guard against empty functions:
84+
if ( trim( str ) === '' ) {
85+
res.type = 'expression';
86+
res.name = ( node.id ) ? node.id.name : '(anonymous)';
87+
res.params = node.params.length;
88+
89+
// Cache the sub-tree results:
90+
results[ key ].data.push( res );
91+
continue;
92+
}
93+
} else {
94+
str = src.substring( node.start, node.end );
95+
}
7996
// Split the source code string into separate lines:
8097
lines = str.split( RE_EOL );
8198

@@ -87,7 +104,10 @@ function analyze( results, ast, src, lines, scope, opts ) {
87104
ast = ast.body[ 0 ];
88105

89106
// Increment the scope if we are analyzing a function AST:
90-
if ( type === 'FunctionDeclaration' ) {
107+
if (
108+
type === 'FunctionDeclaration' ||
109+
type === 'FunctionExpression'
110+
) {
91111
scope += 1;
92112
}
93113
// Analyze the AST:
@@ -97,12 +117,17 @@ function analyze( results, ast, src, lines, scope, opts ) {
97117
if ( type === 'SwitchStatement' ) {
98118
res.case = node.cases.length;
99119
} else if ( type === 'FunctionDeclaration' ) {
100-
res.name = node.id.name || '(anonymous)';
120+
res.type = 'declaration';
121+
res.name = node.id.name;
122+
res.params = node.params.length;
123+
res.scope -= 1; // while contents are in a nested scope, declaration is in parent scope
124+
} else if ( type === 'FunctionExpression' ) {
125+
res.type = 'expression';
126+
res.name = ( node.id ) ? node.id.name : '(anonymous)';
101127
res.params = node.params.length;
102128
res.scope -= 1; // while contents are in a nested scope, declaration is in parent scope
103129
}
104130
// Cache the sub-tree results:
105-
key = type2key( type );
106131
results[ key ].data.push( res );
107132
}
108133
}

lib/node_modules/@stdlib/_tools/js/program-summary/lib/flatten.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ function flatten( ast, scope ) {
3232
*/
3333
function visit( node, state, ancestors ) {
3434
var level;
35+
var type;
3536
var i;
3637
if ( node !== ast && contains( types, node.type ) ) {
3738
level = scope;
3839
for ( i = 0; i < ancestors.length-1; i++ ) {
39-
if ( ancestors[ i ].type === 'FunctionDeclaration' ) {
40+
type = ancestors[ i ].type;
41+
if (
42+
type === 'FunctionDeclaration' ||
43+
type === 'FunctionExpression'
44+
) {
4045
level += 1;
4146
}
4247
}

lib/node_modules/@stdlib/_tools/js/program-summary/lib/node_types.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
// MAIN //
44

55
var types = [
6-
// Declarations:
6+
// Variables and functions:
77
'VariableDeclaration',
88
'FunctionDeclaration',
9+
'FunctionExpression',
910

1011
// Statements:
1112
'ExpressionStatement',

lib/node_modules/@stdlib/_tools/js/program-summary/lib/recurse_nodes.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
"DoWhileStatement",
77
"ForStatement",
88
"ForInStatement",
9-
"FunctionDeclaration"
9+
"FunctionDeclaration",
10+
"FunctionExpression"
1011
]

lib/node_modules/@stdlib/_tools/js/program-summary/lib/type2key.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ var table = {
1212
'ForStatement': 'for',
1313
'ForInStatement': 'forin',
1414
'VariableDeclaration': 'var',
15-
'FunctionDeclaration': 'function'
15+
'FunctionDeclaration': 'function',
16+
'FunctionExpression': 'function'
1617
};
1718

1819

lib/node_modules/@stdlib/_tools/js/program-summary/test/fixtures/1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,7 @@
12311231
"count": 0,
12321232
"data": []
12331233
},
1234+
"type": "declaration",
12341235
"name": "add",
12351236
"params": 2
12361237
}

lib/node_modules/@stdlib/_tools/js/program-summary/test/fixtures/2.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,7 @@
949949
"count": 0,
950950
"data": []
951951
},
952+
"type": "declaration",
952953
"name": "hypot",
953954
"params": 2
954955
}

lib/node_modules/@stdlib/_tools/js/program-summary/test/fixtures/empty_function_declaration.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
"count": 0,
132132
"data": []
133133
},
134+
"type": "declaration",
134135
"name": "noop",
135136
"params": 0
136137
}

lib/node_modules/@stdlib/_tools/js/program-summary/test/fixtures/function_declaration.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
"count": 0,
132132
"data": []
133133
},
134+
"type": "declaration",
134135
"name": "add",
135136
"params": 2
136137
}

0 commit comments

Comments
 (0)