Skip to content

Commit e95aea7

Browse files
swmitraficristo
authored andcommitted
JSUtils modification to handle es6 constructs (adobe#13635)
* JSUtils modification to handle es6 constructs * Addressed review comments and added es6 test cases * Address Code review comments and add support for ArrowFunctionExpressions with new test case * Update comments * Refactor to remove extra variables
1 parent 9f3abb6 commit e95aea7

File tree

11 files changed

+700
-51
lines changed

11 files changed

+700
-51
lines changed

Gruntfile.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ module.exports = function (grunt) {
138138
src: [
139139
'less/dist/less.min.js'
140140
]
141+
},
142+
{
143+
expand: true,
144+
dest: 'src/thirdparty/acorn',
145+
cwd: 'src/node_modules/acorn',
146+
src: [
147+
'dist/{,*/}*'
148+
]
141149
}
142150
]
143151
}

src/extensions/default/QuickOpenJavaScript/main.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ define(function (require, exports, module) {
6565
var lines = docText.split("\n");
6666
var functions = JSUtils.findAllMatchingFunctionsInText(docText, "*");
6767
functions.forEach(function (funcEntry) {
68-
var chFrom = lines[funcEntry.lineStart].indexOf(funcEntry.name);
69-
var chTo = chFrom + funcEntry.name.length;
70-
functionList.push(new FileLocation(null, funcEntry.lineStart, chFrom, chTo, funcEntry.name));
68+
functionList.push(new FileLocation(null, funcEntry.nameLineStart, funcEntry.columnStart, funcEntry.columnEnd, funcEntry.label || funcEntry.name));
7169
});
7270
return functionList;
7371
}

src/language/JSUtils.js

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121
*
2222
*/
2323

24-
/*jslint regexp: true */
25-
2624
/**
2725
* Set of utilities for simple parsing of JS text.
2826
*/
2927
define(function (require, exports, module) {
3028
"use strict";
3129

32-
var _ = require("thirdparty/lodash");
30+
var _ = require("thirdparty/lodash"),
31+
Acorn = require("thirdparty/acorn/dist/acorn"),
32+
AcornLoose = require("thirdparty/acorn/dist/acorn_loose"),
33+
ASTWalker = require("thirdparty/acorn/dist/walk");
3334

3435
// Load brackets modules
3536
var CodeMirror = require("thirdparty/CodeMirror/lib/codemirror"),
@@ -47,17 +48,6 @@ define(function (require, exports, module) {
4748
*/
4849
var _changedDocumentTracker = new ChangedDocumentTracker();
4950

50-
/**
51-
* Function matching regular expression. Recognizes the forms:
52-
* "function functionName()", "functionName = function()", and
53-
* "functionName: function()".
54-
*
55-
* Note: JavaScript identifier matching is not strictly to spec. This
56-
* RegExp matches any sequence of characters that is not whitespace.
57-
* @type {RegExp}
58-
*/
59-
var _functionRegExp = /(function\s+([$_A-Za-z\u007F-\uFFFF][$_A-Za-z0-9\u007F-\uFFFF]*)\s*(\([^)]*\)))|(([$_A-Za-z\u007F-\uFFFF][$_A-Za-z0-9\u007F-\uFFFF]*)\s*[:=]\s*function\s*(\([^)]*\)))/g;
60-
6151
/**
6252
* @private
6353
* Return an object mapping function name to offset info for all functions in the specified text.
@@ -66,21 +56,112 @@ define(function (require, exports, module) {
6656
* @return {Object.<string, Array.<{offsetStart: number, offsetEnd: number}>}
6757
*/
6858
function _findAllFunctionsInText(text) {
69-
var results = {},
59+
var AST,
60+
results = {},
7061
functionName,
62+
resultNode,
63+
memberPrefix,
7164
match;
72-
65+
7366
PerfUtils.markStart(PerfUtils.JSUTILS_REGEXP);
74-
75-
while ((match = _functionRegExp.exec(text)) !== null) {
76-
functionName = (match[2] || match[5]).trim();
77-
67+
68+
try {
69+
AST = Acorn.parse(text, {locations: true});
70+
} catch (e) {
71+
AST = AcornLoose.parse_dammit(text, {locations: true});
72+
}
73+
74+
function _addResult(node, offset, prefix) {
75+
memberPrefix = prefix ? prefix + " - " : "";
76+
resultNode = node.id || node.key || node;
77+
functionName = resultNode.name;
7878
if (!Array.isArray(results[functionName])) {
7979
results[functionName] = [];
8080
}
8181

82-
results[functionName].push({offsetStart: match.index});
82+
results[functionName].push(
83+
{
84+
offsetStart: offset || node.start,
85+
label: memberPrefix ? memberPrefix + functionName : null,
86+
location: resultNode.loc
87+
}
88+
);
8389
}
90+
91+
ASTWalker.simple(AST, {
92+
/*
93+
function <functionName> () {}
94+
*/
95+
FunctionDeclaration: function (node) {
96+
// As acorn_loose marks identifier names with '✖' under erroneous declarations
97+
// we should have a check to discard such 'FunctionDeclaration' nodes
98+
if (node.id.name !== '✖') {
99+
_addResult(node);
100+
}
101+
},
102+
/*
103+
class <className> () {}
104+
*/
105+
ClassDeclaration: function (node) {
106+
_addResult(node);
107+
ASTWalker.simple(node, {
108+
/*
109+
class <className> () {
110+
<methodName> () {
111+
112+
}
113+
}
114+
*/
115+
MethodDefinition: function (methodNode) {
116+
_addResult(methodNode, methodNode.key.start, node.id.name);
117+
}
118+
});
119+
},
120+
/*
121+
var <functionName> = function () {}
122+
123+
or
124+
125+
var <functionName> = () => {}
126+
*/
127+
VariableDeclarator: function (node) {
128+
if (node.init && (node.init.type === "FunctionExpression" || node.init.type === "ArrowFunctionExpression")) {
129+
_addResult(node);
130+
}
131+
},
132+
/*
133+
SomeFunction.prototype.<functionName> = function () {}
134+
*/
135+
AssignmentExpression: function (node) {
136+
if (node.right && node.right.type === "FunctionExpression") {
137+
if (node.left && node.left.type === "MemberExpression" && node.left.property) {
138+
_addResult(node.left.property);
139+
}
140+
}
141+
},
142+
/*
143+
{
144+
<functionName>: function() {}
145+
}
146+
*/
147+
Property: function (node) {
148+
if (node.value && node.value.type === "FunctionExpression") {
149+
if (node.key && node.key.type === "Identifier") {
150+
_addResult(node.key);
151+
}
152+
}
153+
},
154+
/*
155+
<functionName>: function() {}
156+
*/
157+
LabeledStatement: function (node) {
158+
if (node.body && node.body.type === "FunctionDeclaration") {
159+
if (node.label) {
160+
_addResult(node.label);
161+
}
162+
}
163+
}
164+
});
84165

85166
PerfUtils.addMeasurement(PerfUtils.JSUTILS_REGEXP);
86167

@@ -415,8 +496,13 @@ define(function (require, exports, module) {
415496
var endOffset = _getFunctionEndOffset(text, funcEntry.offsetStart);
416497
result.push({
417498
name: functionName,
499+
label: funcEntry.label,
418500
lineStart: StringUtils.offsetToLineNum(lines, funcEntry.offsetStart),
419-
lineEnd: StringUtils.offsetToLineNum(lines, endOffset)
501+
lineEnd: StringUtils.offsetToLineNum(lines, endOffset),
502+
nameLineStart: funcEntry.location.start.line - 1,
503+
nameLineEnd: funcEntry.location.end.line - 1,
504+
columnStart: funcEntry.location.start.column,
505+
columnEnd: funcEntry.location.end.column
420506
});
421507
});
422508
}

0 commit comments

Comments
 (0)