diff --git a/build/amdclean.min.js b/build/amdclean.min.js
index 2a43dfe..39e7987 100644
--- a/build/amdclean.min.js
+++ b/build/amdclean.min.js
@@ -1 +1 @@
-!function(e,t){"use strict";"function"==typeof define&&define.amd?(t.env="undefined"!=typeof exports?"node":"web",t.amd=!0,define(["esprima","estraverse","escodegen","underscore"],function(n,r,i,s){return t({esprima:n,estraverse:r,escodegen:i,underscore:s},e)})):"undefined"!=typeof exports?(t.env="node",module.exports=t(null,e)):(t.env="web",e.amdclean=t(null,e))}(this,function cleanamd(amdDependencies,scope){"use strict";amdDependencies=amdDependencies||{};var codeEnv=cleanamd.env,that=scope,esprima=function(){return cleanamd.amd&&amdDependencies.esprima&&amdDependencies.esprima.parse?amdDependencies.esprima:that&&that.esprima&&that.esprima.parse?that.esprima:"node"===codeEnv?require("esprima"):void 0}(),estraverse=function(){return cleanamd.amd&&amdDependencies.estraverse&&amdDependencies.estraverse.traverse?amdDependencies.estraverse:that&&that.estraverse&&that.estraverse.traverse?that.estraverse:"node"===codeEnv?require("estraverse"):void 0}(),escodegen=function(){return cleanamd.amd&&amdDependencies.escodegen&&amdDependencies.escodegen.generate?amdDependencies.escodegen:that&&that.escodegen&&that.escodegen.generate?that.escodegen:"node"===codeEnv?require("escodegen"):void 0}(),_=function(){return cleanamd.amd&&amdDependencies.underscore?amdDependencies.underscore:that&&that._?that._:"node"===codeEnv?require("lodash"):void 0}(),fs="node"===codeEnv?require("fs"):{},publicAPI={VERSION:"1.2.1",defaultOptions:{code:"",filePath:"",globalModules:[],globalObject:!1,globalObjectName:"amdclean",esprima:{comment:!0,loc:!0,range:!0,tokens:!0},escodegen:{comment:!0},commentCleanName:"amdclean",ignoreModules:[],removeModules:[],removeAllRequires:!1,removeUseStricts:!0,shimOverrides:{},rememberGlobalObject:!0,prefixMode:"standard",prefixTransform:function(e){return e},wrap:{start:"",end:""}},env:codeEnv,errorMsgs:{emptyCode:"There is no code to generate the AST with",emptyAst:function(e){return"An AST is not being passed to the "+e+"() method"},invalidObject:function(e){return"An object is not being passed as the first parameter to the "+e+"() method"},lodash:"There is not an _.isPlainObject() method. Make sure you have included lodash (https://github.com/lodash/lodash).",esprima:"There is not an esprima.parse() method. Make sure you have included esprima (https://github.com/ariya/esprima).",estraverse:"There is not an estraverse.replace() method. Make sure you have included estraverse (https://github.com/Constellation/estraverse).",escodegen:"There is not an escodegen.generate() method. Make sure you have included escodegen (https://github.com/Constellation/escodegen)."},dependencyBlacklist:{require:!0,exports:!0,module:!0},readFile:function(e){return"node"!==publicAPI.env?"":fs.readFileSync(e,"utf8")},isDefine:function(e){var t=e.expression||{},n=t.callee;return _.isObject(e)&&"ExpressionStatement"===e.type&&_.isObject(t)&&"CallExpression"===t.type&&"Identifier"===n.type&&"define"===n.name},isRequire:function(e){var t=e.expression||{},n=t.callee;return _.isObject(e)&&"ExpressionStatement"===e.type&&_.isObject(t)&&"CallExpression"===t.type&&"Identifier"===n.type&&"require"===n.name},isRequireExpression:function(e){return"CallExpression"===e.type&&e.callee&&"require"===e.callee.name},isObjectExpression:function(e){return e&&_.isPlainObject(e)&&"ObjectExpression"===e.type},isFunctionExpression:function(e){return e&&_.isPlainObject(e)&&"FunctionExpression"===e.type},isFunctionCallExpression:function(e){return e&&_.isPlainObject(e)&&"CallExpression"===e.type&&_.isPlainObject(e.callee)&&"FunctionExpression"===e.callee.type},isUseStrict:function(e){return e&&_.isPlainObject(e)&&"Literal"===e.type&&"use strict"===e.value},isAMDConditional:function(e){if(e&&"IfStatement"!==e.type||!_.isObject(e.test)||!_.isObject(e.test.left)||_.isNull(e.test.left.value))return!1;var t={left:{operator:"typeof",argument:{type:"Identifier",name:"define"}},right:{type:"Literal",value:"function"}};return _.where(e.test,t).length||_.where([e.test],t).length||_.where(e.test.left,t).length||_.where([e.test.left],t).length},arrayContains:function(e,t){return _.isArray(e)?-1!==e.indexOf(t):!1},convertToCamelCase:function(e,t){return t=t||"_",e.replace(new RegExp(t+"(.)","g"),function(e,t){return t.toUpperCase()})},prefixReservedWords:function(name){var reservedWord=!1;try{name.length&&eval("var "+name+" = 1;")}catch(e){reservedWord=!0}return reservedWord===!0?"_"+name:name},normalizeModuleName:function(e){var t,n,r,i=publicAPI.options.prefixMode,s=publicAPI.options.prefixTransform;return e=e||"","{}"===e?e:(t=publicAPI.prefixReservedWords(e.replace(/\./g,"").replace(/[^A-Za-z0-9_$]/g,"_").replace(/^_+/,"")),n="camelCase"===i?publicAPI.convertToCamelCase(t):t,_.isFunction(s)&&(r=s(n),_.isString(r)&&r.length)?r:n)},returnExpressionIdentifier:function(e){return{type:"ExpressionStatement",expression:{type:"Identifier",name:e}}},convertToObjectDeclaration:function(e,t){var n=(e.node,e.moduleName),r=function(){var n,r,i,s,a,o;return"functionCallExpression"===t&&(n=e.moduleReturnValue,r=n.callee,i=r.params,i&&i.length&&_.isArray(i)&&_.where(i,{name:"global"})&&_.isObject(r.body)&&_.isArray(r.body.body)&&(s=_.where(r.body.body,{type:"ReturnStatement"})[0],_.isObject(s)&&_.isObject(s.argument)&&"FunctionExpression"===s.argument.type&&(o=s.argument,_.isObject(o.body)&&_.isArray(o.body.body)&&(a=_.where(o.body.body,{type:"ReturnStatement"})[0],_.isObject(a.argument)&&_.isObject(a.argument.right)&&_.isObject(a.argument.right.property)&&a.argument.right.property.name&&(n={type:"MemberExpression",computed:!1,object:{type:"Identifier",name:"window"},property:{type:"Identifier",name:a.argument.right.property.name}}))))),n=n||e.moduleReturnValue}(),i=publicAPI.options,s=function(){return i.globalObject===!0&&i.globalObjectName?{type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:{type:"MemberExpression",computed:!0,object:{type:"Identifier",name:i.globalObjectName},property:{type:"Literal",value:n,raw:""+n}},right:r}}:{type:"VariableDeclaration",declarations:[{type:"VariableDeclarator",id:{type:"Identifier",name:n},init:r}],kind:"var"}}();return s},convertToIIFE:function(e){var t=e.callbackFuncParams,n=e.callbackFunc,r=e.dependencyNames;return{type:"ExpressionStatement",expression:{type:"CallExpression",callee:{type:"FunctionExpression",id:null,params:t,defaults:[],body:n.body,rest:n.rest,generator:n.generator,expression:n.expression},arguments:r}}},convertToIIFEDeclaration:function(e){var t=e.moduleName,n=e.callbackFuncParams,r=e.isOptimized,i=function(){var t=e.callbackFunc;return"Identifier"===t.type&&"undefined"!==t.name&&(t={type:"FunctionExpression",id:null,params:[],defaults:[],body:{type:"BlockStatement",body:[{type:"ReturnStatement",argument:{type:"CallExpression",callee:{type:"Identifier",name:t.name},arguments:[]}}]},rest:null,generator:!1,expression:!1}),t}(),s=e.dependencyNames,a=publicAPI.options,o=function(){return"Literal"===i.type||"Identifier"===i.type&&"undefined"===i.name||r===!0?i:{type:"CallExpression",callee:{type:"FunctionExpression",id:{type:"Identifier",name:""},params:n,defaults:[],body:i.body,rest:i.rest,generator:i.generator,expression:i.expression},arguments:s}}(),c=function(){return a.globalObject===!0&&a.globalObjectName?{type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:{type:"MemberExpression",computed:!0,object:{type:"Identifier",name:a.globalObjectName},property:{type:"Literal",value:t,raw:""+t}},right:o}}:{type:"VariableDeclaration",declarations:[{type:"VariableDeclarator",id:{type:"Identifier",name:t},init:o}],kind:"var"}}();return c},convertToFunctionExpression:function(e){var t=e.isDefine,n=e.isRequire,r=!1,i=(e.node,e.moduleName),s=e.dependencies,a=s.length,o=publicAPI.options,c=function(){for(var e,t=[],n=-1;++n1||s&&"Identifier"===s.type)return o;o=s,r=!0,o.params&&(a=o.params.length)}}else o&&"FunctionExpression"===o.type&&o.body&&_.isArray(o.body.body)&&0===o.body.body.length&&(o={type:"Identifier",name:"undefined"},a=0);return o}(),l=function(){var e=[];return p&&p.body&&_.isArray(p.body.body)&&(e=_.where(p.body.body,{type:"ReturnStatement"}),e.length)?!0:!1}(),u=!1,d=function(){for(var e,t,n=[],r=-1,i=p.params||[];++r1||a&&"Identifier"===a.type)return o;o=a,r=!0,o.params&&(s=o.params.length)}}else o&&"FunctionExpression"===o.type&&o.body&&_.isArray(o.body.body)&&0===o.body.body.length&&(o={type:"Identifier",name:"undefined"},s=0);return o}(),u=function(){var e=[];return l&&l.body&&_.isArray(l.body.body)&&(e=_.where(l.body.body,{type:"ReturnStatement"}),e.length)?!0:!1}(),d=!1,m=function(){for(var e,t,n=[],r=-1,i=l.params||[];++r true
+ isRelativeFilePath: function(path) {
+ var segments = path.split('/');
+
+ return segments.length !== -1 && (segments[0] === '.' || segments[0] === '..');
+ },
+ // normalizeDependencyName
+ // -----------------------
+ // Returns a normalized dependency name that handles relative file paths
+ 'normalizeDependencyName': function(moduleId, dep) {
+ if(!moduleId || !dep || !publicAPI.isRelativeFilePath(dep)) {
+ return dep;
+ }
+
+ var normalizePath = function(path) {
+ var segments = path.split('/'),
+ normalizedSegments;
+
+ normalizedSegments = _.reduce(segments, function(memo, segment) {
+ switch(segment) {
+ case '.':
+ break;
+ case '..':
+ memo.pop();
+ break;
+ default:
+ memo.push(segment);
+ }
+
+ return memo;
+ }, []);
+ return normalizedSegments.join('/');
+ },
+ baseName = function(path) {
+ var segments = path.split('/');
+
+ segments.pop();
+ return segments.join('/');
+ };
+ return normalizePath([baseName(moduleId), dep].join('/'));
+ },
// convertToFunctionExpression
// ---------------------------
// Returns either an IIFE or variable declaration.
- // Internally calls either convertToIIFE() or convertToIIFEDeclaration().
+ // Internally calls either convertToIIFE() or convertToIIFEDeclaration()
'convertToFunctionExpression': function(obj) {
var isDefine = obj.isDefine,
isRequire = obj.isRequire,
isOptimized = false,
node = obj.node,
moduleName = obj.moduleName,
+ moduleId = obj.moduleId,
dependencies = obj.dependencies,
depLength = dependencies.length,
options = publicAPI.options,
@@ -577,7 +622,7 @@
iterator = -1,
currentName;
while(++iterator < depLength) {
- currentName = dependencies[iterator];
+ currentName = publicAPI.normalizeDependencyName(moduleId, dependencies[iterator]);
if(options.globalObject === true && options.globalObjectName && currentName !== '{}') {
deps.push({
'type': 'MemberExpression',
@@ -717,6 +762,7 @@
args,
dependencies,
moduleReturnValue,
+ moduleId,
params,
isDefine = publicAPI.isDefine(node),
isRequire = publicAPI.isRequire(node),
@@ -778,10 +824,12 @@
return depNames;
}());
moduleReturnValue = isRequire ? args[1] : args[args.length - 1];
- moduleName = publicAPI.normalizeModuleName(node.expression['arguments'][0].value);
+ moduleId = node.expression['arguments'][0].value;
+ moduleName = publicAPI.normalizeModuleName(moduleId);
params = {
node: node,
moduleName: moduleName,
+ moduleId: moduleId,
dependencies: dependencies,
moduleReturnValue: moduleReturnValue,
isDefine: isDefine,
@@ -968,6 +1016,7 @@
if(ast && _.isArray(ast.body)) {
estraverse.replace(ast, {
enter: function(node, parent) {
+ var normalizedModuleName;
if(node === undefined || node.type === 'EmptyStatement') {
_.each(parent.body, function(currentNode, iterator) {
if(currentNode === undefined || currentNode.type === 'EmptyStatement') {
@@ -976,10 +1025,27 @@
});
} else if(publicAPI.isRequireExpression(node)) {
if(node['arguments'] && node['arguments'][0] && node['arguments'][0].value) {
- return {
- 'type': 'Identifier',
- 'name': publicAPI.normalizeModuleName(node['arguments'][0].value)
- };
+ normalizedModuleName = publicAPI.normalizeModuleName(node['arguments'][0].value);
+ if(options.globalObject === true && (options.globalObjectName && _.isString(options.globalObjectName) && options.globalObjectName.length)) {
+ return {
+ 'type': 'MemberExpression',
+ 'computed': true,
+ 'object': {
+ 'type': 'Identifier',
+ 'name': options.globalObjectName
+ },
+ 'property': {
+ 'type': 'Literal',
+ 'value': normalizedModuleName,
+ 'raw': normalizedModuleName
+ }
+ };
+ } else {
+ return {
+ 'type': 'Identifier',
+ 'name': normalizedModuleName
+ };
+ }
} else {
return node;
}
diff --git a/test/specs/convert.js b/test/specs/convert.js
index b04dfa2..1c2331d 100644
--- a/test/specs/convert.js
+++ b/test/specs/convert.js
@@ -37,6 +37,30 @@ describe('amdclean specs', function() {
expect(cleanedCode).toBe(standardJavaScript);
});
+ it('should correctly normalize relative file paths dependencies', function() {
+ var AMDcode = "define('./modules/example', ['./example1', './example2', '../example3'], function(one, two, three) {var test = true;});",
+ cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var modules_example=function (one,two,three){var test=true;}(modules_example1,modules_example2,example3);";
+
+ expect(cleanedCode).toBe(standardJavaScript);
+ });
+
+ it('should correctly normalize relative file paths dependencies with the globalObject option', function() {
+ var AMDcode = "define('./modules/example', ['./example1', './example2', '../example3'], function(one, two, three) {var test = true;});",
+ cleanedCode = amdclean.clean({ globalObject: true, rememberGlobalObject: false, code: AMDcode, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var amdclean={};amdclean['modules_example']=function (one,two,three){var test=true;}(amdclean['modules_example1'],amdclean['modules_example2'],amdclean['example3']);";
+
+ expect(cleanedCode).toBe(standardJavaScript);
+ });
+
+ it('should correctly normalize multi-level relative file paths dependencies', function() {
+ var AMDcode = "define('./foo/prototype/subModule/myModule', ['example1','example2', '/anotherModule/example3', '../../example4','../anotherModule/example5'], function(one, two, three, four, five) { var test = true;});",
+ cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var foo_prototype_subModule_myModule=function (one,two,three,four,five){var test=true;}(example1,example2,anotherModule_example3,foo_example4,foo_prototype_anotherModule_example5);";
+
+ expect(cleanedCode).toBe(standardJavaScript);
+ });
+
it('should correctly normalize multi-level relative file paths', function() {
var AMDcode = "define('./foo/prototype/commonMethodName.js', ['example1', 'example2'], function(one, two) { var test = true;});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
@@ -119,8 +143,8 @@ describe('amdclean specs', function() {
it('should support storing modules inside of a global object', function() {
var AMDcode = "define('foo', ['require', 'exports', './bar'], function(require, exports){exports.bar = require('./bar');});",
- cleanedCode = amdclean.clean({ globalObject: true, globalObjectName: 'yeabuddy', code: AMDcode, escodegen: { format: { compact: true } } }),
- standardJavaScript = "var yeabuddy={};yeabuddy['foo']=function (require,exports,bar){exports.bar=bar;return exports;}({},{},yeabuddy['bar']);";
+ cleanedCode = amdclean.clean({ globalObject: true, rememberGlobalObject: false, globalObjectName: 'yeabuddy', code: AMDcode, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var yeabuddy={};yeabuddy['foo']=function (require,exports,bar){exports.bar=yeabuddy['bar'];return exports;}({},{},yeabuddy['bar']);";
expect(cleanedCode).toBe(standardJavaScript);
});
@@ -337,8 +361,8 @@ describe('amdclean specs', function() {
it('should convert object return values to a global object', function() {
var AMDcode = "define('third', { exampleProp: 'This is an example' });",
- cleanedCode = amdclean.clean({ globalObject: true, code: AMDcode, escodegen: { format: { compact: true } } }),
- standardJavaScript = "amdclean['third']={exampleProp:'This is an example'};";
+ cleanedCode = amdclean.clean({ globalObject: true, rememberGlobalObject: false, code: AMDcode, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var amdclean={};amdclean['third']={exampleProp:'This is an example'};";
expect(cleanedCode).toBe(standardJavaScript);
});
@@ -355,6 +379,14 @@ describe('amdclean specs', function() {
expect(cleanedCode).toBe(standardJavaScript);
});
+ it('should convert CommonJS require() calls correctly with the globalObject option', function() {
+ var AMDcode = "var example = require('anotherModule');",
+ cleanedCode = amdclean.clean({ code: AMDcode, globalObject: true, rememberGlobalObject: false, escodegen: { format: { compact: true } } }),
+ standardJavaScript = "var amdclean={};var example=amdclean['anotherModule'];";
+
+ expect(cleanedCode).toBe(standardJavaScript);
+ });
+
it('should convert CommonJS require() calls with file paths', function() {
var AMDcode = "var example = require('./anotherModule');",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),