Skip to content

Commit

Permalink
Re: #24 - Added removeUseStricts option and optimized empty factory f…
Browse files Browse the repository at this point in the history
…unctions to make sure they default to undefined
  • Loading branch information
gfranko committed Feb 9, 2014
1 parent 4c767f2 commit bc694bc
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 15 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ amdclean.clean({
ignoreModules: [],
// Determines if all of the require() method calls will be removed
removeAllRequires: false,
// Determines if all of the 'use strict' statements will be removed
removeUseStricts: true,
// Allows you to pass an expression that will override shimmed modules return values
// e.g. { 'backbone': 'window.Backbone' }
shimOverrides: {},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "amdclean",
"version": "1.0.0",
"version": "1.1.0",
"description": "A build tool that converts AMD code to standard JavaScript",
"main": "./src/amdclean",
"repository": {
Expand Down
33 changes: 27 additions & 6 deletions src/amdclean.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! amdclean - v1.0.0 - 2014-02-09
/*! amdclean - v1.1.0 - 2014-02-09
* http://gregfranko.com/amdclean
* Copyright (c) 2014 Greg Franko; Licensed MIT*/

Expand Down Expand Up @@ -34,13 +34,14 @@
// The Public API object
publicAPI = {
// Current project version number
'VERSION': '1.0.0',
'VERSION': '1.1.0',
// Default Options
'defaultOptions': {
'globalObject': false,
'globalObjectName': 'amdclean',
'rememberGlobalObject': true,
'removeAllRequires': false,
'removeUseStricts': true,
'ignoreModules': [],
'escodegen': {
'comment': true
Expand Down Expand Up @@ -153,6 +154,16 @@
_.isPlainObject(expression.callee) &&
expression.callee.type === 'FunctionExpression');
},
// isUseStrict
// -----------
// Returns if the current AST node is a 'use strict' expression
// e.g. 'use strict'
'isUseStrict': function(expression) {
return (expression &&
_.isPlainObject(expression) &&
expression.type === 'Literal' &&
expression.value === 'use strict');
},
// isAMDConditional
// ----------------
// Returns if the current AST node is an if statement AMD check
Expand Down Expand Up @@ -353,7 +364,7 @@
isOptimized = obj.isOptimized,
callbackFunc = (function() {
var cbFunc = obj.callbackFunc;
if(cbFunc.type === 'Identifier') {
if(cbFunc.type === 'Identifier' && cbFunc.name !== 'undefined') {
cbFunc = {
'type': 'FunctionExpression',
'id': null,
Expand Down Expand Up @@ -383,7 +394,7 @@
dependencyNames = obj.dependencyNames,
options = publicAPI.options,
cb = (function() {
if(callbackFunc.type === 'Literal' || isOptimized === true) {
if(callbackFunc.type === 'Literal' || (callbackFunc.type === 'Identifier' && callbackFunc.name === 'undefined') || isOptimized === true) {
return callbackFunc;
} else {
return {
Expand Down Expand Up @@ -498,9 +509,13 @@
returnStatementArg;
// If the module has NO dependencies and the callback function is not empty
if(!depLength && callbackFunc && callbackFunc.type === 'FunctionExpression' && callbackFunc.body && _.isArray(callbackFunc.body.body) && callbackFunc.body.body.length) {
body = callbackFunc.body.body;
// Filter 'use strict' statements
body = _.filter(callbackFunc.body.body, function(node) {
if(publicAPI.options.removeUseStricts === true) return !publicAPI.isUseStrict(node.expression);
else return node;
});
// Returns an array of all return statements
returnStatements = _.where(callbackFunc.body.body, { 'type': 'ReturnStatement' });
returnStatements = _.where(body, { 'type': 'ReturnStatement' });
// If there is a return statement
if(returnStatements.length) {
firstReturnStatement = returnStatements[0];
Expand All @@ -519,6 +534,12 @@
}
}
}
} else if(callbackFunc && callbackFunc.type === 'FunctionExpression' && callbackFunc.body && _.isArray(callbackFunc.body.body) && callbackFunc.body.body.length === 0) {
callbackFunc = {
'type': 'Identifier',
'name': 'undefined'
};
depLength = 0;
}
return callbackFunc;
}()),
Expand Down
44 changes: 36 additions & 8 deletions test/specs/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,34 @@ describe('amdclean specs', function() {
it('should convert function return values to immediately invoked function declarations', function() {
var AMDcode = "define('example', [], function() {});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var example=function (){}();";
standardJavaScript = "var example=undefined;";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should passing a file path instead of the code directly', function() {
var cleanedCode = amdclean.clean({ filePath: __dirname + '/../filePathTest.js', escodegen: { format: { compact: true } } }),
standardJavaScript = "var example=function (){}();";
standardJavaScript = "var example=undefined;";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should correctly set callback parameters to the callback function', function() {
var AMDcode = "define('example', ['example1', 'example2'], function(one, two) {});",
var AMDcode = "define('example', ['example1', 'example2'], function(one, two) {var test = true;});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var example=function (one,two){}(example1,example2);";
standardJavaScript = "var example=function (one,two){var test=true;}(example1,example2);";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should correctly normalize relative file paths', function() {
var AMDcode = "define('./modules/example', ['example1', 'example2'], function(one, two) {});",
var AMDcode = "define('./modules/example', ['example1', 'example2'], function(one, two) {var test = true;});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var modules_example=function (one,two){}(example1,example2);";
standardJavaScript = "var modules_example=function (one,two){var test=true;}(example1,example2);";
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 AMDcode = "define('./foo/prototype/commonMethodName.js', ['example1', 'example2'], function(one, two) { var test = true;});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var foo_prototype_commonMethodNamejs=function (one,two){}(example1,example2);";
standardJavaScript = "var foo_prototype_commonMethodNamejs=function (one,two){var test=true;}(example1,example2);";
expect(cleanedCode).toBe(standardJavaScript);
});

Expand Down Expand Up @@ -155,13 +155,41 @@ describe('amdclean specs', function() {
expect(cleanedCode).toBe(standardJavaScript);
});

it('should optimize basic define() methods that have an empty factory function', function() {
var AMDcode = "define('optimized', function () {});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var optimized=undefined;";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should optimize more complex define() methods that return a function expression', function() {
var AMDcode = "define('optimized', function () { return function ( thing ) { var anotherThing = true; return !isNaN( parseFloat( thing ) ) && isFinite( thing );};});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var optimized=function(thing){var anotherThing=true;return!isNaN(parseFloat(thing))&&isFinite(thing);};";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should optimize more complex define() methods that have a "use strict" statement and return a function expression', function() {
var AMDcode = "define('optimized', function () { 'use strict'; return function ( thing ) { return !isNaN( parseFloat( thing ) ) && isFinite( thing );};});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var optimized=function(thing){return!isNaN(parseFloat(thing))&&isFinite(thing);};";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should not optimize more complex define() methods that have a "use strict" statement and return a function expression, but have also set the removeUseStricts option to false', function() {
var AMDcode = "define('optimized', function () { 'use strict'; return function ( thing ) { return !isNaN( parseFloat( thing ) ) && isFinite( thing );};});",
cleanedCode = amdclean.clean({ removeUseStricts: false, code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var optimized=function (){'use strict';return function(thing){return!isNaN(parseFloat(thing))&&isFinite(thing);};}();";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should not optimize define() methods that have logic outside of the return statement', function() {
var AMDcode = "define('optimized', [], function () { var test = true; return function ( thing ) { var anotherThing = true; return !isNaN( parseFloat( thing ) ) && isFinite( thing );};});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
standardJavaScript = "var optimized=function (){var test=true;return function(thing){var anotherThing=true;return!isNaN(parseFloat(thing))&&isFinite(thing);};}();";
expect(cleanedCode).toBe(standardJavaScript);
});

it('should not optimize define() methods that have one or more dependencies', function() {
var AMDcode = "define('optimized', ['exampleDependency'], function () { return function ( thing ) { var anotherThing = true; return !isNaN( parseFloat( thing ) ) && isFinite( thing );};});",
cleanedCode = amdclean.clean({ code: AMDcode, escodegen: { format: { compact: true } } }),
Expand Down

0 comments on commit bc694bc

Please sign in to comment.