Skip to content

Commit d370891

Browse files
committed
Merge branch 'dev'
* dev: Last minute README typo fixes Officially releasing v0.7.0 Updated the README with a few more examples Made a few other updates Releasing v0.7.0 Re: #22 - Added optimization techniques Cleaned up createAst() code Re: #23 - Comments are no longer stripped by default
2 parents b00a146 + 148ffde commit d370891

File tree

5 files changed

+210
-50
lines changed

5 files changed

+210
-50
lines changed

README.md

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,11 @@ So, you get great code cleanliness with AMD, reduced file sizes, improved code r
3838

3939
## Restrictions
4040

41-
**Note:** Same restrictions as almond.js, plus a few more.
41+
**Note:** Same restrictions as almond.js.
4242

4343
It is best used for libraries or apps that use AMD and:
4444

4545
* optimize all the modules into one file -- no dynamic code loading.
46-
* do not use AMD loader plugins (e.g. text! plugin)
4746
* only have **one** require.config() call
4847

4948

@@ -55,9 +54,9 @@ It is best used for libraries or apps that use AMD and:
5554

5655
* [Simplified CJS wrapper](https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-cjs)
5756

58-
* Exporting global modules to the `window` object
57+
* Exporting global modules to the global `window` object
5958

60-
* Storing all local modules inside of a global object (Helps scoping issues for certain use cases)
59+
* Storing all local modules inside of a single global object (Helps scoping issues for certain use cases)
6160

6261
## Download
6362

