Skip to content

Commit f749dcd

Browse files
committed
Releasing AMDclean 2.2.0
1 parent 7bfae1e commit f749dcd

12 files changed

+417
-195
lines changed

build/amdclean.js

+105-50
Large diffs are not rendered by default.

build/amdclean.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "amdclean",
3-
"version": "2.1.1",
3+
"version": "2.2.0",
44
"description": "A build tool that converts AMD code to standard JavaScript",
55
"main": "./src/amdclean",
66
"repository": {

src/amdclean.js

+105-50
Large diffs are not rendered by default.

src/modules/convertDefinesAndRequires.js

+47-42
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ define([
3838
defaultLOC = defaultValues.defaultLOC,
3939
range = node.range || defaultRange,
4040
loc = node.loc || defaultLOC,
41-
dependencyBlacklist = defaultValues.dependencyBlacklist;
41+
dependencyBlacklist = defaultValues.dependencyBlacklist,
42+
shouldOptimize;
4243

4344
startLineNumber = isDefine || isRequire ? node.expression.loc.start.line : node && node.loc && node.loc.start ? node.loc.start.line : null;
4445

@@ -48,6 +49,29 @@ define([
4849
// e.g. if(typeof define === 'function') {}
4950
if(utils.isAMDConditional(node)) {
5051

52+
estraverse.traverse(node, {
53+
'enter': function(node) {
54+
var normalizedModuleName;
55+
if(utils.isDefine(node)) {
56+
if(node.expression && node.expression.arguments && node.expression.arguments.length) {
57+
// Add the module name to the ignore list
58+
if(node.expression.arguments[0].type === 'Literal' && node.expression.arguments[0].value) {
59+
normalizedModuleName = normalizeModuleName.call(amdclean, node.expression.arguments[0].value);
60+
if(options.transformAMDChecks !== true) {
61+
amdclean.conditionalModulesToIgnore[normalizedModuleName] = true;
62+
} else {
63+
amdclean.conditionalModulesToNotOptimize[normalizedModuleName] = true;
64+
}
65+
if(options.createAnonymousAMDModule === true) {
66+
amdclean.storedModules[normalizedModuleName] = false;
67+
node.expression.arguments.shift();
68+
}
69+
}
70+
}
71+
}
72+
}
73+
});
74+
5175
// If the AMD conditional statement should be transformed and not ignored
5276
if(!shouldBeIgnored && options.transformAMDChecks === true) {
5377

@@ -64,30 +88,19 @@ define([
6488
return node;
6589
}
6690

67-
// If the AMD conditional statement should not be transformed
68-
if(options.transformAMDChecks === false) {
69-
estraverse.traverse(node, {
70-
'enter': function(node) {
71-
if(utils.isDefine(node)) {
72-
if(node.expression && node.expression.arguments && node.expression.arguments.length) {
73-
// Add the module name to the ignore list
74-
if(node.expression.arguments[0].type === 'Literal' && node.expression.arguments[0].value) {
75-
amdclean.conditionalModulesToIgnore[node.expression.arguments[0].value] = true;
76-
if(options.createAnonymousAMDModule === true) {
77-
amdclean.storedModules[node.expression.arguments[0].value] = false;
78-
node.expression.arguments.shift();
79-
}
80-
}
81-
}
82-
}
83-
}
84-
});
85-
}
8691
}
8792

8893
if(isDefine || isRequire) {
8994
args = Array.prototype.slice.call(node.expression['arguments'], 0);
9095

96+
moduleReturnValue = isRequire ? args[1] : args[args.length - 1];
97+
98+
moduleId = node.expression['arguments'][0].value;
99+
100+
moduleName = normalizeModuleName.call(amdclean, moduleId);
101+
102+
shouldOptimize = !amdclean.conditionalModulesToNotOptimize[moduleName];
103+
91104
dependencies = (function() {
92105
var deps = isRequire ? args[0] : args[args.length - 2],
93106
depNames = [],
@@ -106,9 +119,9 @@ define([
106119
if(_.isArray(deps) && deps.length) {
107120

108121
_.each(deps, function(currentDependency) {
109-
110-
if(dependencyBlacklist[currentDependency.value] !== 'remove') {
111-
122+
if(dependencyBlacklist[currentDependency.value] && !shouldOptimize) {
123+
depNames.push(currentDependency.value);
124+
} else if(dependencyBlacklist[currentDependency.value] !== 'remove') {
112125
if(dependencyBlacklist[currentDependency.value]) {
113126
depNames.push('{}');
114127
} else {
@@ -124,22 +137,17 @@ define([
124137
return depNames;
125138
}());
126139

127-
moduleReturnValue = isRequire ? args[1] : args[args.length - 1];
128-
129-
moduleId = node.expression['arguments'][0].value;
130-
131-
moduleName = normalizeModuleName.call(amdclean, moduleId);
132-
133140
params = {
134-
'node': node,
135-
'moduleName': moduleName,
136-
'moduleId': moduleId,
137-
'dependencies': dependencies,
138-
'moduleReturnValue': moduleReturnValue,
139-
'isDefine': isDefine,
140-
'isRequire': isRequire,
141-
'range': range,
142-
'loc': loc
141+
'node': node,
142+
'moduleName': moduleName,
143+
'moduleId': moduleId,
144+
'dependencies': dependencies,
145+
'moduleReturnValue': moduleReturnValue,
146+
'isDefine': isDefine,
147+
'isRequire': isRequire,
148+
'range': range,
149+
'loc': loc,
150+
'shouldOptimize': shouldOptimize
143151
};
144152

145153
if(isDefine) {
@@ -215,10 +223,7 @@ define([
215223
_.isObject(node.body) &&
216224
_.isArray(node.body.body) &&
217225
!_.where(node.body.body, {
218-
'type': 'ReturnStatement',
219-
'argument': {
220-
'type': 'Identifier'
221-
}
226+
'type': 'ReturnStatement'
222227
}).length) {
223228

224229
parentHasFunctionExpressionArgument = (function () {

src/modules/convertToFunctionExpression.js

+40-13
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ define([
88
'convertToIIFE',
99
'convertToIIFEDeclaration',
1010
'defaultValues',
11-
'normalizeModuleName'
11+
'normalizeModuleName',
12+
'defaultValues'
1213
], function(
1314
utils,
1415
convertToIIFE,
1516
convertToIIFEDeclaration,
1617
defaultValues,
17-
normalizeModuleName
18+
normalizeModuleName,
19+
defaultValues
1820
) {
1921
return function convertToFunctionExpression(obj) {
2022
var amdclean = this,
@@ -35,6 +37,9 @@ define([
3537
defaultLOC = defaultValues.defaultLOC,
3638
range = obj.range || defaultRange,
3739
loc = obj.loc || defaultLOC,
40+
shouldOptimize = obj.shouldOptimize,
41+
dependencyBlacklist = defaultValues.dependencyBlacklist,
42+
hasNonMatchingParameter = false,
3843
callbackFunc = (function() {
3944
var callbackFunc = obj.moduleReturnValue,
4045
body,
@@ -85,10 +90,21 @@ define([
8590
firstReturnStatement = returnStatements[0];
8691
returnStatementArg = firstReturnStatement.argument;
8792

93+
hasNonMatchingParameter = function () {
94+
var nonMatchingParameter = false;
95+
_.each(callbackFunc.params, function (currentParam) {
96+
var currentParamName = currentParam.name;
97+
if(!amdclean.storedModules[currentParamName] && !dependencyBlacklist[currentParamName]) {
98+
nonMatchingParameter = true;
99+
}
100+
});
101+
return nonMatchingParameter;
102+
}();
103+
88104
// If something other than a function expression is getting returned
89105
// and there is more than one AST child node in the factory function
90106
// return early
91-
if((!utils.isFunctionExpression(firstReturnStatement) && body.length > 1) || (returnStatementArg && returnStatementArg.type === 'Identifier')) {
107+
if(hasNonMatchingParameter || !shouldOptimize || (!utils.isFunctionExpression(firstReturnStatement) && body.length > 1) || (returnStatementArg && returnStatementArg.type === 'Identifier')) {
92108
return callbackFunc;
93109
} else {
94110
// Optimize the AMD module by setting the callback function to the return statement argument
@@ -225,7 +241,7 @@ define([
225241
callbackFuncParams = (function() {
226242
var deps = [],
227243
currentName,
228-
cbParams = _.union((callbackFunc.params || dependencyNames || []), matchingRequireExpressionParams),
244+
cbParams = _.union((callbackFunc.params && callbackFunc.params.length ? callbackFunc.params : !shouldOptimize && dependencyNames && dependencyNames.length ? dependencyNames : []), matchingRequireExpressionParams),
229245
mappedParameter = {};
230246

231247
_.each(cbParams, function(currentParam, iterator) {
@@ -234,7 +250,15 @@ define([
234250
} else {
235251
currentName = dependencyNames[iterator].name;
236252
}
237-
if(currentName !== '{}' && (!hasExportsParam || defaultValues.dependencyBlacklist[currentName] !== 'remove')) {
253+
254+
if(!shouldOptimize && currentName !== '{}') {
255+
deps.push({
256+
'type': 'Identifier',
257+
'name': currentName,
258+
'range': defaultRange,
259+
'loc': defaultLOC
260+
});
261+
} else if(currentName !== '{}' && (!hasExportsParam || defaultValues.dependencyBlacklist[currentName] !== 'remove')) {
238262
deps.push({
239263
'type': 'Identifier',
240264
'name': currentName,
@@ -276,7 +300,7 @@ define([
276300

277301
// Only return callback function parameters that do not directly match the name of existing stored modules
278302
return _.filter(deps || [], function(currentParam) {
279-
return aggressiveOptimizations === true ? !amdclean.storedModules[currentParam.name] : true;
303+
return aggressiveOptimizations === true && shouldOptimize ? !amdclean.storedModules[currentParam.name] : true;
280304
});
281305
}()),
282306
isCommonJS = !hasReturnStatement && hasExportsParam,
@@ -291,19 +315,22 @@ define([
291315

292316
// If the matching callback parameter matches the name of a stored module, then do not return it
293317
// Else if the matching callback parameter does not match the name of a stored module, return the dependency
294-
return aggressiveOptimizations === true ? (!mappedCallbackParameter || amdclean.storedModules[mappedCallbackParameter.name] && mappedCallbackParameter.name === currentDepName ? !amdclean.storedModules[currentDepName] : !amdclean.storedModules[mappedCallbackParameter.name]) : true;
318+
return aggressiveOptimizations === true && shouldOptimize ? (!mappedCallbackParameter || amdclean.storedModules[mappedCallbackParameter.name] && mappedCallbackParameter.name === currentDepName ? !amdclean.storedModules[currentDepName] : !amdclean.storedModules[mappedCallbackParameter.name]) : true;
319+
});
320+
321+
dependencyNames = _.map(dependencyNames || [], function(currentDep, iterator) {
322+
if(dependencyBlacklist[currentDep.name]) {
323+
currentDep.name = '{}';
324+
}
325+
return currentDep;
295326
});
296327

297328
dependencyNameLength = dependencyNames.length;
298329
callbackFuncParamsLength = callbackFuncParams.length;
299330

300331
// If the module dependencies passed into the current module are greater than the used callback function parameters, do not pass the dependencies
301-
if(dependencyNameLength && dependencyNameLength > callbackFuncParamsLength) {
302-
if(dependencyNameLength - callbackFuncParamsLength < 2) {
303-
dependencyNames.splice((dependencyNameLength - (callbackFuncParamsLength || 1)), callbackFuncParamsLength || 1);
304-
} else {
305-
dependencyNames.splice(callbackFuncParamsLength || 1, dependencyNameLength - (callbackFuncParamsLength || 1));
306-
}
332+
if (dependencyNameLength > callbackFuncParamsLength) {
333+
dependencyNames.splice(callbackFuncParamsLength, dependencyNameLength - callbackFuncParamsLength);
307334
}
308335

309336
// If it is a CommonJS module and there is an exports assignment, make sure to return the exports object

src/modules/findAndStoreAllModuleIds.js

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ define([
2828
if(moduleName && !amdclean.storedModules[moduleName]) {
2929
amdclean.storedModules[moduleName] = true;
3030
}
31+
32+
// If it is a return statement that returns a define() method call, strip the return statement
33+
if(node.type === 'ReturnStatement' && node.argument && node.argument.callee && node.argument.callee.name === 'define') {
34+
node.type = 'ExpressionStatement';
35+
node.expression = node.argument;
36+
delete node.argument;
37+
}
38+
39+
if(node.type === 'VariableDeclarator') {
40+
amdclean.variablesStore[node.id.name] = true;
41+
}
3142
}
3243
});
3344
};

src/modules/index.js

+15
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ require([
7171
// An object that will store all of the user module names
7272
this.storedModules = {};
7373

74+
// variablesStore
75+
// --------------
76+
// An object that will store all of the local variables that are declared
77+
this.variablesStore = {};
78+
79+
// originalAst
80+
// -----------
81+
// The original AST (Abstract Syntax Tree) before it is transformed
82+
this.originalAst = {};
83+
7484
// callbackParameterMap
7585
// --------------------
7686
// An object that will store all of the user module callback parameters (that are used and also do not match the exact name of the dependencies they are representing) and the dependencies that they map to
@@ -81,6 +91,11 @@ require([
8191
// An object that will store any modules that should be ignored (not cleaned)
8292
this.conditionalModulesToIgnore = {};
8393

94+
// conditionalModulesToNotOptimize
95+
// -------------------------------
96+
// An object that will store any modules that should not be optimized (but still cleaned)
97+
this.conditionalModulesToNotOptimize = {};
98+
8499
// matchingCommentLineNumbers
85100
// --------------------------
86101
// An object that stores any comments that match the commentCleanName option

src/modules/normalizeModuleName.js

+40-28
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,50 @@ define([
1010
defaultValues
1111
) {
1212
return function normalizeModuleName(name, moduleId) {
13-
var amdclean = this,
14-
options = amdclean.options,
15-
prefixMode = options.prefixMode,
16-
prefixTransform = options.prefixTransform,
17-
dependencyBlacklist = defaultValues.dependencyBlacklist,
18-
prefixTransformValue,
19-
preNormalized,
20-
postNormalized;
21-
22-
name = name || '';
23-
24-
if(name === '{}') {
25-
if(dependencyBlacklist[name] === 'remove') {
26-
return '';
27-
} else {
28-
return name;
29-
}
30-
}
13+
var amdclean = this,
14+
options = amdclean.options,
15+
prefixMode = options.prefixMode,
16+
prefixTransform = options.prefixTransform,
17+
dependencyBlacklist = defaultValues.dependencyBlacklist,
18+
prefixTransformValue,
19+
preNormalized,
20+
postNormalized;
21+
22+
name = name || '';
3123

32-
preNormalized = utils.prefixReservedWords(name.replace(/\./g,'').
33-
replace(/[^A-Za-z0-9_$]/g,'_').
34-
replace(/^_+/,''));
24+
if(name === '{}') {
25+
if(dependencyBlacklist[name] === 'remove') {
26+
return '';
27+
} else {
28+
return name;
29+
}
30+
}
3531

36-
postNormalized = prefixMode === 'camelCase' ? utils.convertToCamelCase(preNormalized) : preNormalized;
32+
preNormalized = utils.prefixReservedWords(name.replace(/\./g,'').
33+
replace(/[^A-Za-z0-9_$]/g,'_').
34+
replace(/^_+/,''));
3735

38-
if(_.isFunction(prefixTransform)) {
39-
prefixTransformValue = prefixTransform(postNormalized, moduleId);
40-
if(_.isString(prefixTransformValue) && prefixTransformValue.length) {
41-
return prefixTransformValue;
36+
postNormalized = prefixMode === 'camelCase' ? utils.convertToCamelCase(preNormalized) : preNormalized;
37+
38+
if(options.ignoreModules.indexOf(postNormalized) === -1 && amdclean.variablesStore[postNormalized]) {
39+
amdclean.storedModules[postNormalized] = false;
40+
postNormalized = (function findValidName(currentName) {
41+
if(amdclean.variablesStore[currentName]) {
42+
return findValidName('_' + currentName + '_');
43+
} else {
44+
return currentName;
4245
}
43-
}
46+
}(postNormalized));
47+
amdclean.storedModules[postNormalized] = true;
48+
}
49+
50+
if(_.isFunction(prefixTransform)) {
51+
prefixTransformValue = prefixTransform(postNormalized, moduleId);
52+
if(_.isString(prefixTransformValue) && prefixTransformValue.length) {
53+
return prefixTransformValue;
54+
}
55+
}
4456

45-
return postNormalized;
57+
return postNormalized;
4658
};
4759
});

0 commit comments

Comments
 (0)