fonteditor/node/amd2module.js
2015-01-27 23:51:53 +08:00

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);
};