Skip to content

Commit

Permalink
fix(cli-bundler): fix error on latest JS syntax, replaced outdated es…
Browse files Browse the repository at this point in the history
…prima with meriyah
  • Loading branch information
3cp committed Apr 12, 2021
1 parent 1aa0f8d commit 1dca043
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 284 deletions.
266 changes: 12 additions & 254 deletions lib/build/amodro-trace/lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var define = function(ary, fn) {

/*jslint plusplus: true */
/*global define: false */
define(['esprima', './lang'], function (esprima, lang) {
define(['meriyah', './lang'], function (meriyah, lang) {
'use strict';

function arrayToString(ary) {
Expand All @@ -30,7 +30,7 @@ define(['esprima', './lang'], function (esprima, lang) {
mixin = lang.mixin,
hasProp = lang.hasProp;

//From an esprima example for traversing its ast.
//From an meriyah example for traversing its ast.
function traverse(object, visitor) {
var child;

Expand Down Expand Up @@ -131,7 +131,7 @@ define(['esprima', './lang'], function (esprima, lang) {
result = '',
moduleList = [],
needsDefine = true,
astRoot = esprima.parse(fileContents);
astRoot = meriyah.parseScript(fileContents, {next: true, webcompat: true});

parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) {
if (!deps) {
Expand Down Expand Up @@ -296,85 +296,6 @@ define(['esprima', './lang'], function (esprima, lang) {
}
};

/**
* Determines if the file defines the require/define module API.
* Specifically, it looks for the `define.amd = ` expression.
* @param {String} fileName
* @param {String} fileContents
* @returns {Boolean}
*/
parse.definesRequire = function (fileName, fileContents) {
var foundDefine = false,
foundDefineAmd = false;

traverse(esprima.parse(fileContents), function (node) {
// Look for a top level declaration of a define, like
// var requirejs, require, define, off Program body.
if (node.type === 'Program' && node.body && node.body.length) {
foundDefine = node.body.some(function(bodyNode) {
// var define
if (bodyNode.type === 'VariableDeclaration') {
var decls = bodyNode.declarations;
if (decls) {
var hasVarDefine = decls.some(function(declNode) {
return (declNode.type === 'VariableDeclarator' &&
declNode.id &&
declNode.id.type === 'Identifier' &&
declNode.id.name === 'define');
});
if (hasVarDefine) {
return true;
}
}
}

// function define() {}
if (bodyNode.type === 'FunctionDeclaration' &&
bodyNode.id &&
bodyNode.id.type === 'Identifier' &&
bodyNode.id.name === 'define') {
return true;
}






});
}

// Need define variable found first, before detecting define.amd.
if (foundDefine && parse.hasDefineAmd(node)) {
foundDefineAmd = true;

//Stop traversal
return false;
}
});

return foundDefine && foundDefineAmd;
};

/**
* Finds require("") calls inside a CommonJS anonymous module wrapped in a
* define(function(require, exports, module){}) wrapper. These dependencies
* will be added to a modified define() call that lists the dependencies
* on the outside of the function.
* @param {String} fileName
* @param {String|Object} fileContents: a string of contents, or an already
* parsed AST tree.
* @returns {Array} an array of module names that are dependencies. Always
* returns an array, but could be of length zero.
*/
parse.getAnonDeps = function (fileName, fileContents) {
var astRoot = typeof fileContents === 'string' ?
esprima.parse(fileContents) : fileContents,
defFunc = this.findAnonDefineFactory(astRoot);

return parse.getAnonDepsFromNode(defFunc);
};

/**
* Finds require("") calls inside a CommonJS anonymous module wrapped
* in a define function, given an AST node for the definition function.
Expand Down Expand Up @@ -457,8 +378,10 @@ define(['esprima', './lang'], function (esprima, lang) {
/*jslint evil: true */
var jsConfig, foundConfig, stringData, foundRange, quote, quoteMatch,
quoteRegExp = /(:\s|\[\s*)(['"])/,
astRoot = esprima.parse(fileContents, {
loc: true
astRoot = meriyah.parseScript(fileContents, {
loc: true,
next: true,
webcompat: true
});

traverse(astRoot, function (node) {
Expand Down Expand Up @@ -514,54 +437,6 @@ define(['esprima', './lang'], function (esprima, lang) {
}
};

/**
* Renames require/requirejs/define calls to be ns + '.' + require/requirejs/define
* Does *not* do .config calls though. See pragma.namespace for the complete
* set of namespace transforms. This function is used because require calls
* inside a define() call should not be renamed, so a simple regexp is not
* good enough.
* @param {String} fileContents the contents to transform.
* @param {String} ns the namespace, *not* including trailing dot.
* @return {String} the fileContents with the namespace applied
*/
parse.renameNamespace = function (fileContents, ns) {
var lines,
locs = [],
astRoot = esprima.parse(fileContents, {
loc: true
});

parse.recurse(astRoot, function (callName, config, name, deps, node) {
locs.push(node.loc);
//Do not recurse into define functions, they should be using
//local defines.
return callName !== 'define';
}, {});

if (locs.length) {
lines = fileContents.split('\n');

//Go backwards through the found locs, adding in the namespace name
//in front.
locs.reverse();
locs.forEach(function (loc) {
var startIndex = loc.start.column,
//start.line is 1-based, not 0 based.
lineIndex = loc.start.line - 1,
line = lines[lineIndex];

lines[lineIndex] = line.substring(0, startIndex) +
ns + '.' +
line.substring(startIndex,
line.length);
});

fileContents = lines.join('\n');
}

return fileContents;
};

/**
* Finds all dependencies specified in dependency arrays and inside
* simplified commonjs wrappers.
Expand All @@ -577,7 +452,7 @@ define(['esprima', './lang'], function (esprima, lang) {
if (fileContents && fileContents.type) {
astRoot = fileContents
} else {
astRoot = esprima.parse(fileContents);
astRoot = meriyah.parseScript(fileContents, {next: true, webcompat: true});
}

parse.recurse(astRoot, function (callName, config, name, deps) {
Expand All @@ -596,7 +471,7 @@ define(['esprima', './lang'], function (esprima, lang) {
parse.findCjsDependencies = function (fileName, fileContents) {
var dependencies = [];

traverse(esprima.parse(fileContents), function (node) {
traverse(meriyah.parseScript(fileContents, {next: true, webcompat: true}), function (node) {
var arg;

if (node && node.type === 'CallExpression' && node.callee &&
Expand Down Expand Up @@ -668,61 +543,14 @@ define(['esprima', './lang'], function (esprima, lang) {
node.callee.name === 'define';
};

/**
* If there is a named define in the file, returns the name. Does not
* scan for mulitple names, just the first one.
*/
parse.getNamedDefine = function (fileContents) {
var name;
traverse(esprima.parse(fileContents), function (node) {
if (node && node.type === 'CallExpression' && node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'define' &&
node[argPropName] && node[argPropName][0] &&
node[argPropName][0].type === 'Literal') {
name = node[argPropName][0].value;
return false;
}
});

return name;
};

/**
* Finds all the named define module IDs in a file.
*/
parse.getAllNamedDefines = function (fileContents, excludeMap) {
var names = [];
parse.recurse(esprima.parse(fileContents),
function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) {
if (callName === 'define' && name) {
if (!excludeMap.hasOwnProperty(name)) {
names.push(name);
}
}

//If a UMD definition that points to a factory that is an Identifier,
//indicate processing should not traverse inside the UMD definition.
if (callName === 'define' && factoryIdentifier && hasProp(fnExpScope, factoryIdentifier)) {
return factoryIdentifier;
}

//If define was found, no need to dive deeper, unless
//the config explicitly wants to dig deeper.
return true;
}, {});

return names;
};

/**
* Determines if define(), require({}|[]) or requirejs was called in the
* file. Also finds out if define() is declared and if define.amd is called.
*/
parse.usesAmdOrRequireJs = function (fileName, fileContents) {
var uses;

traverse(esprima.parse(fileContents), function (node) {
traverse(meriyah.parseScript(fileContents, {next: true, webcompat: true}), function (node) {
var type, callName, arg;

if (parse.hasDefDefine(node)) {
Expand Down Expand Up @@ -764,7 +592,7 @@ define(['esprima', './lang'], function (esprima, lang) {
assignsExports = false;


traverse(esprima.parse(fileContents), function (node) {
traverse(meriyah.parseScript(fileContents, {next: true, webcompat: true}), function (node) {
var type,
// modified to fix a bug on (true || exports.name = {})
// https://github.com/requirejs/r.js/issues/980
Expand Down Expand Up @@ -980,7 +808,7 @@ define(['esprima', './lang'], function (esprima, lang) {
/**
* Converts an AST node into a JS source string by extracting
* the node's location from the given contents string. Assumes
* esprima.parse() with loc was done.
* meriyah.parseScript() with loc was done.
* @param {String} contents
* @param {Object} node
* @returns {String} a JS source string.
Expand Down Expand Up @@ -1015,75 +843,5 @@ define(['esprima', './lang'], function (esprima, lang) {
};
};

/**
* Extracts license comments from JS text.
* @param {String} fileName
* @param {String} contents
* @returns {String} a string of license comments.
*/
parse.getLicenseComments = function (fileName, contents) {
var commentNode, refNode, subNode, value, i, j,
//xpconnect's Reflect does not support comment or range, but
//prefer continued operation vs strict parity of operation,
//as license comments can be expressed in other ways, like
//via wrap args, or linked via sourcemaps.
ast = esprima.parse(contents, {
comment: true,
range: true
}),
result = '',
existsMap = {},
lineEnd = contents.indexOf('\r') === -1 ? '\n' : '\r\n';

if (ast.comments) {
for (i = 0; i < ast.comments.length; i++) {
commentNode = ast.comments[i];

if (commentNode.type === 'Line') {
value = '//' + commentNode.value + lineEnd;
refNode = commentNode;

if (i + 1 >= ast.comments.length) {
value += lineEnd;
} else {
//Look for immediately adjacent single line comments
//since it could from a multiple line comment made out
//of single line comments. Like this comment.
for (j = i + 1; j < ast.comments.length; j++) {
subNode = ast.comments[j];
if (subNode.type === 'Line' &&
subNode.range[0] === refNode.range[1] + 1) {
//Adjacent single line comment. Collect it.
value += '//' + subNode.value + lineEnd;
refNode = subNode;
} else {
//No more single line comment blocks. Break out
//and continue outer looping.
break;
}
}
value += lineEnd;
i = j - 1;
}
} else {
value = '/*' + commentNode.value + '*/' + lineEnd + lineEnd;
}

if (!existsMap[value] && (value.indexOf('license') !== -1 ||
(commentNode.type === 'Block' &&
value.indexOf('/*!') === 0) ||
value.indexOf('opyright') !== -1 ||
value.indexOf('(c)') !== -1)) {

result += value;
existsMap[value] = true;
}

}
}

return result;
};

return parse;
});
10 changes: 6 additions & 4 deletions lib/build/amodro-trace/lib/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ var define = function(ary, fn) {

/*global define */

define([ 'esprima', './parse', './lang'],
function (esprima, parse, lang) {
define([ 'meriyah', './parse', './lang'],
function (meriyah, parse, lang) {
'use strict';
var transform,
jsExtRegExp = /\.js$/g,
Expand Down Expand Up @@ -51,8 +51,10 @@ function (esprima, parse, lang) {
};

try {
astRoot = esprima.parse(contents, {
loc: true
astRoot = meriyah.parseScript(contents, {
loc: true,
next: true,
webcompat: true
});
} catch (e) {
var logger = options.logger;
Expand Down
4 changes: 2 additions & 2 deletions lib/build/amodro-trace/write/replace.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// and also dep string cleanup
// remove tailing '/', '.js'
const esprima = require('esprima');
const meriyah = require('meriyah');
const astMatcher = require('../../ast-matcher').astMatcher;
// it is definitely a named AMD module at this stage
var amdDep = astMatcher('define(__str, [__anl_deps], __any)');
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function stubs(options) {
};

// need node location
const parsed = esprima.parse(contents, {range: true});
const parsed = meriyah.parseScript(contents, {ranges: true, next: true, webcompat: true});

if (isUMD(parsed) || isUMD2(parsed)) {
// Skip lib in umd format, because browersify umd build could
Expand Down
Loading

0 comments on commit 1dca043

Please sign in to comment.