coffeescript-router 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/.gitignore +3 -0
  2. data/Cakefile +122 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/LICENSE.txt +19 -0
  6. data/README.md +18 -0
  7. data/Rakefile +2 -0
  8. data/SpecRunner.html +25 -0
  9. data/coffeescript-router.gemspec +19 -0
  10. data/lib/CoffeeScript.png +0 -0
  11. data/lib/coffeescript-router/version.rb +5 -0
  12. data/lib/jasmine-1.0.2/MIT.LICENSE +20 -0
  13. data/lib/jasmine-1.0.2/jasmine-html.js +188 -0
  14. data/lib/jasmine-1.0.2/jasmine.css +166 -0
  15. data/lib/jasmine-1.0.2/jasmine.js +2421 -0
  16. data/node_modules/.bin/cake +7 -0
  17. data/node_modules/.bin/coffee +7 -0
  18. data/node_modules/.bin/uglifyjs +212 -0
  19. data/node_modules/coffee-script/.npmignore +11 -0
  20. data/node_modules/coffee-script/LICENSE +22 -0
  21. data/node_modules/coffee-script/README +48 -0
  22. data/node_modules/coffee-script/Rakefile +78 -0
  23. data/node_modules/coffee-script/bin/cake +7 -0
  24. data/node_modules/coffee-script/bin/coffee +7 -0
  25. data/node_modules/coffee-script/lib/browser.js +75 -0
  26. data/node_modules/coffee-script/lib/cake.js +76 -0
  27. data/node_modules/coffee-script/lib/coffee-script.js +107 -0
  28. data/node_modules/coffee-script/lib/command.js +274 -0
  29. data/node_modules/coffee-script/lib/grammar.js +591 -0
  30. data/node_modules/coffee-script/lib/helpers.js +66 -0
  31. data/node_modules/coffee-script/lib/index.js +8 -0
  32. data/node_modules/coffee-script/lib/lexer.js +650 -0
  33. data/node_modules/coffee-script/lib/nodes.js +2230 -0
  34. data/node_modules/coffee-script/lib/optparse.js +111 -0
  35. data/node_modules/coffee-script/lib/parser.js +676 -0
  36. data/node_modules/coffee-script/lib/repl.js +114 -0
  37. data/node_modules/coffee-script/lib/rewriter.js +359 -0
  38. data/node_modules/coffee-script/lib/scope.js +120 -0
  39. data/node_modules/coffee-script/package.json +27 -0
  40. data/node_modules/growl/History.md +16 -0
  41. data/node_modules/growl/Readme.md +74 -0
  42. data/node_modules/growl/lib/growl.js +82 -0
  43. data/node_modules/growl/package.json +6 -0
  44. data/node_modules/growl/test.js +17 -0
  45. data/node_modules/uglify-js/.gitignore +4 -0
  46. data/node_modules/uglify-js/README.html +825 -0
  47. data/node_modules/uglify-js/README.org +431 -0
  48. data/node_modules/uglify-js/bin/uglifyjs +212 -0
  49. data/node_modules/uglify-js/docstyle.css +75 -0
  50. data/node_modules/uglify-js/lib/parse-js.js +1319 -0
  51. data/node_modules/uglify-js/lib/process.js +1614 -0
  52. data/node_modules/uglify-js/lib/squeeze-more.js +22 -0
  53. data/node_modules/uglify-js/package.json +22 -0
  54. data/node_modules/uglify-js/test/beautify.js +28 -0
  55. data/node_modules/uglify-js/test/testparser.js +402 -0
  56. data/node_modules/uglify-js/test/unit/compress/expected/array1.js +1 -0
  57. data/node_modules/uglify-js/test/unit/compress/expected/array2.js +1 -0
  58. data/node_modules/uglify-js/test/unit/compress/expected/array3.js +1 -0
  59. data/node_modules/uglify-js/test/unit/compress/expected/array4.js +1 -0
  60. data/node_modules/uglify-js/test/unit/compress/expected/assignment.js +1 -0
  61. data/node_modules/uglify-js/test/unit/compress/expected/concatstring.js +1 -0
  62. data/node_modules/uglify-js/test/unit/compress/expected/const.js +1 -0
  63. data/node_modules/uglify-js/test/unit/compress/expected/empty-blocks.js +1 -0
  64. data/node_modules/uglify-js/test/unit/compress/expected/forstatement.js +1 -0
  65. data/node_modules/uglify-js/test/unit/compress/expected/if.js +1 -0
  66. data/node_modules/uglify-js/test/unit/compress/expected/ifreturn.js +1 -0
  67. data/node_modules/uglify-js/test/unit/compress/expected/issue10.js +1 -0
  68. data/node_modules/uglify-js/test/unit/compress/expected/issue11.js +1 -0
  69. data/node_modules/uglify-js/test/unit/compress/expected/issue13.js +1 -0
  70. data/node_modules/uglify-js/test/unit/compress/expected/issue14.js +1 -0
  71. data/node_modules/uglify-js/test/unit/compress/expected/issue16.js +1 -0
  72. data/node_modules/uglify-js/test/unit/compress/expected/issue17.js +1 -0
  73. data/node_modules/uglify-js/test/unit/compress/expected/issue20.js +1 -0
  74. data/node_modules/uglify-js/test/unit/compress/expected/issue21.js +1 -0
  75. data/node_modules/uglify-js/test/unit/compress/expected/issue25.js +1 -0
  76. data/node_modules/uglify-js/test/unit/compress/expected/issue27.js +1 -0
  77. data/node_modules/uglify-js/test/unit/compress/expected/issue28.js +1 -0
  78. data/node_modules/uglify-js/test/unit/compress/expected/issue29.js +1 -0
  79. data/node_modules/uglify-js/test/unit/compress/expected/issue30.js +1 -0
  80. data/node_modules/uglify-js/test/unit/compress/expected/issue34.js +1 -0
  81. data/node_modules/uglify-js/test/unit/compress/expected/issue4.js +1 -0
  82. data/node_modules/uglify-js/test/unit/compress/expected/issue48.js +1 -0
  83. data/node_modules/uglify-js/test/unit/compress/expected/issue50.js +1 -0
  84. data/node_modules/uglify-js/test/unit/compress/expected/issue53.js +1 -0
  85. data/node_modules/uglify-js/test/unit/compress/expected/issue54.1.js +1 -0
  86. data/node_modules/uglify-js/test/unit/compress/expected/issue68.js +1 -0
  87. data/node_modules/uglify-js/test/unit/compress/expected/issue69.js +1 -0
  88. data/node_modules/uglify-js/test/unit/compress/expected/issue9.js +1 -0
  89. data/node_modules/uglify-js/test/unit/compress/expected/strict-equals.js +1 -0
  90. data/node_modules/uglify-js/test/unit/compress/expected/var.js +1 -0
  91. data/node_modules/uglify-js/test/unit/compress/test/array1.js +3 -0
  92. data/node_modules/uglify-js/test/unit/compress/test/array2.js +4 -0
  93. data/node_modules/uglify-js/test/unit/compress/test/array3.js +4 -0
  94. data/node_modules/uglify-js/test/unit/compress/test/array4.js +6 -0
  95. data/node_modules/uglify-js/test/unit/compress/test/assignment.js +20 -0
  96. data/node_modules/uglify-js/test/unit/compress/test/concatstring.js +3 -0
  97. data/node_modules/uglify-js/test/unit/compress/test/const.js +5 -0
  98. data/node_modules/uglify-js/test/unit/compress/test/empty-blocks.js +4 -0
  99. data/node_modules/uglify-js/test/unit/compress/test/forstatement.js +10 -0
  100. data/node_modules/uglify-js/test/unit/compress/test/if.js +6 -0
  101. data/node_modules/uglify-js/test/unit/compress/test/ifreturn.js +9 -0
  102. data/node_modules/uglify-js/test/unit/compress/test/issue10.js +1 -0
  103. data/node_modules/uglify-js/test/unit/compress/test/issue11.js +3 -0
  104. data/node_modules/uglify-js/test/unit/compress/test/issue13.js +1 -0
  105. data/node_modules/uglify-js/test/unit/compress/test/issue14.js +1 -0
  106. data/node_modules/uglify-js/test/unit/compress/test/issue16.js +1 -0
  107. data/node_modules/uglify-js/test/unit/compress/test/issue17.js +4 -0
  108. data/node_modules/uglify-js/test/unit/compress/test/issue20.js +1 -0
  109. data/node_modules/uglify-js/test/unit/compress/test/issue21.js +6 -0
  110. data/node_modules/uglify-js/test/unit/compress/test/issue25.js +7 -0
  111. data/node_modules/uglify-js/test/unit/compress/test/issue27.js +1 -0
  112. data/node_modules/uglify-js/test/unit/compress/test/issue28.js +3 -0
  113. data/node_modules/uglify-js/test/unit/compress/test/issue29.js +1 -0
  114. data/node_modules/uglify-js/test/unit/compress/test/issue30.js +3 -0
  115. data/node_modules/uglify-js/test/unit/compress/test/issue34.js +3 -0
  116. data/node_modules/uglify-js/test/unit/compress/test/issue4.js +3 -0
  117. data/node_modules/uglify-js/test/unit/compress/test/issue48.js +1 -0
  118. data/node_modules/uglify-js/test/unit/compress/test/issue50.js +9 -0
  119. data/node_modules/uglify-js/test/unit/compress/test/issue53.js +1 -0
  120. data/node_modules/uglify-js/test/unit/compress/test/issue54.1.js +3 -0
  121. data/node_modules/uglify-js/test/unit/compress/test/issue68.js +5 -0
  122. data/node_modules/uglify-js/test/unit/compress/test/issue69.js +1 -0
  123. data/node_modules/uglify-js/test/unit/compress/test/issue9.js +4 -0
  124. data/node_modules/uglify-js/test/unit/compress/test/strict-equals.js +3 -0
  125. data/node_modules/uglify-js/test/unit/compress/test/var.js +3 -0
  126. data/node_modules/uglify-js/test/unit/scripts.js +46 -0
  127. data/node_modules/uglify-js/uglify-js.js +2 -0
  128. data/src/coffeescript/coffeescript-router.js.coffee +31 -0
  129. data/test/coffeescript/routerSpec.coffee +47 -0
  130. data/vendor/assets/javascripts/coffeescript-router.min.js +1 -0
  131. metadata +187 -0
