219 lines
5.2 KiB
JavaScript
219 lines
5.2 KiB
JavaScript
/**
|
|
* @file amd 模块转换为commonjs模块
|
|
* @author mengke01(kekee000@gmail.com)
|
|
*/
|
|
|
|
var esprima = require('esprima');
|
|
var estraverse = require( 'estraverse' );
|
|
var escodegen = require('escodegen');
|
|
var SYNTAX = estraverse.Syntax;
|
|
|
|
// 顶级模块,用来生成相对位置
|
|
var REG_TOP_MODULE = /^(:?common|math|graphics|ttf)/;
|
|
|
|
var EXPORT_SEGMENT = {
|
|
"expression": {
|
|
"left": {
|
|
"computed": false,
|
|
"object": {
|
|
"name": "module",
|
|
"type": "Identifier"
|
|
},
|
|
"property": {
|
|
"name": "exports",
|
|
"type": "Identifier"
|
|
},
|
|
"type": "MemberExpression"
|
|
},
|
|
"operator": "=",
|
|
"right": null,
|
|
"type": "AssignmentExpression"
|
|
},
|
|
"type": "ExpressionStatement"
|
|
};
|
|
|
|
/**
|
|
* 获取导出声明
|
|
*
|
|
* @return {Object}
|
|
*/
|
|
function getExportStatement() {
|
|
return JSON.parse(JSON.stringify(EXPORT_SEGMENT));
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取ast树
|
|
* @param {string} code 代码片段
|
|
* @return {Object} ast树
|
|
*/
|
|
function getAst(code) {
|
|
var ast = null;
|
|
|
|
try {
|
|
ast = esprima.parse(code, {
|
|
// raw: true,
|
|
// tokens: true,
|
|
// range: true,
|
|
// comment: true
|
|
});
|
|
} catch (ex) {
|
|
throw 'can\'t parse amd code';
|
|
}
|
|
|
|
return ast;
|
|
}
|
|
|
|
/**
|
|
* 获取define的factory
|
|
*
|
|
* @return {astNode}
|
|
*/
|
|
function getDefineFactory(defineExpr) {
|
|
|
|
var args = defineExpr['arguments'];
|
|
var factoryAst;
|
|
|
|
// 解析参数
|
|
for (var i = 0, l = args.length; i < l; i++) {
|
|
var argument = args[i];
|
|
if (argument.type === SYNTAX.FunctionExpression || argument.type === SYNTAX.ObjectExpression) {
|
|
factoryAst = argument;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return factoryAst;
|
|
}
|
|
|
|
/**
|
|
* 替换define的return为 module.exports
|
|
*
|
|
* @param {Object} ast ast
|
|
* @return {Object} ast
|
|
*/
|
|
function replaceDefine(ast) {
|
|
|
|
estraverse.replace(ast, {
|
|
enter: function (node, parent) {
|
|
|
|
if ( node.type === SYNTAX.ExpressionStatement
|
|
&& node.expression.type === SYNTAX.CallExpression
|
|
&& node.expression.callee.name === 'define'
|
|
) {
|
|
var factory = getDefineFactory(node.expression);
|
|
|
|
// define('xxx', {})
|
|
if (factory.type === SYNTAX.ObjectExpression) {
|
|
var exportStatment = getExportStatement();
|
|
exportStatment.expression.right = factory;
|
|
|
|
return exportStatment;
|
|
}
|
|
|
|
// define(function() {})
|
|
else if (factory.type === SYNTAX.FunctionExpression){
|
|
|
|
var body = factory.body.body;
|
|
// 替换return
|
|
for (var i = body.length - 1; i >=0; i--) {
|
|
if (body[i].type === SYNTAX.ReturnStatement) {
|
|
var exportStatment = getExportStatement();
|
|
exportStatment.expression.right = body[i].argument;
|
|
body.splice(i, 1, exportStatment);
|
|
break;
|
|
}
|
|
}
|
|
|
|
var index = parent.body.indexOf(node);
|
|
Array.prototype.splice.apply(parent.body, [index, 1].concat(body));
|
|
|
|
return body[0];
|
|
}
|
|
|
|
}
|
|
|
|
return node;
|
|
}
|
|
});
|
|
|
|
return ast;
|
|
}
|
|
|
|
|
|
/**
|
|
* 去除生成的代码缩进
|
|
*
|
|
* @param {Object} ast ast
|
|
* @return {Object} ast
|
|
*/
|
|
function replaceComments(ast) {
|
|
if (ast.comments && ast.comments.length) {
|
|
ast.comments.forEach(function (comment) {
|
|
if (comment.type === 'Block') {
|
|
// 去除缩进
|
|
comment.value = comment.value.replace(/ /g, '');
|
|
}
|
|
});
|
|
}
|
|
|
|
return ast;
|
|
}
|
|
|
|
/**
|
|
* 替换require的绝对路径为相对路径
|
|
*
|
|
* @param {Object} ast ast
|
|
* @param {Object} codeDepth 当前模块位置
|
|
* @return {Object} ast
|
|
*/
|
|
function replaceRequire(ast, codeDepth) {
|
|
|
|
estraverse.replace(ast, {
|
|
enter: function (node, parent) {
|
|
|
|
if ( node.type === SYNTAX.CallExpression
|
|
&& node.callee.name === 'require'
|
|
&& node.arguments.length
|
|
&& node.arguments[0].type === 'Literal'
|
|
) {
|
|
var argument = node.arguments[0];
|
|
if (REG_TOP_MODULE.test(argument.value)) {
|
|
argument.value = codeDepth + argument.value;
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
} );
|
|
|
|
return ast;
|
|
}
|
|
|
|
|
|
/**
|
|
* 生成commonjs代码
|
|
* @param {Object} ast ast树
|
|
* @return {string} 生成后的代码
|
|
*/
|
|
function genCommonJS(ast) {
|
|
|
|
// ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
|
|
return escodegen.generate(ast, {
|
|
// comment: true
|
|
});
|
|
}
|
|
|
|
module.exports = function (code, codeDepth) {
|
|
|
|
if (codeDepth && codeDepth[codeDepth.length - 1] !== '/') {
|
|
codeDepth += '/';
|
|
}
|
|
|
|
var ast = getAst(code);
|
|
ast = replaceRequire(ast, codeDepth);
|
|
ast = replaceDefine(ast);
|
|
// ast = replaceComments(ast);
|
|
return genCommonJS(ast);
|
|
};
|