@gerhobbelt/mathjax-third-party-extensions
Version:
A list of MathJax extensions provided by third-party contributors
302 lines (262 loc) • 10.2 kB
JavaScript
// convertDefinesAndRequires.js
// ============================
// Replaces define() and require() methods to standard JavaScript
define([
'utils',
'convertToFunctionExpression',
'convertToObjectDeclaration',
'defaultValues',
'normalizeModuleName',
'createAst'
], function(
utils,
convertToFunctionExpression,
convertToObjectDeclaration,
defaultValues,
normalizeModuleName,
createAst
) {
return function convertDefinesAndRequires(node, parent) {
var amdclean = this,
options = amdclean.options,
moduleName,
args,
dependencies,
moduleReturnValue,
moduleId,
params,
isDefine = utils.isDefine(node),
isRequire = utils.isRequire(node),
startLineNumber,
callbackFuncArg = false,
type = '',
shouldBeIgnored,
moduleToBeIgnored,
parentHasFunctionExpressionArgument,
defaultRange = defaultValues.defaultRange,
defaultLOC = defaultValues.defaultLOC,
range = node.range || defaultRange,
loc = node.loc || defaultLOC,
dependencyBlacklist = defaultValues.dependencyBlacklist,
shouldOptimize;
startLineNumber = isDefine || isRequire ? node.expression.loc.start.line : node && node.loc && node.loc.start ? node.loc.start.line : null;
shouldBeIgnored = (amdclean.matchingCommentLineNumbers[startLineNumber] || amdclean.matchingCommentLineNumbers[startLineNumber - 1]);
// If it is an AMD conditional statement
// e.g. if(typeof define === 'function') {}
if (utils.isAMDConditional(node)) {
estraverse.traverse(node, {
'enter': function(node) {
var normalizedModuleName;
if (utils.isDefine(node)) {
if (node.expression && node.expression.arguments && node.expression.arguments.length) {
// Add the module name to the ignore list
if (node.expression.arguments[0].type === 'Literal' && node.expression.arguments[0].value) {
normalizedModuleName = normalizeModuleName.call(amdclean, node.expression.arguments[0].value);
if (options.transformAMDChecks !== true) {
amdclean.conditionalModulesToIgnore[normalizedModuleName] = true;
} else {
amdclean.conditionalModulesToNotOptimize[normalizedModuleName] = true;
}
if (options.createAnonymousAMDModule === true) {
amdclean.storedModules[normalizedModuleName] = false;
node.expression.arguments.shift();
}
}
}
}
}
});
// If the AMD conditional statement should be transformed and not ignored
if (!shouldBeIgnored && options.transformAMDChecks === true) {
// Transform the AMD conditional statement
// e.g. if(typeof define === 'function') {} -> if(true) {}
node.test = {
'type': 'Literal',
'value': true,
'raw': 'true',
'range': range,
'loc': loc
};
return node;
}
}
if (isDefine || isRequire) {
args = Array.prototype.slice.call(node.expression['arguments'], 0);
moduleReturnValue = isRequire ? args[1] : args[args.length - 1];
moduleId = node.expression['arguments'][0].value;
moduleName = normalizeModuleName.call(amdclean, moduleId);
shouldOptimize = !amdclean.conditionalModulesToNotOptimize[moduleName];
dependencies = (function() {
var deps = isRequire ? args[0] : args[args.length - 2],
depNames = [],
hasExportsParam;
if (_.isPlainObject(deps)) {
deps = deps.elements || [];
} else {
deps = [];
}
hasExportsParam = _.where(deps, {
'value': 'exports'
}).length;
if (_.isArray(deps) && deps.length) {
_.each(deps, function(currentDependency) {
if (dependencyBlacklist[currentDependency.value] && !shouldOptimize) {
depNames.push(currentDependency.value);
} else if (dependencyBlacklist[currentDependency.value] !== 'remove') {
if (currentDependency.value === "exports") {
depNames.push(moduleName);
amdclean.exportsModules[moduleName] = true;
} else if (dependencyBlacklist[currentDependency.value]) {
depNames.push('{}');
} else {
depNames.push(currentDependency.value);
}
} else {
if (!hasExportsParam) {
depNames.push('{}');
}
}
});
}
return depNames;
}());
params = {
'node': node,
'moduleName': moduleName,
'moduleId': moduleId,
'dependencies': dependencies,
'moduleReturnValue': moduleReturnValue,
'isDefine': isDefine,
'isRequire': isRequire,
'range': range,
'loc': loc,
'shouldOptimize': shouldOptimize
};
if (isDefine) {
if (shouldBeIgnored || !moduleName || amdclean.conditionalModulesToIgnore[moduleName] === true) {
amdclean.options.ignoreModules.push(moduleName);
return node;
}
if (_.contains(options.removeModules, moduleName)) {
// Remove the current module from the source
return {
'type': 'EmptyStatement'
};
}
if (_.isObject(options.shimOverrides) && options.shimOverrides[moduleId]) {
params.moduleReturnValue = createAst.call(amdclean, options.shimOverrides[moduleId]);
if (_.isArray(params.moduleReturnValue.body) && _.isObject(params.moduleReturnValue.body[0])) {
if (_.isObject(params.moduleReturnValue.body[0].expression)) {
params.moduleReturnValue = params.moduleReturnValue.body[0].expression;
type = 'objectExpression';
}
} else {
params.moduleReturnValue = moduleReturnValue;
}
} else if (params.moduleReturnValue && params.moduleReturnValue.type === 'Identifier') {
type = 'functionExpression';
}
if (_.contains(options.ignoreModules, moduleName)) {
return node;
} else if (utils.isFunctionExpression(moduleReturnValue) || type === 'functionExpression') {
return convertToFunctionExpression.call(amdclean, params);
} else if (utils.isObjectExpression(moduleReturnValue) || type === 'objectExpression') {
return convertToObjectDeclaration.call(amdclean, params);
} else if (utils.isFunctionCallExpression(moduleReturnValue)) {
return convertToObjectDeclaration.call(amdclean, params, 'functionCallExpression');
}
} else if (isRequire) {
if (shouldBeIgnored) {
return node;
}
callbackFuncArg = _.isArray(node.expression['arguments']) && node.expression['arguments'].length ? node.expression['arguments'][1] && node.expression['arguments'][1].body && node.expression['arguments'][1].body.body && node.expression['arguments'][1].body.body.length : false;
if (options.removeAllRequires !== true && callbackFuncArg) {
return convertToFunctionExpression.call(amdclean, params);
} else {
// Remove the require include statement from the source
return {
'type': 'EmptyStatement',
'range': range,
'loc': loc
};
}
}
} else {
// If the node is a function expression that has an exports parameter and does not return anything, return exports
if (node.type === 'FunctionExpression' &&
_.isArray(node.params) &&
_.where(node.params, {
'type': 'Identifier',
'name': 'exports'
}).length &&
_.isObject(node.body) &&
_.isArray(node.body.body) &&
!_.where(node.body.body, {
'type': 'ReturnStatement'
}).length) {
parentHasFunctionExpressionArgument = (function() {
if (!parent || !parent.arguments) {
return false;
}
if (parent && parent.arguments && parent.arguments.length) {
return _.where(parent.arguments, {
'type': 'FunctionExpression'
}).length;
}
return false;
}());
if (parentHasFunctionExpressionArgument) {
// Adds the logical expression, 'exports = exports || {}', to the beginning of the function expression
node.body.body.unshift({
'type': 'ExpressionStatement',
'expression': {
'type': 'AssignmentExpression',
'operator': '=',
'left': {
'type': 'Identifier',
'name': 'exports',
'range': defaultRange,
'loc': defaultLOC
},
'right': {
'type': 'LogicalExpression',
'operator': '||',
'left': {
'type': 'Identifier',
'name': 'exports',
'range': defaultRange,
'loc': defaultLOC
},
'right': {
'type': 'ObjectExpression',
'properties': [],
'range': defaultRange,
'loc': defaultLOC
},
'range': defaultRange,
'loc': defaultLOC
},
'range': defaultRange,
'loc': defaultLOC
},
'range': defaultRange,
'loc': defaultLOC
});
}
// Adds the return statement, 'return exports', to the end of the function expression
node.body.body.push({
'type': 'ReturnStatement',
'argument': {
'type': 'Identifier',
'name': 'exports',
'range': defaultRange,
'loc': defaultLOC
},
'range': defaultRange,
'loc': defaultLOC
});
}
return node;
}
};
});