@@ -0,0 +1,120 @@
1
+ (function() {
2
+ var Scope, extend, last, _ref;
3
+ _ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
4
+ exports.Scope = Scope = (function() {
5
+ Scope.root = null;
6
+ function Scope(parent, expressions, method) {
7
+ this.parent = parent;
8
+ this.expressions = expressions;
9
+ this.method = method;
10
+ this.variables = [
11
+ {
12
+ name: 'arguments',
13
+ type: 'arguments'
14
+ }
15
+ ];
16
+ this.positions = {};
17
+ if (!this.parent) {
18
+ Scope.root = this;
19
+ }
20
+ }
21
+ Scope.prototype.add = function(name, type, immediate) {
22
+ var pos;
23
+ if (this.shared && !immediate) {
24
+ return this.parent.add(name, type, immediate);
25
+ }
26
+ if (typeof (pos = this.positions[name]) === 'number') {
27
+ return this.variables[pos].type = type;
28
+ } else {
29
+ return this.positions[name] = this.variables.push({
30
+ name: name,
31
+ type: type
32
+ }) - 1;
33
+ }
34
+ };
35
+ Scope.prototype.find = function(name, options) {
36
+ if (this.check(name, options)) {
37
+ return true;
38
+ }
39
+ this.add(name, 'var');
40
+ return false;
41
+ };
42
+ Scope.prototype.parameter = function(name) {
43
+ if (this.shared && this.parent.check(name, true)) {
44
+ return;
45
+ }
46
+ return this.add(name, 'param');
47
+ };
48
+ Scope.prototype.check = function(name, immediate) {
49
+ var found, _ref2;
50
+ found = !!this.type(name);
51
+ if (found || immediate) {
52
+ return found;
53
+ }
54
+ return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0);
55
+ };
56
+ Scope.prototype.temporary = function(name, index) {
57
+ if (name.length > 1) {
58
+ return '_' + name + (index > 1 ? index : '');
59
+ } else {
60
+ return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
61
+ }
62
+ };
63
+ Scope.prototype.type = function(name) {
64
+ var v, _i, _len, _ref2;
65
+ _ref2 = this.variables;
66
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
67
+ v = _ref2[_i];
68
+ if (v.name === name) {
69
+ return v.type;
70
+ }
71
+ }
72
+ return null;
73
+ };
74
+ Scope.prototype.freeVariable = function(type) {
75
+ var index, temp;
76
+ index = 0;
77
+ while (this.check((temp = this.temporary(type, index)))) {
78
+ index++;
79
+ }
80
+ this.add(temp, 'var', true);
81
+ return temp;
82
+ };
83
+ Scope.prototype.assign = function(name, value) {
84
+ this.add(name, {
85
+ value: value,
86
+ assigned: true
87
+ });
88
+ return this.hasAssignments = true;
89
+ };
90
+ Scope.prototype.hasDeclarations = function() {
91
+ return !!this.declaredVariables().length;
92
+ };
93
+ Scope.prototype.declaredVariables = function() {
94
+ var realVars, tempVars, v, _i, _len, _ref2;
95
+ realVars = [];
96
+ tempVars = [];
97
+ _ref2 = this.variables;
98
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
99
+ v = _ref2[_i];
100
+ if (v.type === 'var') {
101
+ (v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
102
+ }
103
+ }
104
+ return realVars.sort().concat(tempVars.sort());
105
+ };
106
+ Scope.prototype.assignedVariables = function() {
107
+ var v, _i, _len, _ref2, _results;
108
+ _ref2 = this.variables;
109
+ _results = [];
110
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
111
+ v = _ref2[_i];
112
+ if (v.type.assigned) {
113
+ _results.push("" + v.name + " = " + v.type.value);
114
+ }
115
+ }
116
+ return _results;
117
+ };
118
+ return Scope;
119
+ })();
120
+ }).call(this);
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "coffee-script",
3
+ "description": "Unfancy JavaScript",
4
+ "keywords": ["javascript", "language", "coffeescript", "compiler"],
5
+ "author": "Jeremy Ashkenas",
6
+ "version": "1.1.0",
7
+ "licenses": [{
8
+ "type": "MIT",
9
+ "url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
10
+ }],
11
+ "engines": {
12
+ "node": ">=0.2.5"
13
+ },
14
+ "directories" : {
15
+ "lib" : "./lib"
16
+ },
17
+ "main" : "./lib/coffee-script",
18
+ "bin": {
19
+ "coffee": "./bin/coffee",
20
+ "cake": "./bin/cake"
21
+ },
22
+ "homepage": "http://coffeescript.org",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git://github.com/jashkenas/coffee-script.git"
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+
2
+ 1.1.0 / 2011-03-15
3
+ ==================
4
+
5
+ * Added optional callbacks
6
+ * Added parsing of version
7
+
8
+ 1.0.1 / 2010-03-26
9
+ ==================
10
+
11
+ * Fixed; sys.exec -> child_process.exec to support latest node
12
+
13
+ 1.0.0 / 2010-03-19
14
+ ==================
15
+
16
+ * Initial release
@@ -0,0 +1,74 @@
1
+
2
+ # Growl for nodejs
3
+
4
+ Growl support for Nodejs. This is essentially a port of my [Ruby Growl Library](http://github.com/visionmedia/growl).
5
+
6
+ ## Installation
7
+
8
+ Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
9
+ and run:
10
+
11
+ $ kiwi -v install growl
12
+
13
+ ## Examples
14
+
15
+ Callback functions are optional
16
+
17
+ var growl = require('growl')
18
+ growl.notify('You have mail!')
19
+ growl.notify('5 new messages', { sticky: true })
20
+ growl.notify('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true })
21
+ growl.notify('Show Safari icon', { image: 'Safari' })
22
+ growl.notify('Show icon', { image: 'path/to/icon.icns' })
23
+ growl.notify('Show image', { image: 'path/to/my.image.png' })
24
+ growl.notify('Show png filesystem icon', { image: 'png' })
25
+ growl.notify('Show pdf filesystem icon', { image: 'article.pdf' })
26
+ growl.notify('Show pdf filesystem icon', { image: 'article.pdf' }, function(){
27
+ // ... notified
28
+ })
29
+
30
+ ## Options
31
+
32
+ - title
33
+ - notification title
34
+ - name
35
+ - application name
36
+ - sticky
37
+ - weither or not the notification should remainin until closed
38
+ - image
39
+ - Auto-detects the context:
40
+ - path to an icon sets --iconpath
41
+ - path to an image sets --image
42
+ - capitalized word sets --appIcon
43
+ - filename uses extname as --icon
44
+ - otherwise treated as --icon
45
+
46
+ Fetch the current version of 'growlnotify':
47
+
48
+ growl.binVersion(function(err, version){ ... })
49
+ // => 'n.n.n'
50
+
51
+ ## License
52
+
53
+ (The MIT License)
54
+
55
+ Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca>
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining
58
+ a copy of this software and associated documentation files (the
59
+ 'Software'), to deal in the Software without restriction, including
60
+ without limitation the rights to use, copy, modify, merge, publish,
61
+ distribute, sublicense, and/or sell copies of the Software, and to
62
+ permit persons to whom the Software is furnished to do so, subject to
63
+ the following conditions:
64
+
65
+ The above copyright notice and this permission notice shall be
66
+ included in all copies or substantial portions of the Software.
67
+
68
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
69
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
70
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
71
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
72
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
73
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
74
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+
2
+ // Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
3
+
4
+ /**
5
+ * Module dependencies.
6
+ */
7
+
8
+ var exec = require('child_process').exec
9
+ , path = require('path');
10
+
11
+ /**
12
+ * Node-growl version.
13
+ */
14
+
15
+ exports.version = '1.1.0'
16
+
17
+ /**
18
+ * Fetch the binary version when available.
19
+ *
20
+ * @param {function} fn
21
+ * @api public
22
+ */
23
+
24
+ exports.binVersion = function(fn) {
25
+ exec('growlnotify -v', function(err, stdout){
26
+ if (err) return fn(err);
27
+ var version = /(\d+\.\d+(?:\.\d+)?)/.exec(stdout)[1];
28
+ fn(null, parseFloat(version));
29
+ });
30
+ };
31
+
32
+ /**
33
+ * Send growl notification _msg_ with _options_.
34
+ *
35
+ * Options:
36
+ *
37
+ * - title Notification title
38
+ * - sticky Make the notification stick (defaults to false)
39
+ * - name Application name (defaults to growlnotify)
40
+ * - image
41
+ * - path to an icon sets --iconpath
42
+ * - path to an image sets --image
43
+ * - capitalized word sets --appIcon
44
+ * - filename uses extname as --icon
45
+ * - otherwise treated as --icon
46
+ *
47
+ * Examples:
48
+ *
49
+ * growl.notify('New email')
50
+ * growl.notify('5 new emails', { title: 'Thunderbird' })
51
+ * growl.notify('Email sent', function(){
52
+ * // ... notification sent
53
+ * })
54
+ *
55
+ * @param {string} msg
56
+ * @param {object} options
57
+ * @param {function} fn
58
+ * @api public
59
+ */
60
+
61
+ exports.notify = function(msg, options, fn) {
62
+ var image
63
+ , args = ['growlnotify', '-m', '"' + msg + '"']
64
+ , options = options || {}
65
+ , fn = fn || function(){};
66
+ exports.binVersion(function(err, version){
67
+ if (err) return fn(err);
68
+ if (image = options.image) {
69
+ var flag, ext = path.extname(image).substr(1)
70
+ flag = flag || ext == 'icns' && 'iconpath'
71
+ flag = flag || /^[A-Z]/.test(image) && 'appIcon'
72
+ flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image'
73
+ flag = flag || ext && (image = ext) && 'icon'
74
+ flag = flag || 'icon'
75
+ args.push('--' + flag, image)
76
+ }
77
+ if (options.sticky) args.push('--sticky');
78
+ if (options.name) args.push('--name', options.name);
79
+ if (options.title) args.push(options.title);
80
+ exec(args.join(' '), fn);
81
+ });
82
+ };
@@ -0,0 +1,6 @@
1
+ { "name": "growl",
2
+ "version": "1.1.0",
3
+ "description": "Growl unobtrusive notifications",
4
+ "author": "TJ Holowaychuk <tj@vision-media.ca>",
5
+ "main": "./lib/growl.js"
6
+ }
@@ -0,0 +1,17 @@
1
+
2
+ var growl = require('./lib/growl')
3
+
4
+ growl.binVersion(function(err, version){
5
+ console.log(version);
6
+ })
7
+ growl.notify('You have mail!')
8
+ growl.notify('5 new messages', { sticky: true })
9
+ growl.notify('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true })
10
+ growl.notify('Show Safari icon', { image: 'Safari' })
11
+ growl.notify('Show icon', { image: 'path/to/icon.icns' })
12
+ growl.notify('Show image', { image: 'path/to/my.image.png' })
13
+ growl.notify('Show png filesystem icon', { image: 'png' })
14
+ growl.notify('Show pdf filesystem icon', { image: 'article.pdf' })
15
+ growl.notify('Show pdf filesystem icon', { image: 'article.pdf' }, function(){
16
+ require('sys').p('callback')
17
+ })
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ .tmp*~
3
+ *.local.*
4
+ .pinf-*
@@ -0,0 +1,825 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml"
5
+ lang="en" xml:lang="en">
6
+ <head>
7
+ <title>UglifyJS -- a JavaScript parser/compressor/beautifier</title>
8
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
9
+ <meta name="generator" content="Org-mode"/>
10
+ <meta name="generated" content="2011-04-04 00:07:13 EEST"/>
11
+ <meta name="author" content="Mihai Bazon"/>
12
+ <meta name="description" content="a JavaScript parser/compressor/beautifier in JavaScript"/>
13
+ <meta name="keywords" content="javascript, js, parser, compiler, compressor, mangle, minify, minifier"/>
14
+ <style type="text/css">
15
+ <!--/*--><![CDATA[/*><!--*/
16
+ html { font-family: Times, serif; font-size: 12pt; }
17
+ .title { text-align: center; }
18
+ .todo { color: red; }
19
+ .done { color: green; }
20
+ .tag { background-color: #add8e6; font-weight:normal }
21
+ .target { }
22
+ .timestamp { color: #bebebe; }
23
+ .timestamp-kwd { color: #5f9ea0; }
24
+ p.verse { margin-left: 3% }
25
+ pre {
26
+ border: 1pt solid #AEBDCC;
27
+ background-color: #F3F5F7;
28
+ padding: 5pt;
29
+ font-family: courier, monospace;
30
+ font-size: 90%;
31
+ overflow:auto;
32
+ }
33
+ table { border-collapse: collapse; }
34
+ td, th { vertical-align: top; }
35
+ dt { font-weight: bold; }
36
+ div.figure { padding: 0.5em; }
37
+ div.figure p { text-align: center; }
38
+ textarea { overflow-x: auto; }
39
+ .linenr { font-size:smaller }
40
+ .code-highlighted {background-color:#ffff00;}
41
+ .org-info-js_info-navigation { border-style:none; }
42
+ #org-info-js_console-label { font-size:10px; font-weight:bold;
43
+ white-space:nowrap; }
44
+ .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
45
+ font-weight:bold; }
46
+ /*]]>*/-->
47
+ </style>
48
+ <link rel="stylesheet" type="text/css" href="docstyle.css" />
49
+ <script type="text/javascript">
50
+ <!--/*--><![CDATA[/*><!--*/
51
+ function CodeHighlightOn(elem, id)
52
+ {
53
+ var target = document.getElementById(id);
54
+ if(null != target) {
55
+ elem.cacheClassElem = elem.className;
56
+ elem.cacheClassTarget = target.className;
57
+ target.className = "code-highlighted";
58
+ elem.className = "code-highlighted";
59
+ }
60
+ }
61
+ function CodeHighlightOff(elem, id)
62
+ {
63
+ var target = document.getElementById(id);
64
+ if(elem.cacheClassElem)
65
+ elem.className = elem.cacheClassElem;
66
+ if(elem.cacheClassTarget)
67
+ target.className = elem.cacheClassTarget;
68
+ }
69
+ /*]]>*///-->
70
+ </script>
71
+
72
+ </head>
73
+ <body>
74
+ <div id="content">
75
+
76
+ <h1 class="title">UglifyJS &ndash; a JavaScript parser/compressor/beautifier</h1>
77
+
78
+
79
+ <div id="table-of-contents">
80
+ <h2>Table of Contents</h2>
81
+ <div id="text-table-of-contents">
82
+ <ul>
83
+ <li><a href="#sec-1">1 UglifyJS &mdash; a JavaScript parser/compressor/beautifier </a>
84
+ <ul>
85
+ <li><a href="#sec-1_1">1.1 Unsafe transformations </a>
86
+ <ul>
87
+ <li><a href="#sec-1_1_1">1.1.1 Calls involving the global Array constructor </a></li>
88
+ </ul>
89
+ </li>
90
+ <li><a href="#sec-1_2">1.2 Install (NPM) </a></li>
91
+ <li><a href="#sec-1_3">1.3 Install latest code from GitHub </a></li>
92
+ <li><a href="#sec-1_4">1.4 Usage </a>
93
+ <ul>
94
+ <li><a href="#sec-1_4_1">1.4.1 API </a></li>
95
+ <li><a href="#sec-1_4_2">1.4.2 Beautifier shortcoming &ndash; no more comments </a></li>
96
+ </ul>
97
+ </li>
98
+ <li><a href="#sec-1_5">1.5 Compression &ndash; how good is it? </a></li>
99
+ <li><a href="#sec-1_6">1.6 Bugs? </a></li>
100
+ <li><a href="#sec-1_7">1.7 Links </a></li>
101
+ <li><a href="#sec-1_8">1.8 License </a></li>
102
+ </ul>
103
+ </li>
104
+ </ul>
105
+ </div>
106
+ </div>
107
+
108
+ <div id="outline-container-1" class="outline-2">
109
+ <h2 id="sec-1"><span class="section-number-2">1</span> UglifyJS &mdash; a JavaScript parser/compressor/beautifier </h2>
110
+ <div class="outline-text-2" id="text-1">
111
+
112
+
113
+ <p>
114
+ This package implements a general-purpose JavaScript
115
+ parser/compressor/beautifier toolkit. It is developed on <a href="http://nodejs.org/">NodeJS</a>, but it
116
+ should work on any JavaScript platform supporting the CommonJS module system
117
+ (and if your platform of choice doesn't support CommonJS, you can easily
118
+ implement it, or discard the <code>exports.*</code> lines from UglifyJS sources).
119
+ </p>
120
+ <p>
121
+ The tokenizer/parser generates an abstract syntax tree from JS code. You
122
+ can then traverse the AST to learn more about the code, or do various
123
+ manipulations on it. This part is implemented in <a href="../lib/parse-js.js">parse-js.js</a> and it's a
124
+ port to JavaScript of the excellent <a href="http://marijn.haverbeke.nl/parse-js/">parse-js</a> Common Lisp library from <a href="http://marijn.haverbeke.nl/">Marijn Haverbeke</a>.
125
+ </p>
126
+ <p>
127
+ ( See <a href="http://github.com/mishoo/cl-uglify-js">cl-uglify-js</a> if you're looking for the Common Lisp version of
128
+ UglifyJS. )
129
+ </p>
130
+ <p>
131
+ The second part of this package, implemented in <a href="../lib/process.js">process.js</a>, inspects and
132
+ manipulates the AST generated by the parser to provide the following:
133
+ </p>
134
+ <ul>
135
+ <li>
136
+ ability to re-generate JavaScript code from the AST. Optionally
137
+ indented&mdash;you can use this if you want to “beautify” a program that has
138
+ been compressed, so that you can inspect the source. But you can also run
139
+ our code generator to print out an AST without any whitespace, so you
140
+ achieve compression as well.
141
+
142
+ </li>
143
+ <li>
144
+ shorten variable names (usually to single characters). Our mangler will
145
+ analyze the code and generate proper variable names, depending on scope
146
+ and usage, and is smart enough to deal with globals defined elsewhere, or
147
+ with <code>eval()</code> calls or <code>with{}</code> statements. In short, if <code>eval()</code> or
148
+ <code>with{}</code> are used in some scope, then all variables in that scope and any
149
+ variables in the parent scopes will remain unmangled, and any references
150
+ to such variables remain unmangled as well.
151
+
152
+ </li>
153
+ <li>
154
+ various small optimizations that may lead to faster code but certainly
155
+ lead to smaller code. Where possible, we do the following:
156
+
157
+ <ul>
158
+ <li>
159
+ foo["bar"] ==&gt; foo.bar
160
+
161
+ </li>
162
+ <li>
163
+ remove block brackets <code>{}</code>
164
+
165
+ </li>
166
+ <li>
167
+ join consecutive var declarations:
168
+ var a = 10; var b = 20; ==&gt; var a=10,b=20;
169
+
170
+ </li>
171
+ <li>
172
+ resolve simple constant expressions: 1 +2 * 3 ==&gt; 7. We only do the
173
+ replacement if the result occupies less bytes; for example 1/3 would
174
+ translate to 0.333333333333, so in this case we don't replace it.
175
+
176
+ </li>
177
+ <li>
178
+ consecutive statements in blocks are merged into a sequence; in many
179
+ cases, this leaves blocks with a single statement, so then we can remove
180
+ the block brackets.
181
+
182
+ </li>
183
+ <li>
184
+ various optimizations for IF statements:
185
+
186
+ <ul>
187
+ <li>
188
+ if (foo) bar(); else baz(); ==&gt; foo?bar():baz();
189
+ </li>
190
+ <li>
191
+ if (!foo) bar(); else baz(); ==&gt; foo?baz():bar();
192
+ </li>
193
+ <li>
194
+ if (foo) bar(); ==&gt; foo&amp;&amp;bar();
195
+ </li>
196
+ <li>
197
+ if (!foo) bar(); ==&gt; foo||bar();
198
+ </li>
199
+ <li>
200
+ if (foo) return bar(); else return baz(); ==&gt; return foo?bar():baz();
201
+ </li>
202
+ <li>
203
+ if (foo) return bar(); else something(); ==&gt; {if(foo)return bar();something()}
204
+
205
+ </li>
206
+ </ul>
207
+ </li>
208
+ <li>
209
+ remove some unreachable code and warn about it (code that follows a
210
+ <code>return</code>, <code>throw</code>, <code>break</code> or <code>continue</code> statement, except
211
+ function/variable declarations).
212
+ </li>
213
+ </ul>
214
+ </li>
215
+ </ul>
216
+
217
+
218
+
219
+ </div>
220
+
221
+ <div id="outline-container-1_1" class="outline-3">
222
+ <h3 id="sec-1_1"><span class="section-number-3">1.1</span> <span class="target">Unsafe transformations</span> </h3>
223
+ <div class="outline-text-3" id="text-1_1">
224
+
225
+
226
+ <p>
227
+ UglifyJS tries its best to achieve great compression while leaving the
228
+ semantics of the code intact. In general, if your code logic is broken by
229
+ UglifyJS then it's a bug in UglifyJS and you should report it and I should
230
+ fix it. :-)
231
+ </p>
232
+ <p>
233
+ However, I opted to include the following potentially unsafe transformations
234
+ as default behavior. Discussion is welcome, if you have ideas of how to
235
+ handle this better, or any objections to these optimizations, please let me
236
+ know.
237
+ </p>
238
+
239
+ </div>
240
+
241
+ <div id="outline-container-1_1_1" class="outline-4">
242
+ <h4 id="sec-1_1_1"><span class="section-number-4">1.1.1</span> Calls involving the global Array constructor </h4>
243
+ <div class="outline-text-4" id="text-1_1_1">
244
+
245
+
246
+ <p>
247
+ The following transformations occur:
248
+ </p>
249
+
250
+
251
+
252
+ <pre class="src src-js"><span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3, 4) =&gt; [1,2,3,4]
253
+ Array(a, b, c) =&gt; [a,b,c]
254
+ <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(5) =&gt; Array(5)
255
+ <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(a) =&gt; Array(a)
256
+ </pre>
257
+
258
+
259
+
260
+ <p>
261
+ These are all safe if the Array name isn't redefined. JavaScript does allow
262
+ one to globally redefine Array (and pretty much everything, in fact) but I
263
+ personally don't see why would anyone do that.
264
+ </p>
265
+ <p>
266
+ UglifyJS does handle the case where Array is redefined locally, or even
267
+ globally but with a <code>function</code> or <code>var</code> declaration. Therefore, in the
268
+ following cases UglifyJS <b>doesn't touch</b> calls or instantiations of Array:
269
+ </p>
270
+
271
+
272
+
273
+ <pre class="src src-js"><span style="color: #b22222;">// </span><span style="color: #b22222;">case 1. globally declared variable
274
+ </span> <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
275
+ <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
276
+ Array(a, b);
277
+
278
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">or (can be declared later)
279
+ </span> <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
280
+ <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
281
+
282
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">or (can be a function)
283
+ </span> <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
284
+ <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">Array</span>() { ... }
285
+
286
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">case 2. declared in a function
287
+ </span> (<span style="color: #a020f0;">function</span>(){
288
+ a = <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3);
289
+ b = Array(5, 6);
290
+ <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">Array</span>;
291
+ })();
292
+
293
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">or
294
+ </span> (<span style="color: #a020f0;">function</span>(<span style="color: #b8860b;">Array</span>){
295
+ <span style="color: #a020f0;">return</span> Array(5, 6, 7);
296
+ })();
297
+
298
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">or
299
+ </span> (<span style="color: #a020f0;">function</span>(){
300
+ <span style="color: #a020f0;">return</span> <span style="color: #a020f0;">new</span> <span style="color: #228b22;">Array</span>(1, 2, 3, 4);
301
+ <span style="color: #a020f0;">function</span> <span style="color: #0000ff;">Array</span>() { ... }
302
+ })();
303
+
304
+ <span style="color: #b22222;">// </span><span style="color: #b22222;">etc.
305
+ </span></pre>
306
+
307
+
308
+
309
+ </div>
310
+ </div>
311
+
312
+ </div>
313
+
314
+ <div id="outline-container-1_2" class="outline-3">
315
+ <h3 id="sec-1_2"><span class="section-number-3">1.2</span> Install (NPM) </h3>
316
+ <div class="outline-text-3" id="text-1_2">
317
+
318
+
319
+ <p>
320
+ UglifyJS is now available through NPM &mdash; <code>npm install uglify-js</code> should do
321
+ the job.
322
+ </p>
323
+ </div>
324
+
325
+ </div>
326
+
327
+ <div id="outline-container-1_3" class="outline-3">
328
+ <h3 id="sec-1_3"><span class="section-number-3">1.3</span> Install latest code from GitHub </h3>
329
+ <div class="outline-text-3" id="text-1_3">
330
+
331
+
332
+
333
+
334
+
335
+ <pre class="src src-sh"><span style="color: #b22222;">## </span><span style="color: #b22222;">clone the repository
336
+ </span>mkdir -p /where/you/wanna/put/it
337
+ <span style="color: #da70d6;">cd</span> /where/you/wanna/put/it
338
+ git clone git://github.com/mishoo/UglifyJS.git
339
+
340
+ <span style="color: #b22222;">## </span><span style="color: #b22222;">make the module available to Node
341
+ </span>mkdir -p ~/.node_libraries/
342
+ <span style="color: #da70d6;">cd</span> ~/.node_libraries/
343
+ ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js
344
+
345
+ <span style="color: #b22222;">## </span><span style="color: #b22222;">and if you want the CLI script too:
346
+ </span>mkdir -p ~/bin
347
+ <span style="color: #da70d6;">cd</span> ~/bin
348
+ ln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs
349
+ <span style="color: #b22222;"># </span><span style="color: #b22222;">(then add ~/bin to your $PATH if it's not there already)
350
+ </span></pre>
351
+
352
+
353
+
354
+ </div>
355
+
356
+ </div>
357
+
358
+ <div id="outline-container-1_4" class="outline-3">
359
+ <h3 id="sec-1_4"><span class="section-number-3">1.4</span> Usage </h3>
360
+ <div class="outline-text-3" id="text-1_4">
361
+
362
+
363
+ <p>
364
+ There is a command-line tool that exposes the functionality of this library
365
+ for your shell-scripting needs:
366
+ </p>
367
+
368
+
369
+
370
+ <pre class="src src-sh">uglifyjs [ options... ] [ filename ]
371
+ </pre>
372
+
373
+
374
+
375
+ <p>
376
+ <code>filename</code> should be the last argument and should name the file from which
377
+ to read the JavaScript code. If you don't specify it, it will read code
378
+ from STDIN.
379
+ </p>
380
+ <p>
381
+ Supported options:
382
+ </p>
383
+ <ul>
384
+ <li>
385
+ <code>-b</code> or <code>--beautify</code> &mdash; output indented code; when passed, additional
386
+ options control the beautifier:
387
+
388
+ <ul>
389
+ <li>
390
+ <code>-i N</code> or <code>--indent N</code> &mdash; indentation level (number of spaces)
391
+
392
+ </li>
393
+ <li>
394
+ <code>-q</code> or <code>--quote-keys</code> &mdash; quote keys in literal objects (by default,
395
+ only keys that cannot be identifier names will be quotes).
396
+
397
+ </li>
398
+ </ul>
399
+ </li>
400
+ <li>
401
+ <code>--ascii</code> &mdash; pass this argument to encode non-ASCII characters as
402
+ <code>\uXXXX</code> sequences. By default UglifyJS won't bother to do it and will
403
+ output Unicode characters instead. (the output is always encoded in UTF8,
404
+ but if you pass this option you'll only get ASCII).
405
+
406
+ </li>
407
+ <li>
408
+ <code>-nm</code> or <code>--no-mangle</code> &mdash; don't mangle variable names
409
+
410
+ </li>
411
+ <li>
412
+ <code>-ns</code> or <code>--no-squeeze</code> &mdash; don't call <code>ast_squeeze()</code> (which does various
413
+ optimizations that result in smaller, less readable code).
414
+
415
+ </li>
416
+ <li>
417
+ <code>-mt</code> or <code>--mangle-toplevel</code> &mdash; mangle names in the toplevel scope too
418
+ (by default we don't do this).
419
+
420
+ </li>
421
+ <li>
422
+ <code>--no-seqs</code> &mdash; when <code>ast_squeeze()</code> is called (thus, unless you pass
423
+ <code>--no-squeeze</code>) it will reduce consecutive statements in blocks into a
424
+ sequence. For example, "a = 10; b = 20; foo();" will be written as
425
+ "a=10,b=20,foo();". In various occasions, this allows us to discard the
426
+ block brackets (since the block becomes a single statement). This is ON
427
+ by default because it seems safe and saves a few hundred bytes on some
428
+ libs that I tested it on, but pass <code>--no-seqs</code> to disable it.
429
+
430
+ </li>
431
+ <li>
432
+ <code>--no-dead-code</code> &mdash; by default, UglifyJS will remove code that is
433
+ obviously unreachable (code that follows a <code>return</code>, <code>throw</code>, <code>break</code> or
434
+ <code>continue</code> statement and is not a function/variable declaration). Pass
435
+ this option to disable this optimization.
436
+
437
+ </li>
438
+ <li>
439
+ <code>-nc</code> or <code>--no-copyright</code> &mdash; by default, <code>uglifyjs</code> will keep the initial
440
+ comment tokens in the generated code (assumed to be copyright information
441
+ etc.). If you pass this it will discard it.
442
+
443
+ </li>
444
+ <li>
445
+ <code>-o filename</code> or <code>--output filename</code> &mdash; put the result in <code>filename</code>. If
446
+ this isn't given, the result goes to standard output (or see next one).
447
+
448
+ </li>
449
+ <li>
450
+ <code>--overwrite</code> &mdash; if the code is read from a file (not from STDIN) and you
451
+ pass <code>--overwrite</code> then the output will be written in the same file.
452
+
453
+ </li>
454
+ <li>
455
+ <code>--ast</code> &mdash; pass this if you want to get the Abstract Syntax Tree instead
456
+ of JavaScript as output. Useful for debugging or learning more about the
457
+ internals.
458
+
459
+ </li>
460
+ <li>
461
+ <code>-v</code> or <code>--verbose</code> &mdash; output some notes on STDERR (for now just how long
462
+ each operation takes).
463
+
464
+ </li>
465
+ <li>
466
+ <code>--extra</code> &mdash; enable additional optimizations that have not yet been
467
+ extensively tested. These might, or might not, break your code. If you
468
+ find a bug using this option, please report a test case.
469
+
470
+ </li>
471
+ <li>
472
+ <code>--unsafe</code> &mdash; enable other additional optimizations that are known to be
473
+ unsafe in some contrived situations, but could still be generally useful.
474
+ For now only this:
475
+
476
+ <ul>
477
+ <li>
478
+ foo.toString() ==&gt; foo+""
479
+
480
+ </li>
481
+ </ul>
482
+ </li>
483
+ <li>
484
+ <code>--max-line-len</code> (default 32K characters) &mdash; add a newline after around
485
+ 32K characters. I've seen both FF and Chrome croak when all the code was
486
+ on a single line of around 670K. Pass &ndash;max-line-len 0 to disable this
487
+ safety feature.
488
+
489
+ </li>
490
+ <li>
491
+ <code>--reserved-names</code> &mdash; some libraries rely on certain names to be used, as
492
+ pointed out in issue #92 and #81, so this option allow you to exclude such
493
+ names from the mangler. For example, to keep names <code>require</code> and <code>$super</code>
494
+ intact you'd specify &ndash;reserved-names "require,$super".
495
+ </li>
496
+ </ul>
497
+
498
+
499
+
500
+ </div>
501
+
502
+ <div id="outline-container-1_4_1" class="outline-4">
503
+ <h4 id="sec-1_4_1"><span class="section-number-4">1.4.1</span> API </h4>
504
+ <div class="outline-text-4" id="text-1_4_1">
505
+
506
+
507
+ <p>
508
+ To use the library from JavaScript, you'd do the following (example for
509
+ NodeJS):
510
+ </p>
511
+
512
+
513
+
514
+ <pre class="src src-js"><span style="color: #a020f0;">var</span> <span style="color: #b8860b;">jsp</span> = require(<span style="color: #bc8f8f;">"uglify-js"</span>).parser;
515
+ <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">pro</span> = require(<span style="color: #bc8f8f;">"uglify-js"</span>).uglify;
516
+
517
+ <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">orig_code</span> = <span style="color: #bc8f8f;">"... JS code here"</span>;
518
+ <span style="color: #a020f0;">var</span> <span style="color: #b8860b;">ast</span> = jsp.parse(orig_code); <span style="color: #b22222;">// </span><span style="color: #b22222;">parse code and get the initial AST
519
+ </span>ast = pro.ast_mangle(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">get a new AST with mangled names
520
+ </span>ast = pro.ast_squeeze(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">get an AST with compression optimizations
521
+ </span><span style="color: #a020f0;">var</span> <span style="color: #b8860b;">final_code</span> = pro.gen_code(ast); <span style="color: #b22222;">// </span><span style="color: #b22222;">compressed code here
522
+ </span></pre>
523
+
524
+
525
+
526
+ <p>
527
+ The above performs the full compression that is possible right now. As you
528
+ can see, there are a sequence of steps which you can apply. For example if
529
+ you want compressed output but for some reason you don't want to mangle
530
+ variable names, you would simply skip the line that calls
531
+ <code>pro.ast_mangle(ast)</code>.
532
+ </p>
533
+ <p>
534
+ Some of these functions take optional arguments. Here's a description:
535
+ </p>
536
+ <ul>
537
+ <li>
538
+ <code>jsp.parse(code, strict_semicolons)</code> &ndash; parses JS code and returns an AST.
539
+ <code>strict_semicolons</code> is optional and defaults to <code>false</code>. If you pass
540
+ <code>true</code> then the parser will throw an error when it expects a semicolon and
541
+ it doesn't find it. For most JS code you don't want that, but it's useful
542
+ if you want to strictly sanitize your code.
543
+
544
+ </li>
545
+ <li>
546
+ <code>pro.ast_mangle(ast, options)</code> &ndash; generates a new AST containing mangled
547
+ (compressed) variable and function names. It supports the following
548
+ options:
549
+
550
+ <ul>
551
+ <li>
552
+ <code>toplevel</code> &ndash; mangle toplevel names (by default we don't touch them).
553
+ </li>
554
+ <li>
555
+ <code>except</code> &ndash; an array of names to exclude from compression.
556
+
557
+ </li>
558
+ </ul>
559
+ </li>
560
+ <li>
561
+ <code>pro.ast_squeeze(ast, options)</code> &ndash; employs further optimizations designed
562
+ to reduce the size of the code that <code>gen_code</code> would generate from the
563
+ AST. Returns a new AST. <code>options</code> can be a hash; the supported options
564
+ are:
565
+
566
+ <ul>
567
+ <li>
568
+ <code>make_seqs</code> (default true) which will cause consecutive statements in a
569
+ block to be merged using the "sequence" (comma) operator
570
+
571
+ </li>
572
+ <li>
573
+ <code>dead_code</code> (default true) which will remove unreachable code.
574
+
575
+ </li>
576
+ </ul>
577
+ </li>
578
+ <li>
579
+ <code>pro.gen_code(ast, options)</code> &ndash; generates JS code from the AST. By
580
+ default it's minified, but using the <code>options</code> argument you can get nicely
581
+ formatted output. <code>options</code> is, well, optional :-) and if you pass it it
582
+ must be an object and supports the following properties (below you can see
583
+ the default values):
584
+
585
+ <ul>
586
+ <li>
587
+ <code>beautify: false</code> &ndash; pass <code>true</code> if you want indented output
588
+ </li>
589
+ <li>
590
+ <code>indent_start: 0</code> (only applies when <code>beautify</code> is <code>true</code>) &ndash; initial
591
+ indentation in spaces
592
+ </li>
593
+ <li>
594
+ <code>indent_level: 4</code> (only applies when <code>beautify</code> is <code>true</code>) --
595
+ indentation level, in spaces (pass an even number)
596
+ </li>
597
+ <li>
598
+ <code>quote_keys: false</code> &ndash; if you pass <code>true</code> it will quote all keys in
599
+ literal objects
600
+ </li>
601
+ <li>
602
+ <code>space_colon: false</code> (only applies when <code>beautify</code> is <code>true</code>) &ndash; wether
603
+ to put a space before the colon in object literals
604
+ </li>
605
+ <li>
606
+ <code>ascii_only: false</code> &ndash; pass <code>true</code> if you want to encode non-ASCII
607
+ characters as <code>\uXXXX</code>.
608
+ </li>
609
+ </ul>
610
+ </li>
611
+ </ul>
612
+
613
+
614
+ </div>
615
+
616
+ </div>
617
+
618
+ <div id="outline-container-1_4_2" class="outline-4">
619
+ <h4 id="sec-1_4_2"><span class="section-number-4">1.4.2</span> Beautifier shortcoming &ndash; no more comments </h4>
620
+ <div class="outline-text-4" id="text-1_4_2">
621
+
622
+
623
+ <p>
624
+ The beautifier can be used as a general purpose indentation tool. It's
625
+ useful when you want to make a minified file readable. One limitation,
626
+ though, is that it discards all comments, so you don't really want to use it
627
+ to reformat your code, unless you don't have, or don't care about, comments.
628
+ </p>
629
+ <p>
630
+ In fact it's not the beautifier who discards comments &mdash; they are dumped at
631
+ the parsing stage, when we build the initial AST. Comments don't really
632
+ make sense in the AST, and while we could add nodes for them, it would be
633
+ inconvenient because we'd have to add special rules to ignore them at all
634
+ the processing stages.
635
+ </p>
636
+ </div>
637
+ </div>
638
+
639
+ </div>
640
+
641
+ <div id="outline-container-1_5" class="outline-3">
642
+ <h3 id="sec-1_5"><span class="section-number-3">1.5</span> Compression &ndash; how good is it? </h3>
643
+ <div class="outline-text-3" id="text-1_5">
644
+
645
+
646
+ <p>
647
+ (XXX: this is somewhat outdated. On the jQuery source code we beat Closure
648
+ by 168 bytes (560 after gzip) and by many seconds.)
649
+ </p>
650
+ <p>
651
+ There are a few popular JS minifiers nowadays &ndash; the two most well known
652
+ being the GoogleClosure (GCL) compiler and the YUI compressor. For some
653
+ reason they are both written in Java. I didn't really hope to beat any of
654
+ them, but finally I did &ndash; UglifyJS compresses better than the YUI
655
+ compressor, and safer than GoogleClosure.
656
+ </p>
657
+ <p>
658
+ I tested it on two big libraries. <a href="http://www.dynarchlib.com/">DynarchLIB</a> is my own, and it's big enough
659
+ to contain probably all the JavaScript tricks known to mankind. <a href="http://jquery.com/">jQuery</a> is
660
+ definitely the most popular JavaScript library (to some people, it's a
661
+ synonym to JavaScript itself).
662
+ </p>
663
+ <p>
664
+ I cannot swear that there are no bugs in the generated codes, but they
665
+ appear to work fine.
666
+ </p>
667
+ <p>
668
+ Compression results:
669
+ </p>
670
+ <table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
671
+ <caption></caption>
672
+ <colgroup><col align="left" /><col align="right" /><col align="right" /><col align="left" /><col align="left" />
673
+ </colgroup>
674
+ <thead>
675
+ <tr><th scope="col">Library</th><th scope="col">Orig. size</th><th scope="col">UglifyJS</th><th scope="col">YUI</th><th scope="col">GCL</th></tr>
676
+ </thead>
677
+ <tbody>
678
+ <tr><td>DynarchLIB</td><td>636896</td><td>241441</td><td>246452 (+5011)</td><td>240439 (-1002) (buggy)</td></tr>
679
+ <tr><td>jQuery</td><td>163855</td><td>72006</td><td>79702 (+7696)</td><td>71858 (-148)</td></tr>
680
+ </tbody>
681
+ </table>
682
+
683
+
684
+ <p>
685
+ UglifyJS is the fastest to run. On my laptop UglifyJS takes 1.35s for
686
+ DynarchLIB, while YUI takes 2.7s and GCL takes 6.5s.
687
+ </p>
688
+ <p>
689
+ GoogleClosure does a lot of smart ass optimizations. I had to strive really
690
+ hard to get close to it. It should be possible to even beat it, but then
691
+ again, GCL has a gazillion lines of code and runs terribly slow, so I'm not
692
+ sure it worths spending the effort to save a few bytes. Also, GCL doesn't
693
+ cope with <code>eval()</code> or <code>with{}</code> &ndash; it just dumps a warning and proceeds to
694
+ mangle names anyway; my DynarchLIB compiled with it is buggy because of
695
+ this.
696
+ </p>
697
+ <p>
698
+ UglifyJS consists of ~1100 lines of code for the tokenizer/parser, and ~1100
699
+ lines for the compressor and code generator. That should make it very
700
+ maintainable and easily extensible, so I would say it has a good place in
701
+ this field and it's bound to become the de-facto standard JS minifier. And
702
+ I shall rule the world. :-) Use it, and <b>spread the word</b>!
703
+ </p>
704
+ </div>
705
+
706
+ </div>
707
+
708
+ <div id="outline-container-1_6" class="outline-3">
709
+ <h3 id="sec-1_6"><span class="section-number-3">1.6</span> Bugs? </h3>
710
+ <div class="outline-text-3" id="text-1_6">
711
+
712
+
713
+ <p>
714
+ Unfortunately, for the time being there is no automated test suite. But I
715
+ ran the compressor manually on non-trivial code, and then I tested that the
716
+ generated code works as expected. A few hundred times.
717
+ </p>
718
+ <p>
719
+ DynarchLIB was started in times when there was no good JS minifier.
720
+ Therefore I was quite religious about trying to write short code manually,
721
+ and as such DL contains a lot of syntactic hacks<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> such as “foo == bar ? a
722
+ = 10 : b = 20”, though the more readable version would clearly be to use
723
+ “if/else”.
724
+ </p>
725
+ <p>
726
+ Since the parser/compressor runs fine on DL and jQuery, I'm quite confident
727
+ that it's solid enough for production use. If you can identify any bugs,
728
+ I'd love to hear about them (<a href="http://groups.google.com/group/uglifyjs">use the Google Group</a> or email me directly).
729
+ </p>
730
+ </div>
731
+
732
+ </div>
733
+
734
+ <div id="outline-container-1_7" class="outline-3">
735
+ <h3 id="sec-1_7"><span class="section-number-3">1.7</span> Links </h3>
736
+ <div class="outline-text-3" id="text-1_7">
737
+
738
+
739
+ <ul>
740
+ <li>
741
+ Project at GitHub: <a href="http://github.com/mishoo/UglifyJS">http://github.com/mishoo/UglifyJS</a>
742
+ </li>
743
+ <li>
744
+ Google Group: <a href="http://groups.google.com/group/uglifyjs">http://groups.google.com/group/uglifyjs</a>
745
+ </li>
746
+ <li>
747
+ Common Lisp JS parser: <a href="http://marijn.haverbeke.nl/parse-js/">http://marijn.haverbeke.nl/parse-js/</a>
748
+ </li>
749
+ <li>
750
+ JS-to-Lisp compiler: <a href="http://github.com/marijnh/js">http://github.com/marijnh/js</a>
751
+ </li>
752
+ <li>
753
+ Common Lisp JS uglifier: <a href="http://github.com/mishoo/cl-uglify-js">http://github.com/mishoo/cl-uglify-js</a>
754
+ </li>
755
+ </ul>
756
+
757
+
758
+ </div>
759
+
760
+ </div>
761
+
762
+ <div id="outline-container-1_8" class="outline-3">
763
+ <h3 id="sec-1_8"><span class="section-number-3">1.8</span> License </h3>
764
+ <div class="outline-text-3" id="text-1_8">
765
+
766
+
767
+ <p>
768
+ UglifyJS is released under the BSD license:
769
+ </p>
770
+
771
+
772
+
773
+ <pre class="example">Copyright 2010 (c) Mihai Bazon &lt;mihai.bazon@gmail.com&gt;
774
+ Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
775
+
776
+ Redistribution and use in source and binary forms, with or without
777
+ modification, are permitted provided that the following conditions
778
+ are met:
779
+
780
+ * Redistributions of source code must retain the above
781
+ copyright notice, this list of conditions and the following
782
+ disclaimer.
783
+
784
+ * Redistributions in binary form must reproduce the above
785
+ copyright notice, this list of conditions and the following
786
+ disclaimer in the documentation and/or other materials
787
+ provided with the distribution.
788
+
789
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
790
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
791
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
792
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
793
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
794
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
795
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
796
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
797
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
798
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
799
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
800
+ SUCH DAMAGE.
801
+ </pre>
802
+
803
+
804
+
805
+
806
+ </div>
807
+ </div>
808
+ </div>
809
+ <div id="footnotes">
810
+ <h2 class="footnotes">Footnotes: </h2>
811
+ <div id="text-footnotes">
812
+ <p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> I even reported a few bugs and suggested some fixes in the original
813
+ <a href="http://marijn.haverbeke.nl/parse-js/">parse-js</a> library, and Marijn pushed fixes literally in minutes.
814
+ </p>
815
+ </div>
816
+ </div>
817
+ <div id="postamble">
818
+ <p class="author"> Author: Mihai Bazon
819
+ </p>
820
+ <p class="date"> Date: 2011-04-04 00:07:13 EEST</p>
821
+ <p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p>
822
+ </div>
823
+ </div>
824
+ </body>
825
+ </html>