@@ -229,6 +228,42 @@ var example = function () {
229228

230229
_AMD_
231230

231+
```javascript
232+
define('example', [], function() {
233+
return function(name) {
234+
return 'Hello ' + name;
235+
};
236+
});
237+
```
238+
239+
_Standard_
240+
241+
```javascript
242+
var example = function (name) {
243+
return 'Hello ' + name;
244+
};
245+
```
246+
247+
---
248+
249+
_AMD_
250+
251+
```javascript
252+
define('example', [], function() {
253+
return 'I love AMDClean';
254+
});
255+
```
256+
257+
_Standard_
258+
259+
```javascript
260+
var example = 'I love AMDClean';
261+
```
262+
263+
---
264+
265+
_AMD_
266+
232267
```javascript
233268
define('example', ['example1', 'example2'], function(one, two) {
234269

@@ -261,7 +296,7 @@ define("backbone", ["underscore","jquery"], (function (global) {
261296
_Standard_
262297

263298
```javascript
264-
var backbone=window.Backbone;
299+
var backbone = window.Backbone;
265300
```
266301

267302
---
@@ -325,7 +360,7 @@ _Standard_
325360

326361
##Options
327362

328-
The amdclean `clean()` method accepts a string or an object. Below is an example objects with all of the available configuration options:
363+
The amdclean `clean()` method accepts a string or an object. Below is an example object with all of the available configuration options:
329364

330365
```javascript
331366
amdclean.clean({
@@ -407,14 +442,24 @@ onModuleBundleComplete: function (data) {
407442

408443
__What if I don't want all define() and require() method calls to be removed?__
409444

410-
- If you don't want one or more define() and require() methods to be removed by `amdclean`, you have a few options. If the module has a named module id associated with it, then you can add the associated module id to the `ignoreModules` option array. If there is not an associated module id, then you must put a comment with only the words _amdclean_ on the same line or one line above the method in question. For example, `amdclean` would not remove the `define()` method below:
445+
- If you don't want one or more define() and require() methods to be removed by `amdclean`, you have a few options. If the module has a named module id associated with it, then you can add the associated module id to the `ignoreModules` option array. Like this:
446+
447+
```javascript
448+
var amdclean = require('amdclean');
449+
amdclean.clean({
450+
'code': 'define("randomExample", function() { console.log("I am a random example"); });',
451+
'ignoreModules': ['randomExample']
452+
});
453+
```
454+
455+
If there is not an associated module id, then you must put a comment with only the words _amdclean_ on the same line or one line above the method in question. For example, `amdclean` would not remove the `define()` method below:
411456

412457
```javascript
413458
// amdclean
414459
define('example', [], function() {});
415460
```
416461

417-
If you want to use different text than `amdclean`, you can customize the comment name by using the `ignoreModules` option.
462+
If you want to use different text than `amdclean`, you can customize the comment name by using the `commentCleanName` option.
418463

419464
__Why are define() method placeholder functions inserted into my source?__
420465

@@ -426,9 +471,9 @@ __How would I expose one or more modules as a global window property?__
426471

427472
__I am having a scope problem with all of the local module variables. What can I do?__
428473

429-
- You can use the `globalObject` option to store all of your modules in a global object that uses the top-most function scope.
474+
- You can use the `globalObject` option to store all of your modules in a single global object that uses the top-most function scope. You can even name that global object whatever you prefer by using the `globalObjectName` option.
430475

431476

432-
## Liense
477+
## License
433478

434479
Copyright (c) 2014 Greg Franko Licensed under the MIT license.

build/amdclean.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "amdclean",
3-
"version": "0.6.2",
3+
"version": "0.7.0",
44
"description": "A build tool that converts AMD code to standard JavaScript",
55
"main": "./src/amdclean",
66
"repository": {
@@ -32,7 +32,8 @@
3232
"gulp-uglify": "~0.1.0",
3333
"gulp-jshint": "~1.3.2",
3434
"gulp-jasmine": "~0.1.1",
35-
"gulp-rename": "~0.2.1"
35+
"gulp-rename": "~0.2.1",
36+
"jasmine-only": "~0.1.0"
3637
},
3738
"engine": {
3839
"node": ">= 0.8"

src/amdclean.js

Lines changed: 80 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! amdclean - v0.6.2 - 2014-01-26
1+
/*! amdclean - v0.7.0 - 2014-02-08
22
* http://gregfranko.com/amdclean
33
* Copyright (c) 2014 Greg Franko; Licensed MIT*/
44

@@ -34,18 +34,22 @@
3434
// The Public API object
3535
publicAPI = {
3636
// Current project version number
37-
'VERSION': '0.6.2',
37+
'VERSION': '0.7.0',
3838
// Default Options
3939
'defaultOptions': {
4040
'globalObject': false,
4141
'globalObjectName': 'amdclean',
4242
'rememberGlobalObject': true,
4343
'removeAllRequires': false,
4444
'ignoreModules': [],
45-
'escodegen': {},
45+
'escodegen': {
46+
'comment': true
47+
},
4648
'esprima': {
4749
'comment': true,
48-
'loc': true
50+
'loc': true,
51+
'range': true,
52+
'tokens': true
4953
},
5054
'globalModules': [],
5155
'commentCleanName': 'amdclean',
@@ -346,6 +350,7 @@
346350
'convertToIIFEDeclaration': function(obj) {
347351
var moduleName = obj.moduleName,
348352
callbackFuncParams = obj.callbackFuncParams,
353+
isOptimized = obj.isOptimized,
349354
callbackFunc = (function() {
350355
var cbFunc = obj.callbackFunc;
351356
if(cbFunc.type === 'Identifier') {
@@ -377,23 +382,29 @@
377382
}()),
378383
dependencyNames = obj.dependencyNames,
379384
options = publicAPI.options,
380-
cb = {
381-
'type': 'CallExpression',
382-
'callee': {
383-
'type': 'FunctionExpression',
384-
'id': {
385-
'type': 'Identifier',
386-
'name': ''
387-
},
388-
'params': callbackFuncParams,
389-
'defaults': [],
390-
'body': callbackFunc.body,
391-
'rest': callbackFunc.rest,
392-
'generator': callbackFunc.generator,
393-
'expression': callbackFunc.expression
394-
},
395-
'arguments': dependencyNames
396-
},
385+
cb = (function() {
386+
if(callbackFunc.type === 'Literal' || isOptimized === true) {
387+
return callbackFunc;
388+
} else {
389+
return {
390+
'type': 'CallExpression',
391+
'callee': {
392+
'type': 'FunctionExpression',
393+
'id': {
394+
'type': 'Identifier',
395+
'name': ''
396+
},
397+
'params': callbackFuncParams,
398+
'defaults': [],
399+
'body': callbackFunc.body,
400+
'rest': callbackFunc.rest,
401+
'generator': callbackFunc.generator,
402+
'expression': callbackFunc.expression
403+
},
404+
'arguments': dependencyNames
405+
};
406+
}
407+
}()),
397408
updatedNode = (function() {
398409
if(options.globalObject === true && options.globalObjectName) {
399410
return {
@@ -414,7 +425,7 @@
414425
'raw': "" + moduleName + ""
415426
}
416427
},
417-
"right": cb
428+
'right': cb
418429
}
419430
};
420431
} else {
@@ -443,6 +454,7 @@
443454
'convertToFunctionExpression': function(obj) {
444455
var isDefine = obj.isDefine,
445456
isRequire = obj.isRequire,
457+
isOptimized = false,
446458
node = obj.node,
447459
moduleName = obj.moduleName,
448460
dependencies = obj.dependencies,
@@ -478,7 +490,36 @@
478490
}
479491
return deps;
480492
}()),
481-
callbackFunc = obj.moduleReturnValue,
493+
callbackFunc = (function() {
494+
var callbackFunc = obj.moduleReturnValue,
495+
body,
496+
returnStatements,
497+
firstReturnStatement;
498+
// If the module has NO dependencies and the callback function is not empty
499+
if(!depLength && callbackFunc && callbackFunc.type === 'FunctionExpression' && callbackFunc.body && _.isArray(callbackFunc.body.body) && callbackFunc.body.body.length) {
500+
body = callbackFunc.body.body;
501+
// Returns an array of all return statements
502+
returnStatements = _.where(callbackFunc.body.body, { 'type': 'ReturnStatement' });
503+
// If there is a return statement
504+
if(returnStatements.length) {
505+
firstReturnStatement = returnStatements[0];
506+
// If something other than a function expression is getting returned
507+
// and there is more than one AST child node in the factory function
508+
// return early
509+
if(!publicAPI.isFunctionExpression(firstReturnStatement) && body.length > 1) {
510+
return callbackFunc;
511+
} else {
512+
// Optimize the AMD module by setting the callback function to the return statement argument
513+
callbackFunc = firstReturnStatement.argument;
514+
isOptimized = true;
515+
if(callbackFunc.params) {
516+
depLength = callbackFunc.params.length;
517+
}
518+
}
519+
}
520+
}
521+
return callbackFunc;
522+
}()),
482523
hasReturnStatement = (function() {
483524
var returns = [];
484525
if(callbackFunc && callbackFunc.body && _.isArray(callbackFunc.body.body)) {
@@ -533,7 +574,8 @@
533574
dependencyNames: dependencyNames,
534575
callbackFuncParams: callbackFuncParams,
535576
hasExportsParam: hasExportsParam,
536-
callbackFunc: callbackFunc
577+
callbackFunc: callbackFunc,
578+
isOptimized: isOptimized
537579
});
538580
} else if(isRequire) {
539581
return publicAPI.convertToIIFE({
@@ -712,8 +754,7 @@
712754
'createAst': function(obj) {
713755
var filePath = obj.filePath,
714756
code = obj.code || (filePath && publicAPI.env === 'node' ? publicAPI.readFile(filePath) : ''),
715-
esprimaDefaultOptions = publicAPI.defaultOptions.esprima,
716-
esprimaOptions = _.extend(esprimaDefaultOptions, (_.isPlainObject(obj.esprima) ? obj.esprima : {}));
757+
esprimaOptions = publicAPI.options.esprima;
717758
if(!code) {
718759
throw new Error(publicAPI.errorMsgs.emptyCode);
719760
} else {
@@ -751,23 +792,28 @@
751792
// ------------
752793
// Returns standard JavaScript generated by Escodegen
753794
'generateCode': function(ast, options) {
795+
var esprimaOptions = options.esprima || {},
796+
escodegenOptions = options.escodegen || {};
754797
if(!_.isPlainObject(escodegen) || !_.isFunction(escodegen.generate)) {
755798
throw new Error(publicAPI.errorMsgs.escodegen);
756799
}
757-
return escodegen.generate(ast, options);
800+
// Check if both the esprima and escodegen comment options are set to true
801+
if(esprimaOptions.comment === true && escodegenOptions.comment === true) {
802+
// Needed to keep source code comments when generating the code with escodegen
803+
ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
804+
}
805+
return escodegen.generate(ast, escodegenOptions);
758806
},
759807
// clean
760808
// -----
761809
// Creates an AST using Esprima, traverse and updates the AST using Estraverse, and generates standard JavaScript using Escodegen.
762810
'clean': function(obj) {
763811
var code = {},
764812
ast = {},
765-
options = {};
766-
767-
publicAPI.options = publicAPI.defaultOptions;
768-
if(_.isPlainObject(obj)) {
769-
publicAPI.options = options = _.extend({}, publicAPI.options, obj);
770-
}
813+
options = {},
814+
defaultOptions = _.cloneDeep(publicAPI.defaultOptions) || {},
815+
userOptions = _.cloneDeep(obj) || {};
816+
publicAPI.options = options = _.merge(defaultOptions, userOptions);
771817
if(!_ || !_.isPlainObject) {
772818
throw new Error(publicAPI.errorMsgs.lodash);
773819
}
@@ -858,7 +904,7 @@
858904
'kind': 'var'
859905
});
860906
}
861-
return publicAPI.generateCode(ast, options.escodegen);
907+
return publicAPI.generateCode(ast, options);
862908
}
863909
};
864910
// Returns the public API for node and web environments

0 commit comments

Comments
 (0)