Skip to content

Commit 6747fc2

Browse files
committed
Releasing v0.2.2
1 parent ff5d60e commit 6747fc2

File tree

3 files changed

+240
-26
lines changed

3 files changed

+240
-26
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ It is best used for libraries or apps that use AMD and:
3535
* include `path` alias names for each module using the `require.config()` method.
3636
* do not use AMD loader plugins (e.g. text! plugin)
3737
* only have **one** require.config() call
38-
* do not use the `cjsTranslate` Require.js configuration
3938

4039

4140
##What is Supported

src/amdclean.js

Lines changed: 200 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
'fix': 'Fix: ' + 'Make sure that you assign unique module paths using the require.config() method. Take a look at http://requirejs.org/docs/api.html#config for more details\n',
5050
'exiting': 'Result: Did not complete and exiting...'
5151
},
52+
// Malformed module name
53+
malformedModuleName: function(moduleName) {
54+
return 'This module name is malformed: ' + moduleName;
55+
},
56+
// CommonJS converting issues
57+
'commonjs': 'There was an error parsing a CommonJS require include. Please create a ticket at https://github.com/gfranko/amdclean/issues',
5258
// The user has not supplied the cliean method with any code
5359
'emptyCode': 'There is no code to generate the AST with',
5460
// An AST has not been correctly returned by Esprima
@@ -92,11 +98,54 @@
9298
isRequire: function(node) {
9399
var expression = node.expression || {},
94100
callee = expression.callee;
95-
return node.type === 'ExpressionStatement' &&
101+
return (node.type === 'ExpressionStatement' &&
96102
!_.isUndefined(expression) &&
97103
expression.type === 'CallExpression' &&
98104
callee.type === 'Identifier' &&
99-
callee.name === 'require';
105+
callee.name === 'require');
106+
},
107+
// isCommonJS
108+
// ----------
109+
// Returns if the current AST node is a commonJS require() method call
110+
// e.g. require('someModule');
111+
isCommonJS: function(node) {
112+
if(!node) return false;
113+
var callee = node.callee,
114+
obj = node.object;
115+
return (publicAPI.isRequireExpression || publicAPI.isRequireMemberExpression(node) || isRequireCallExpression(node));
116+
},
117+
isRequireExpression: function(node) {
118+
return (node.type === 'VariableDeclarator' &&
119+
!_.isUndefined(node.init) &&
120+
!_.isUndefined(node.init.type) &&
121+
node.init.type === 'CallExpression' &&
122+
!_.isUndefined(node.init.callee) &&
123+
node.init.callee.name === 'require');
124+
},
125+
isRequireMemberExpression: function(node) {
126+
return (node.type === 'VariableDeclarator' &&
127+
!_.isUndefined(node.init) &&
128+
!_.isUndefined(node.init.type) &&
129+
node.init.type === 'MemberExpression' &&
130+
!_.isUndefined(node.init.object) &&
131+
!_.isUndefined(node.init.object.callee) &&
132+
node.init.object.callee.name === 'require');
133+
},
134+
isRequireCallExpression: function(node) {
135+
return (node.type === 'VariableDeclarator' &&
136+
!_.isUndefined(node.init) &&
137+
!_.isUndefined(node.init.type) &&
138+
node.init.type === 'CallExpression' &&
139+
!_.isUndefined(node.init.callee) &&
140+
node.init.callee.type === 'MemberExpression' &&
141+
!_.isUndefined(node.init.callee.object) &&
142+
!_.isUndefined(node.init.callee.object.type) &&
143+
node.init.callee.object.type === 'CallExpression' &&
144+
!_.isUndefined(node.init.callee.object['arguments']) &&
145+
!_.isUndefined(node.init.callee.object.callee) &&
146+
node.init.callee.object.callee.name === 'require' &&
147+
!_.isUndefined(node.init.callee.property) &&
148+
!_.isUndefined(node.init.callee.property.name));
100149
},
101150
// isObjectExpression
102151
// ------------------
@@ -122,9 +171,15 @@
122171
containsRelativePath = name.lastIndexOf('/') !== -1;
123172
if(containsRelativePath) {
124173
moduleName = moduleName.substring(0, lastIndex);
125-
folderName = moduleName.substring((moduleName.lastIndexOf('/') + 1), moduleName.length);
126-
fileName = name.substring((lastIndex + 1), name.length);
127-
return folderName + '_' + fileName;
174+
folderName = (moduleName.substring((moduleName.lastIndexOf('/') + 1), moduleName.length)).replace(/\W/g, '');
175+
fileName = (name.substring((lastIndex + 1), name.length)).replace(/\W/g, '');
176+
if(folderName && fileName) {
177+
return folderName + '_' + fileName;
178+
} else if(!folderName && fileName) {
179+
return fileName;
180+
} else {
181+
throw new Error(publicAPI.errorMsgs.malformedModuleName(name));
182+
}
128183
} else {
129184
return name;
130185
}
@@ -150,10 +205,107 @@
150205
return true;
151206
}
152207
},
208+
// convertCommonJSDeclaration
209+
// --------------------------
210+
// Replaces the CommonJS variable declaration with a variable the same name as the argument
211+
// e.g. var prop = require('example'); -> var prop = example;
212+
convertCommonJSDeclaration: function(node) {
213+
if(!node) return node;
214+
try {
215+
if(publicAPI.isRequireExpression(node)) {
216+
return {
217+
'type': 'VariableDeclarator',
218+
'id': {
219+
'type': 'Identifier',
220+
'name': node.id.name
221+
},
222+
'init': {
223+
'type': 'Identifier',
224+
'name': publicAPI.normalizeModuleName((node.init['arguments'][0].value) || (node.init['arguments'][0].elements[0].value))
225+
}
226+
};
227+
} else if(publicAPI.isRequireMemberExpression(node)) {
228+
return {
229+
'type': 'VariableDeclarator',
230+
'id': {
231+
'type': 'Identifier',
232+
'name': node.id.name
233+
},
234+
'init': {
235+
'type': 'MemberExpression',
236+
'computed': false,
237+
'object': {
238+
'type': 'Identifier',
239+
'name': (function() {
240+
if(node.init && node.init.object && node.init.object['arguments'] && node.init.object['arguments'][0] && node.init.object['arguments'][0].elements) {
241+
return publicAPI.normalizeModuleName(node.init.object['arguments'][0].elements[0].value);
242+
} else {
243+
return publicAPI.normalizeModuleName(node.init.object['arguments'][0].value);
244+
}
245+
}())
246+
},
247+
'property': {
248+
'type': 'Identifier',
249+
'name': node.init.property.name
250+
}
251+
}
252+
};
253+
} else if(publicAPI.isRequireCallExpression(node)) {
254+
return {
255+
'type': 'VariableDeclarator',
256+
'id': {
257+
'type': 'Identifier',
258+
'name': node.id.name
259+
},
260+
'init': {
261+
'type': 'CallExpression',
262+
'callee': {
263+
'type': 'MemberExpression',
264+
'computed': false,
265+
'object': {
266+
'type': 'Identifier',
267+
'name': (function() {
268+
if(node.init && node.init.callee && node.init.callee.object && node.init.callee.object['arguments'] && node.init.callee.object['arguments'][0] && node.init.callee.object['arguments'][0].elements) {
269+
return publicAPI.normalizeModuleName(node.init.callee.object['arguments'][0].elements[0].value);
270+
} else {
271+
return publicAPI.normalizeModuleName(node.init.callee.object['arguments'][0].value);
272+
}
273+
}())
274+
},
275+
'property': {
276+
'type': 'Identifier',
277+
'name': node.init.callee.property.name
278+
}
279+
},
280+
'arguments': node.init['arguments']
281+
}
282+
};
283+
} else {
284+
return node;
285+
}
286+
} catch(e) {
287+
console.log(publicAPI.errorMsgs.commonjs + '\n\n' + e);
288+
return node;
289+
}
290+
291+
},
292+
// returnExpressionIdentifier
293+
// --------------------------
294+
// Returns a single identifier
295+
// e.g. module
296+
returnExpressionIdentifier: function(name) {
297+
return {
298+
'type': 'ExpressionStatement',
299+
'expression': {
300+
'type': 'Identifier',
301+
'name': name
302+
}
303+
};
304+
},
153305
// convertToObjectDeclaration
154306
// --------------------------
155307
// Returns an object variable declaration
156-
// ( e.g. var example = { exampleProp: true } )
308+
// e.g. var example = { exampleProp: true }
157309
convertToObjectDeclaration: function(obj) {
158310
var node = obj.node,
159311
moduleName = obj.moduleName,
@@ -176,7 +328,7 @@
176328
// convertToIIFE
177329
// -------------
178330
// Returns an IIFE
179-
// ( e.g. (function() { }()) )
331+
// e.g. (function() { }())
180332
convertToIIFE: function(obj) {
181333
var callbackFuncParams = obj.callbackFuncParams,
182334
callbackFunc = obj.callbackFunc,
@@ -202,7 +354,7 @@
202354
// convertToIIFEDeclaration
203355
// ------------------------
204356
// Returns a function expression that is executed immediately
205-
// ( e.g. var example = function(){}() )
357+
// e.g. var example = function(){}()
206358
convertToIIFEDeclaration: function(obj) {
207359
var moduleName = obj.moduleName,
208360
callbackFuncParams = obj.callbackFuncParams,
@@ -248,22 +400,31 @@
248400
isRequire = obj.isRequire,
249401
node = obj.node,
250402
moduleName = obj.moduleName,
403+
dependencies = obj.dependencies,
404+
depLength = dependencies.length,
405+
dependencyNames = (function() {
406+
var deps = [],
407+
iterator = -1;
408+
while(++iterator < depLength) {
409+
deps.push({ type: 'Identifier', name: publicAPI.normalizeModuleName(dependencies[iterator]) });
410+
}
411+
return deps;
412+
}()),
251413
callbackFunc = obj.moduleReturnValue,
252414
callbackFuncParams = (function() {
253415
var deps = [],
416+
iterator = -1,
417+
currentParam,
254418
cbParams = callbackFunc.params || [];
255-
_.each(cbParams, function(currentParam) {
256-
deps.push({ 'type': 'Identifier', 'name': currentParam.name });
257-
});
419+
while(++iterator < depLength) {
420+
currentParam = cbParams[iterator];
421+
if(currentParam) {
422+
deps.push({ 'type': 'Identifier', 'name': currentParam.name });
423+
} else {
424+
deps.push({ 'type': 'Identifier', 'name': dependencyNames[iterator].name });
425+
}
426+
}
258427
return deps;
259-
}()),
260-
dependencies = obj.dependencies,
261-
dependencyNames = (function() {
262-
var arr = [], names = dependencies;
263-
_.each(callbackFuncParams, function(currentCallbackFuncParam, iterator) {
264-
arr.push({ type: 'Identifier', name: publicAPI.normalizeModuleName(names[iterator]) });
265-
});
266-
return arr;
267428
}());
268429
if(isDefine) {
269430
return publicAPI.convertToIIFEDeclaration({
@@ -324,7 +485,7 @@
324485
return publicAPI.convertToFunctionExpression(params);
325486
} else {
326487
// Remove the require include statement from the source
327-
return { type: 'EmptyStatement', expression: {} };
488+
return { type: 'EmptyStatement' };
328489
}
329490
}
330491
} else {
@@ -401,11 +562,26 @@
401562
ast = publicAPI.traverseAndUpdateAst({
402563
ast: publicAPI.createAst(code)
403564
});
404-
// Removes all empty statements from the source so that there are no single semicolons
565+
// Removes all empty statements from the source so that there are no single semicolons and
566+
// Make sure that all require() CommonJS calls are converted
405567
if(ast && _.isArray(ast.body)) {
406-
_.each(ast.body, function(currentNode, iterator) {
407-
if(currentNode === undefined || currentNode.type === 'EmptyStatement') {
408-
ast.body.splice(iterator, 1);
568+
estraverse.replace(ast, {
569+
enter: function(node, parent) {
570+
if(node === undefined || node.type === 'EmptyStatement') {
571+
_.each(parent.body, function(currentNode, iterator) {
572+
if(currentNode === undefined || currentNode.type === 'EmptyStatement') {
573+
parent.body.splice(iterator, 1);
574+
}
575+
});
576+
} else if(node.type === 'VariableDeclaration' && Array.isArray(node.declarations)) {
577+
_.each(node.declarations, function(currentDeclaration, iterator) {
578+
if(publicAPI.isCommonJS(currentDeclaration)) {
579+
node.declarations[iterator] = publicAPI.convertCommonJSDeclaration(currentDeclaration);
580+
}
581+
});
582+
return node;
583+
}
584+
409585
}
410586
});
411587
}

test/specs/convert.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,45 @@ describe('amdclean specs', function() {
3939

4040
});
4141

42+
describe('CommonJS Variable Declarations', function() {
43+
44+
it('should convert CommonJS require() calls', function() {
45+
var AMDcode = "var example = require('anotherModule');",
46+
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
47+
standardJavaScript = "var example=anotherModule;";
48+
expect(cleanedCode).toBe(standardJavaScript);
49+
});
50+
51+
it('should convert CommonJS require() calls with file paths', function() {
52+
var AMDcode = "var example = require('./anotherModule');",
53+
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
54+
standardJavaScript = "var example=anotherModule;";
55+
expect(cleanedCode).toBe(standardJavaScript);
56+
});
57+
58+
it('should convert CommonJS require() calls with advanced file paths', function() {
59+
var AMDcode = "var example = require('./../anotherModule');",
60+
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
61+
standardJavaScript = "var example=anotherModule;";
62+
expect(cleanedCode).toBe(standardJavaScript);
63+
});
64+
65+
it('should convert CommonJS require() calls with single properties', function() {
66+
var AMDcode = "var example = require('./anotherModule').prop;",
67+
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
68+
standardJavaScript = "var example=anotherModule.prop;";
69+
expect(cleanedCode).toBe(standardJavaScript);
70+
});
71+
72+
it('should convert CommonJS require() calls with method calls', function() {
73+
var AMDcode = "var example = require('./anotherModule').prop();",
74+
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
75+
standardJavaScript = "var example=anotherModule.prop();";
76+
expect(cleanedCode).toBe(standardJavaScript);
77+
});
78+
79+
});
80+
4281
});
4382

4483
describe('require() method conversions', function() {
@@ -66,7 +105,7 @@ describe('amdclean specs', function() {
66105
expect(cleanedCode).toBe(standardJavaScript);
67106
});
68107

69-
it('remove require() calls with no callback functions', function() {
108+
it('should remove require() calls with no callback functions', function() {
70109
var AMDcode = "require(['anotherModule']);",
71110
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
72111
standardJavaScript = "";

0 commit comments

Comments
 (0)