blob: d14794fad3c7929416c1b2d26b01427b75d28a71 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var glob = require('glob');
var fsExtra = require('fs-extra');
var esprima = require('esprima');
function run(cb) {
glob('**/*.js', {
cwd: __dirname + '/../src/'
}, function (err, files) {
files.forEach(function (filePath) {
var code = parse(fsExtra.readFileSync(
__dirname + '/../src/' + filePath, 'utf-8'));
code = code.replace(/require\(([\'"])zrender\//g, 'require($1zrender/lib/');
fsExtra.outputFileSync(
__dirname + '/../lib/' + filePath,
code, 'utf-8');
});
cb && cb();
});
}
if (require.main === module) {
run();
}
else {
module.exports = run;
}
var MAGIC_DEPS = {
'exports' : true,
'module' : true,
'require' : true
};
var SIMPLIFIED_CJS = ['require', 'exports', 'module'];
// Convert AMD-style JavaScript string into node.js compatible module
function parse (raw){
var output = '';
var ast = esprima.parse(raw, {
range: true,
raw: true
});
var defines = ast.body.filter(isDefine);
if ( defines.length > 1 ){
throw new Error('Each file can have only a single define call. Found "'+ defines.length +'"');
} else if (!defines.length){
return raw;
}
var def = defines[0];
var args = def.expression['arguments'];
var factory = getFactory( args );
var useStrict = getUseStrict( factory );
// do replacements in-place to avoid modifying the code more than needed
if (useStrict) {
output += useStrict.expression.raw +';\n';
}
output += raw.substring( 0, def.range[0] ); // anything before define
output += getRequires(args, factory); // add requires
output += getBody(raw, factory.body, useStrict); // module body
output += raw.substring( def.range[1], raw.length ); // anything after define
return output;
}
function getRequires(args, factory){
var requires = [];
var deps = getDependenciesNames( args );
var params = factory.params.map(function(param, i){
return {
name : param.name,
// simplified cjs doesn't have deps
dep : (deps.length)? deps[i] : SIMPLIFIED_CJS[i]
};
});
params.forEach(function(param){
if ( MAGIC_DEPS[param.dep] && !MAGIC_DEPS[param.name] ) {
// if user remaped magic dependency we declare a var
requires.push( 'var '+ param.name +' = '+ param.dep +';' );
} else if ( param.dep && !MAGIC_DEPS[param.dep] ) {
// only do require for params that have a matching dependency also
// skip "magic" dependencies
requires.push( 'var '+ param.name +' = require(\''+ param.dep +'\');' );
}
});
return requires.join('\n');
}
function getDependenciesNames(args){
var deps = [];
var arr = args.filter(function(arg){
return arg.type === 'ArrayExpression';
})[0];
if (arr) {
deps = arr.elements.map(function(el){
return el.value;
});
}
return deps;
}
function isDefine(node){
return node.type === 'ExpressionStatement' &&
node.expression.type === 'CallExpression' &&
node.expression.callee.type === 'Identifier' &&
node.expression.callee.name === 'define';
}
function getFactory(args){
return args.filter(function(arg){
return arg.type === 'FunctionExpression';
})[0];
}
function getBody(raw, factoryBody, useStrict){
var returnStatement = factoryBody.body.filter(function(node){
return node.type === 'ReturnStatement';
})[0];
var body = '';
var bodyStart = useStrict ? useStrict.expression.range[1] + 1 : factoryBody.range[0] + 1;
if (returnStatement) {
body += raw.substring( bodyStart, returnStatement.range[0] );
// "return ".length === 7 so we add "6" to returnStatement start
body += 'module.exports ='+ raw.substring( returnStatement.range[0] + 6, factoryBody.range[1] - 1 );
} else {
// if using exports or module.exports or just a private module we
// simply return the factoryBody content
body = raw.substring( bodyStart, factoryBody.range[1] - 1 );
}
return body;
}
function getUseStrict(factory){
return factory.body.body.filter(isUseStrict)[0];
}
function isUseStrict(node){
return node.type === 'ExpressionStatement' &&
node.expression.type === 'Literal' &&
node.expression.value === 'use strict';
}