Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Replace build system with a faster new one that uses Node and UglifyJ…

…S and generates smaller minified files. Also removes builds through rake/ant since having 3 different build systems was too much to maintain (make was the only one consistently kept up-to-date). Fixes #7973.
  • Loading branch information...
commit d503845d0cf45632c0d7c3542ffd1b19257a8e5e 1 parent 9c76ac4
Colin Snover authored January 17, 2011
15  Makefile
@@ -7,11 +7,8 @@ BUILD_DIR = build
7 7
 PREFIX = .
8 8
 DIST_DIR = ${PREFIX}/dist
9 9
 
10  
-RHINO ?= java -jar ${BUILD_DIR}/js.jar
11  
-
12  
-CLOSURE_COMPILER = ${BUILD_DIR}/google-compiler-20100917.jar
13  
-
14  
-MINJAR ?= java -jar ${CLOSURE_COMPILER}
  10
+JS_ENGINE ?= node
  11
+COMPILER = ${JS_ENGINE} ${BUILD_DIR}/uglify.js --unsafe
15 12
 
16 13
 BASE_FILES = ${SRC_DIR}/core.js\
17 14
 	${SRC_DIR}/support.js\
@@ -93,17 +90,13 @@ ${SRC_DIR}/selector.js: ${SIZZLE_DIR}/sizzle.js
93 90
 
94 91
 lint: ${JQ}
95 92
 	@@echo "Checking jQuery against JSLint..."
96  
-	@@${RHINO} build/jslint-check.js
  93
+	@@${JS_ENGINE} build/jslint-check.js
97 94
 
98 95
 min: ${JQ_MIN}
99 96
 
100 97
 ${JQ_MIN}: ${JQ}
101 98
 	@@echo "Building" ${JQ_MIN}
102  
-
103  
-	@@head -15 ${JQ} > ${JQ_MIN}
104  
-	@@${MINJAR} --js ${JQ} --warning_level QUIET --js_output_file ${JQ_MIN}.tmp
105  
-	@@cat ${JQ_MIN}.tmp >> ${JQ_MIN}
106  
-	@@rm -f ${JQ_MIN}.tmp
  99
+	@@${COMPILER} ${JQ} > ${JQ_MIN}
107 100
 
108 101
 clean:
109 102
 	@@echo "Removing Distribution directory:" ${DIST_DIR}
95  README.md
Source Rendered
... ...
@@ -1,85 +1,64 @@
1 1
 [jQuery](http://jquery.com/) - New Wave Javascript
2  
-================================
  2
+==================================================
3 3
 
4 4
 What you need to build your own jQuery
5  
----------------------------------------
6  
-* Make sure that you have Java installed (if you want to build a minified version of jQuery).  
7  
-If not, [go to this page](http://java.sun.com/javase/downloads/index.jsp) and download "Java Runtime Environment (JRE) 5.0"
  5
+--------------------------------------
8 6
 
9  
-Build Options
10  
---------------
  7
+In order to build jQuery, you need to have GNU make 3.8 or later, Node.js 0.2 or later, and git 1.7 or later.
  8
+(Earlier versions might work OK, but are not tested.)
11 9
 
12  
-You now have **three** options for building jQuery:
  10
+Windows users have two options:
13 11
 
14  
-* **`make`**: If you have access to common UNIX commands (like `make`, `mkdir`, `rm`, `cat`, and `echo`) then simply type `make` to build all the components.
  12
+1. Install [msysgit](https://code.google.com/p/msysgit/) (Full installer for official Git),
  13
+   [GNU make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm), and a
  14
+   [binary version of Node.js](http://node-js.prcn.co.cc/). Make sure all three packages are installed to the same
  15
+   location (by default, this is C:\Program Files\Git).
  16
+2. Install [Cygwin](http://cygwin.com/) (remember to install the git and make packages) and follow the
  17
+   [Node.js build instructions](https://github.com/ry/node/wiki/Building-node.js-on-Cygwin-%28Windows%29) or install
  18
+   the [binary version of Node.js](http://node-js.prcn.co.cc/).
15 19
 
16  
-* **`rake`**: If you have Ruby Rake installed (on either Windows or UNIX/Linux), you can simply type `rake` to build all the components.
  20
+Mac OS users should install Xcode (comes on your Mac OS install DVD, or downloadable from
  21
+[Apple's Xcode site](http://developer.apple.com/technologies/xcode.html)) and
  22
+[http://mxcl.github.com/homebrew/](Homebrew). Once Homebrew is installed, run `brew install git` to install git,
  23
+and `brew install node` to install Node.js.
17 24
 
18  
-* **`ant`**: If you have Ant installed (or are on Windows and don't have access to make). You can download Ant from here: [http://ant.apache.org/bindownload.cgi].
  25
+Linux/BSD users should use their appropriate package managers to install make, git, and node, or build from source
  26
+if you swing that way. Easy-peasy.
19 27
 
20  
-How to build your own jQuery
21  
------------------------------
22  
-
23  
-*Note: If you are using either `rake` or `ant`, substitute your chosen method in place of `make` in the examples below. They work identically for all intents and purposes. Quick reference is also available for `rake` by typing `rake -T` in the `jquery` directory.*
24  
-
25  
-In the main directory of the distribution (the one that this file is in), type
26  
-the following to make all versions of jQuery:
27  
-
28  
-    make
29  
-
30  
-*Here are the individual items that are buildable from the Makefile:*
31  
-
32  
-    make init
33 28
 
34  
-Pull in all the external dependencies (QUnit, Sizzle) for the project.
35  
-
36  
-    make jquery
37  
-
38  
-The standard, uncompressed, jQuery code.  
39  
-Makes: `./dist/jquery.js`
40  
-
41  
-    make min
42  
-
43  
-A compressed version of jQuery (made the Closure Compiler).  
44  
-Makes: `./dist/jquery.min.js`
  29
+How to build your own jQuery
  30
+----------------------------
45 31
 
46  
-    make lint
  32
+First, clone a copy of the main jQuery git repo by running `git clone git://github.com/jquery/jquery.git`.
47 33
 
48  
-Tests a build of jQuery against JSLint, looking for potential errors or bits of confusing code.
  34
+Then, to get a complete, minified, jslinted version of jQuery, simply `cd` to the `jquery` directory and type
  35
+`make`. If you don't have Node installed and/or want to make a basic, uncompressed, unlinted version of jQuery, use
  36
+`make jquery` instead of `make`.
49 37
 
50  
-    make selector
  38
+The built version of jQuery will be put in the `dist/` subdirectory.
51 39
 
52  
-Builds the selector library for jQuery from Sizzle.  
53  
-Makes: `./src/selector.js`
  40
+To remove all built files, run `make clean`.
54 41
 
55  
-Finally, you can remove all the built files using the command:
56  
-  
57  
-    make clean
58 42
 
59 43
 Building to a different directory
60  
-----------------------------------
  44
+---------------------------------
61 45
 
62  
-If you want to build jQuery to a directory that is different from the default location, you can...
  46
+If you want to build jQuery to a directory that is different from the default location, you can specify the PREFIX
  47
+directory: `make PREFIX=/home/jquery/test/ [command]`
63 48
 
64  
-**Make only:** Specify the PREFIX directory, for example:
65  
-  
66  
-    make PREFIX=/home/john/test/ [command]
67  
-    
68  
-With this example, the output files would be contained in `/home/john/test/dist/`
  49
+With this example, the output files would end up in `/home/jquery/test/dist/`.
69 50
 
70  
-**Rake only:** Define the DIST_DIR directory, for example:
71 51
 
72  
-    rake DIST_DIR=/home/john/test/ [command]
73  
-    
74  
-With this example, the output files would be contained in `/home/john/test/`
  52
+Troubleshooting
  53
+---------------
75 54
 
76  
-*In both examples, `[command]` is optional.*
  55
+Sometimes, the various git repositories get into an inconsistent state where builds don't complete properly
  56
+(usually this results in the jquery.js or jquery.min.js being 0 bytes). If this happens, run `make clean`, then
  57
+run `make` again.
77 58
 
78  
-**Ant only:** You cannot currently build to another directory when using Ant.
79 59
 
80 60
 Questions?
81 61
 ----------
82 62
 
83  
-If you have any questions, please feel free to ask them on the Developing jQuery Core
84  
-forum, which can be found here:  
85  
-[http://forum.jquery.com/developing-jquery-core](http://forum.jquery.com/developing-jquery-core)
  63
+If you have any questions, please feel free to ask on the
  64
+[Developing jQuery Core forum](http://forum.jquery.com/developing-jquery-core) or in #jquery on irc.freenode.net.
162  Rakefile
... ...
@@ -1,162 +0,0 @@
1  
-prefix    = File.dirname( __FILE__ )
2  
-
3  
-# Directory variables
4  
-src_dir   = File.join( prefix, 'src' )
5  
-build_dir = File.join( prefix, 'build' )
6  
-test_dir  = File.join( prefix, 'test' )
7  
-
8  
-# A different destination directory can be set by
9  
-# setting DIST_DIR before calling rake
10  
-dist_dir  = ENV['DIST_DIR'] || File.join( prefix, 'dist' )
11  
-
12  
-base_files = %w{
13  
-  intro
14  
-  core
15  
-  support
16  
-  data
17  
-  queue
18  
-  attributes
19  
-  event
20  
-  selector
21  
-  traversing
22  
-  manipulation
23  
-  css
24  
-  ajax
25  
-  ajax/jsonp
26  
-  ajax/script
27  
-  ajax/xhr
28  
-  effects
29  
-  offset
30  
-  dimensions
31  
-  outro
32  
-}.map { |js| File.join( src_dir, "#{js}.js" ) }
33  
-
34  
-# Sizzle, QUnit and jQuery files/dirs
35  
-sizzle_dir = File.join( src_dir, "sizzle" )
36  
-sizzle     = File.join( sizzle_dir, "sizzle.js" )
37  
-selector   = File.join( src_dir, "selector.js" )
38  
-
39  
-qunit_dir  = File.join( test_dir, "qunit" )
40  
-qunit      = File.join( qunit_dir, "qunit", "qunit.js" )
41  
-
42  
-jq         = File.join( dist_dir, "jquery.js" )
43  
-jq_min     = File.join( dist_dir, "jquery.min.js" )
44  
-
45  
-# General Variables
46  
-date       = `git log -1`[/^Date:\s+(.+)$/, 1]
47  
-version    = File.read( File.join( prefix, 'version.txt' ) ).strip
48  
-
49  
-# Build tools
50  
-rhino      = "java -jar #{build_dir}/js.jar"
51  
-minfier    = "java -jar #{build_dir}/google-compiler-20100917.jar"
52  
-
53  
-# Turn off output other than needed from `sh` and file commands
54  
-verbose(false)
55  
-
56  
-# Tasks
57  
-task :default => "all"
58  
-
59  
-desc "Builds jQuery; Tests with JSLint; Minifies jQuery"
60  
-task :all => [:jquery, :lint, :min] do
61  
-  puts "jQuery build complete."
62  
-end
63  
-
64  
-desc "Builds jQuery: jquery.js (Default task)"
65  
-task :jquery => [:selector, jq]
66  
-
67  
-desc "Builds a minified version of jQuery: jquery.min.js"
68  
-task :min => jq_min
69  
-
70  
-
71  
-task :init => [sizzle, qunit] do
72  
-  sizzle_git = File.join(sizzle_dir, '.git')
73  
-  qunit_git  = File.join(qunit_dir,  '.git')
74  
-
75  
-  puts "Updating SizzleJS with latest..."
76  
-	sh "git --git-dir=#{sizzle_git} pull -q origin master"
77  
-
78  
-  puts "Updating QUnit with latest..."
79  
-	sh "git --git-dir=#{qunit_git} pull -q origin master"
80  
-end
81  
-
82  
-desc "Removes dist folder, selector.js, and Sizzle/QUnit"
83  
-task :clean do
84  
-  puts "Removing Distribution directory: #{dist_dir}..."
85  
-  rm_rf dist_dir
86  
-
87  
-  puts "Removing built copy of Sizzle..."
88  
-  rm_rf selector
89  
-
90  
-  puts "Removing cloned directories..."
91  
-  rm_rf qunit_dir
92  
-  rm_rf sizzle_dir
93  
-end
94  
-
95  
-desc "Rebuilds selector.js from SizzleJS"
96  
-task :selector => [:init, selector]
97  
-
98  
-desc "Tests built jquery.js against JSLint"
99  
-task :lint => jq do
100  
-  puts "Checking jQuery against JSLint..."
101  
-  sh "#{rhino} " + File.join(build_dir, 'jslint-check.js')
102  
-end
103  
-
104  
-
105  
-# File and Directory Dependencies
106  
-directory dist_dir
107  
-
108  
-file jq => [dist_dir, base_files].flatten do
109  
-  puts "Building jquery.js..."
110  
-
111  
-  File.open(jq, 'w') do |f|
112  
-    f.write cat(base_files).
113  
-      gsub(/@DATE/, date).
114  
-      gsub(/@VERSION/, version).
115  
-      gsub(/.function..jQuery...\{/, '').
116  
-      gsub(/\}...jQuery..;/, '')
117  
-  end
118  
-end
119  
-
120  
-file jq_min => jq do
121  
-  puts "Building jquery.min.js..."
122  
-
123  
-  sh "#{minfier} --js #{jq} --warning_level QUIET --js_output_file #{jq_min}"
124  
-
125  
-  min = File.read( jq_min )
126  
-
127  
-  # Equivilent of "head"
128  
-  File.open(jq_min, 'w') do |f|
129  
-    f.write File.readlines(jq)[0..14].join()
130  
-    f.write min
131  
-  end
132  
-end
133  
-
134  
-file selector => [sizzle, :init] do
135  
-  puts "Building selector code from Sizzle..."
136  
-
137  
-  File.open(selector, 'w') do |f|
138  
-    f.write File.read(sizzle).gsub(
139  
-      /^.+EXPOSE$\n/,
140  
-      '\0' + File.read( File.join( src_dir, 'sizzle-jquery.js' ))
141  
-    ).gsub(
142  
-      /^window.Sizzle.+$\n/, ''
143  
-    )
144  
-  end
145  
-end
146  
-
147  
-file sizzle do
148  
-  puts "Retrieving SizzleJS from Github..."
149  
-  sh "git clone git://github.com/jeresig/sizzle.git #{sizzle_dir}"
150  
-end
151  
-
152  
-file qunit do
153  
-  puts "Retrieving QUnit from Github..."
154  
-  sh "git clone git://github.com/jquery/qunit.git #{qunit_dir}"
155  
-end
156  
-
157  
-
158  
-def cat( files )
159  
-  files.map do |file|
160  
-    File.read(file)
161  
-  end.join('')
162  
-end
132  build.xml
... ...
@@ -1,132 +0,0 @@
1  
-<project name="jQuery" default="all" basedir=".">
2  
-
3  
-	<loadfile property="version" srcfile="version.txt" />
4  
-	<property name="PREFIX" value="." />
5  
-	<property description="Folder for jquery and min target" name="dist" value="${PREFIX}/dist" />
6  
-
7  
-	<property name="JQ" value="${dist}/jquery.js" />
8  
-	<property name="JQ_MIN" value="${dist}/jquery.min.js" />
9  
-
10  
-	<loadfile property="sizzle-exports" srcfile="src/sizzle-jquery.js" />
11  
-
12  
-	<available property="qunit" file="test/qunit" />
13  
-	<available property="sizzle" file="src/sizzle" />
14  
-
15  
-	<target name="all" depends="jquery,lint,min" />
16  
-
17  
-	<target name="qunit-clone" unless="qunit">
18  
-		<exec executable="git" outputproperty="git-qunit" >
19  
-			<arg line="clone git://github.com/jquery/qunit.git test/qunit" />
20  
-		</exec>
21  
-		<echo message="git clone qunit: ${git-qunit}" />
22  
-	</target>
23  
-	<target name="qunit-pull" if="qunit">
24  
-		<exec executable="git" outputproperty="git-qunit" dir="test/qunit" >
25  
-			<arg line="pull origin master" />
26  
-		</exec>
27  
-		<echo message="git pull sizzle: ${git-qunit}" />
28  
-	</target>
29  
-	<target name="sizzle-clone" unless="sizzle">
30  
-		<exec executable="git" outputproperty="git-sizzle" >
31  
-			<arg line="clone git://github.com/jeresig/sizzle.git src/sizzle" />
32  
-		</exec>
33  
-		<echo message="git clone sizzle: ${git-sizzle}" />
34  
-	</target>
35  
-	<target name="sizzle-pull" if="sizzle">
36  
-		<exec executable="git" outputproperty="git-sizzle" dir="src/sizzle" >
37  
-			<arg line="pull origin master" />
38  
-		</exec>
39  
-		<echo message="git pull sizzle: ${git-sizzle}" />
40  
-	</target>
41  
-
42  
-	<target name="init" depends="qunit-clone,qunit-pull,sizzle-clone,sizzle-pull" />
43  
-
44  
-	<target name="selector" depends="init" description="Builds the selector library for jQuery from Sizzle.">
45  
-		<copy file="src/sizzle/sizzle.js" tofile="src/selector.js" overwrite="true" />
46  
-		<replaceregexp match="// EXPOSE(.*)&#10;" replace="// EXPOSE\1&#10;${sizzle-exports}" file="src/selector.js" />
47  
-		<replaceregexp match="window.Sizzle(.*)&#10;" replace="" file="src/selector.js" />
48  
-	</target>
49  
-
50  
-	<target name="jquery" depends="init,selector" description="Main jquery build, concatenates source files and replaces @VERSION">
51  
-		<echo message="Building ${JQ}" />
52  
-		<mkdir dir="${dist}" />
53  
-		<concat destfile="${JQ}">
54  
-			<fileset file="src/intro.js" />
55  
-			<fileset file="src/core.js" />
56  
-			<fileset file="src/support.js" />
57  
-			<fileset file="src/data.js" />
58  
-			<fileset file="src/queue.js" />
59  
-			<fileset file="src/attributes.js" />
60  
-			<fileset file="src/event.js" />
61  
-			<fileset file="src/selector.js" />
62  
-			<fileset file="src/traversing.js" />
63  
-			<fileset file="src/manipulation.js" />
64  
-			<fileset file="src/css.js" />
65  
-			<fileset file="src/ajax.js" />
66  
-			<fileset file="src/ajax/jsonp.js" />
67  
-			<fileset file="src/ajax/script.js" />
68  
-			<fileset file="src/ajax/xhr.js" />
69  
-			<fileset file="src/effects.js" />
70  
-			<fileset file="src/offset.js" />
71  
-			<fileset file="src/dimensions.js" />
72  
-			<fileset file="src/outro.js" />
73  
-		</concat>
74  
-		<replaceregexp match="@VERSION" replace="${version}" flags="g" byline="true" file="${JQ}" />
75  
-		<exec executable="git" outputproperty="date">
76  
-			<arg line="log -1 --pretty=format:%ad" />
77  
-		</exec>
78  
-		<replaceregexp match="(\(\s*function\s*\(\s*jQuery\s*\)\s*\{)|(\}\s*\)\s*\(\s*jQuery\s*\)\s*;)" flags="g" replace="" file="${JQ}" />
79  
-		<replaceregexp match="@DATE" replace="${date}" file="${JQ}" />
80  
-		<echo message="${JQ} built." />
81  
-	</target>
82  
-
83  
-	<target name="lint" depends="jquery" description="Check jQuery against JSLint">
84  
-		<exec executable="java">
85  
-			<arg line="-jar build/js.jar build/jslint-check.js" />
86  
-		</exec>
87  
-	</target>
88  
-
89  
-	<target name="min" depends="jquery" description="Remove all comments and whitespace, no compression, great in combination with GZip">
90  
-		<echo message="Building ${JQ_MIN}" />
91  
-		<apply executable="java" parallel="false" verbose="true" dest="${dist}">
92  
-			<fileset dir="${dist}">
93  
-				<include name="jquery.js" />
94  
-			</fileset>
95  
-			<arg line="-jar" />
96  
-			<arg path="build/google-compiler-20100917.jar" />
97  
-			<arg value="--warning_level" />
98  
-			<arg value="QUIET" />
99  
-			<arg value="--js_output_file" />
100  
-			<targetfile />
101  
-			<arg value="--js" />
102  
-			<mapper type="glob" from="jquery.js" to="tmpmin" />
103  
-		</apply>
104  
-		<concat destfile="${JQ_MIN}">
105  
-			<filelist files="${JQ}, ${dist}/tmpmin" />
106  
-			<filterchain>
107  
-				<headfilter lines="15" />
108  
-			</filterchain>
109  
-		</concat>
110  
-		<concat destfile="${JQ_MIN}" append="yes">
111  
-			<filelist files="${dist}/tmpmin" />
112  
-		</concat>
113  
-		<delete file="${dist}/tmpmin" />
114  
-		<echo message="${JQ_MIN} built." />
115  
-	</target>
116  
-
117  
-	<target name="clean">
118  
-		<delete dir="${dist}" />
119  
-		<delete file="src/selector.js" />
120  
-		<delete dir="test/qunit" />
121  
-		<delete dir="src/sizzle" />
122  
-	</target>
123  
-
124  
-	<target name="openAjaxMetadata">
125  
-		<property name="target" value="openAjaxMetadata-jquery-${version}.xml" />
126  
-		<delete file="${dist}/jquery-*.xml" />
127  
-		<get src="http://www.exfer.net/jquery/createjQueryXMLDocs.py?version=1.3" dest="${target}" />
128  
-		<xslt includes="${target}" excludes="build.xml" destdir="./dist" style="build/style.xsl" extension=".xml" />
129  
-		<delete file="${target}" />
130  
-	</target>
131  
-
132  
-</project>
BIN  build/google-compiler-20100917.jar
Binary file not shown
BIN  build/js.jar
Binary file not shown
10  build/jslint-check.js
... ...
@@ -1,6 +1,6 @@
1  
-load("build/jslint.js");
2  
-
3  
-var src = readFile("dist/jquery.js");
  1
+var JSLINT = require("./lib/jslint").JSLINT,
  2
+	print = require("sys").print,
  3
+	src = require("fs").readFileSync("dist/jquery.js", "utf8");
4 4
 
5 5
 JSLINT(src, { evil: true, forin: true, maxerr: 100 });
6 6
 
@@ -29,8 +29,8 @@ for ( var i = 0; i < e.length; i++ ) {
29 29
 }
30 30
 
31 31
 if ( found > 0 ) {
32  
-	print( "\n" + found + " Error(s) found." );
  32
+	print( "\n" + found + " Error(s) found.\n" );
33 33
 
34 34
 } else {
35  
-	print( "JSLint check passed." );
  35
+	print( "JSLint check passed.\n" );
36 36
 }
6  build/jslint.js → build/lib/jslint.js
@@ -5495,6 +5495,10 @@ loop:   for (;;) {
5495 5495
 
5496 5496
     itself.edition = '2010-02-20';
5497 5497
 
  5498
+    if (typeof exports !== "undefined") {
  5499
+        exports.JSLINT = itself;
  5500
+    }
  5501
+
5498 5502
     return itself;
5499 5503
 
5500  
-}());
  5504
+}());
1,239  build/lib/parse-js.js
... ...
@@ -0,0 +1,1239 @@
  1
+/***********************************************************************
  2
+
  3
+  A JavaScript tokenizer / parser / beautifier / compressor.
  4
+
  5
+  This version is suitable for Node.js.  With minimal changes (the
  6
+  exports stuff) it should work on any JS platform.
  7
+
  8
+  This file contains the tokenizer/parser.  It is a port to JavaScript
  9
+  of parse-js [1], a JavaScript parser library written in Common Lisp
  10
+  by Marijn Haverbeke.  Thank you Marijn!
  11
+
  12
+  [1] http://marijn.haverbeke.nl/parse-js/
  13
+
  14
+  Exported functions:
  15
+
  16
+    - tokenizer(code) -- returns a function.  Call the returned
  17
+      function to fetch the next token.
  18
+
  19
+    - parse(code) -- returns an AST of the given JavaScript code.
  20
+
  21
+  -------------------------------- (C) ---------------------------------
  22
+
  23
+                           Author: Mihai Bazon
  24
+                         <mihai.bazon@gmail.com>
  25
+                       http://mihai.bazon.net/blog
  26
+
  27
+  Distributed under the BSD license:
  28
+
  29
+    Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
  30
+    Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
  31
+
  32
+    Redistribution and use in source and binary forms, with or without
  33
+    modification, are permitted provided that the following conditions
  34
+    are met:
  35
+
  36
+        * Redistributions of source code must retain the above
  37
+          copyright notice, this list of conditions and the following
  38
+          disclaimer.
  39
+
  40
+        * Redistributions in binary form must reproduce the above
  41
+          copyright notice, this list of conditions and the following
  42
+          disclaimer in the documentation and/or other materials
  43
+          provided with the distribution.
  44
+
  45
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
  46
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  48
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  49
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  50
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  51
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  52
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  53
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  54
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  55
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  56
+    SUCH DAMAGE.
  57
+
  58
+ ***********************************************************************/
  59
+
  60
+/* -----[ Tokenizer (constants) ]----- */
  61
+
  62
+var KEYWORDS = array_to_hash([
  63
+        "break",
  64
+        "case",
  65
+        "catch",
  66
+        "const",
  67
+        "continue",
  68
+        "default",
  69
+        "delete",
  70
+        "do",
  71
+        "else",
  72
+        "finally",
  73
+        "for",
  74
+        "function",
  75
+        "if",
  76
+        "in",
  77
+        "instanceof",
  78
+        "new",
  79
+        "return",
  80
+        "switch",
  81
+        "throw",
  82
+        "try",
  83
+        "typeof",
  84
+        "var",
  85
+        "void",
  86
+        "while",
  87
+        "with"
  88
+]);
  89
+
  90
+var RESERVED_WORDS = array_to_hash([
  91
+        "abstract",
  92
+        "boolean",
  93
+        "byte",
  94
+        "char",
  95
+        "class",
  96
+        "debugger",
  97
+        "double",
  98
+        "enum",
  99
+        "export",
  100
+        "extends",
  101
+        "final",
  102
+        "float",
  103
+        "goto",
  104
+        "implements",
  105
+        "import",
  106
+        "int",
  107
+        "interface",
  108
+        "long",
  109
+        "native",
  110
+        "package",
  111
+        "private",
  112
+        "protected",
  113
+        "public",
  114
+        "short",
  115
+        "static",
  116
+        "super",
  117
+        "synchronized",
  118
+        "throws",
  119
+        "transient",
  120
+        "volatile"
  121
+]);
  122
+
  123
+var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
  124
+        "return",
  125
+        "new",
  126
+        "delete",
  127
+        "throw",
  128
+        "else",
  129
+        "case"
  130
+]);
  131
+
  132
+var KEYWORDS_ATOM = array_to_hash([
  133
+        "false",
  134
+        "null",
  135
+        "true",
  136
+        "undefined"
  137
+]);
  138
+
  139
+var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
  140
+
  141
+var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
  142
+var RE_OCT_NUMBER = /^0[0-7]+$/;
  143
+var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
  144
+
  145
+var OPERATORS = array_to_hash([
  146
+        "in",
  147
+        "instanceof",
  148
+        "typeof",
  149
+        "new",
  150
+        "void",
  151
+        "delete",
  152
+        "++",
  153
+        "--",
  154
+        "+",
  155
+        "-",
  156
+        "!",
  157
+        "~",
  158
+        "&",
  159
+        "|",
  160
+        "^",
  161
+        "*",
  162
+        "/",
  163
+        "%",
  164
+        ">>",
  165
+        "<<",
  166
+        ">>>",
  167
+        "<",
  168
+        ">",
  169
+        "<=",
  170
+        ">=",
  171
+        "==",
  172
+        "===",
  173
+        "!=",
  174
+        "!==",
  175
+        "?",
  176
+        "=",
  177
+        "+=",
  178
+        "-=",
  179
+        "/=",
  180
+        "*=",
  181
+        "%=",
  182
+        ">>=",
  183
+        "<<=",
  184
+        ">>>=",
  185
+        "~=",
  186
+        "%=",
  187
+        "|=",
  188
+        "^=",
  189
+        "&=",
  190
+        "&&",
  191
+        "||"
  192
+]);
  193
+
  194
+var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t"));
  195
+
  196
+var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
  197
+
  198
+var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
  199
+
  200
+var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
  201
+
  202
+/* -----[ Tokenizer ]----- */
  203
+
  204
+function is_alphanumeric_char(ch) {
  205
+        ch = ch.charCodeAt(0);
  206
+        return (ch >= 48 && ch <= 57) ||
  207
+                (ch >= 65 && ch <= 90) ||
  208
+                (ch >= 97 && ch <= 122);
  209
+};
  210
+
  211
+function is_identifier_char(ch) {
  212
+        return is_alphanumeric_char(ch) || ch == "$" || ch == "_";
  213
+};
  214
+
  215
+function is_digit(ch) {
  216
+        ch = ch.charCodeAt(0);
  217
+        return ch >= 48 && ch <= 57;
  218
+};
  219
+
  220
+function parse_js_number(num) {
  221
+        if (RE_HEX_NUMBER.test(num)) {
  222
+                return parseInt(num.substr(2), 16);
  223
+        } else if (RE_OCT_NUMBER.test(num)) {
  224
+                return parseInt(num.substr(1), 8);
  225
+        } else if (RE_DEC_NUMBER.test(num)) {
  226
+                return parseFloat(num);
  227
+        }
  228
+};
  229
+
  230
+function JS_Parse_Error(message, line, col, pos) {
  231
+        this.message = message;
  232
+        this.line = line;
  233
+        this.col = col;
  234
+        this.pos = pos;
  235
+        try {
  236
+                ({})();
  237
+        } catch(ex) {
  238
+                this.stack = ex.stack;
  239
+        };
  240
+};
  241
+
  242
+JS_Parse_Error.prototype.toString = function() {
  243
+        return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
  244
+};
  245
+
  246
+function js_error(message, line, col, pos) {
  247
+        throw new JS_Parse_Error(message, line, col, pos);
  248
+};
  249
+
  250
+function is_token(token, type, val) {
  251
+        return token.type == type && (val == null || token.value == val);
  252
+};
  253
+
  254
+var EX_EOF = {};
  255
+
  256
+function tokenizer($TEXT, skip_comments) {
  257
+
  258
+        var S = {
  259
+                text           : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
  260
+                pos            : 0,
  261
+                tokpos         : 0,
  262
+                line           : 0,
  263
+                tokline        : 0,
  264
+                col            : 0,
  265
+                tokcol         : 0,
  266
+                newline_before : false,
  267
+                regex_allowed  : false
  268
+        };
  269
+
  270
+        function peek() { return S.text.charAt(S.pos); };
  271
+
  272
+        function next(signal_eof) {
  273
+                var ch = S.text.charAt(S.pos++);
  274
+                if (signal_eof && !ch)
  275
+                        throw EX_EOF;
  276
+                if (ch == "\n") {
  277
+                        S.newline_before = true;
  278
+                        ++S.line;
  279
+                        S.col = 0;
  280
+                } else {
  281
+                        ++S.col;
  282
+                }
  283
+                return ch;
  284
+        };
  285
+
  286
+        function eof() {
  287
+                return !S.peek();
  288
+        };
  289
+
  290
+        function find(what, signal_eof) {
  291
+                var pos = S.text.indexOf(what, S.pos);
  292
+                if (signal_eof && pos == -1) throw EX_EOF;
  293
+                return pos;
  294
+        };
  295
+
  296
+        function start_token() {
  297
+                S.tokline = S.line;
  298
+                S.tokcol = S.col;
  299
+                S.tokpos = S.pos;
  300
+        };
  301
+
  302
+        function token(type, value) {
  303
+                S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
  304
+                                   (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
  305
+                                   (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
  306
+                var ret = {
  307
+                        type  : type,
  308
+                        value : value,
  309
+                        line  : S.tokline,
  310
+                        col   : S.tokcol,
  311
+                        pos   : S.tokpos,
  312
+                        nlb   : S.newline_before
  313
+                };
  314
+                S.newline_before = false;
  315
+                return ret;
  316
+        };
  317
+
  318
+        function skip_whitespace() {
  319
+                while (HOP(WHITESPACE_CHARS, peek()))
  320
+                        next();
  321
+        };
  322
+
  323
+        function read_while(pred) {
  324
+                var ret = "", ch = peek(), i = 0;
  325
+                while (ch && pred(ch, i++)) {
  326
+                        ret += next();
  327
+                        ch = peek();
  328
+                }
  329
+                return ret;
  330
+        };
  331
+
  332
+        function parse_error(err) {
  333
+                js_error(err, S.tokline, S.tokcol, S.tokpos);
  334
+        };
  335
+
  336
+        function read_num(prefix) {
  337
+                var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
  338
+                var num = read_while(function(ch, i){
  339
+                        if (ch == "x" || ch == "X") {
  340
+                                if (has_x) return false;
  341
+                                return has_x = true;
  342
+                        }
  343
+                        if (!has_x && (ch == "E" || ch == "e")) {
  344
+                                if (has_e) return false;
  345
+                                return has_e = after_e = true;
  346
+                        }
  347
+                        if (ch == "-") {
  348
+                                if (after_e || (i == 0 && !prefix)) return true;
  349
+                                return false;
  350
+                        }
  351
+                        if (ch == "+") return after_e;
  352
+                        after_e = false;
  353
+                        if (ch == ".") {
  354
+                                if (!has_dot)
  355
+                                        return has_dot = true;
  356
+                                return false;
  357
+                        }
  358
+                        return is_alphanumeric_char(ch);
  359
+                });
  360
+                if (prefix)
  361
+                        num = prefix + num;
  362
+                var valid = parse_js_number(num);
  363
+                if (!isNaN(valid)) {
  364
+                        return token("num", valid);
  365
+                } else {
  366
+                        parse_error("Invalid syntax: " + num);
  367
+                }
  368
+        };
  369
+
  370
+        function read_escaped_char() {
  371
+                var ch = next(true);
  372
+                switch (ch) {
  373
+                    case "n" : return "\n";
  374
+                    case "r" : return "\r";
  375
+                    case "t" : return "\t";
  376
+                    case "b" : return "\b";
  377
+                    case "v" : return "\v";
  378
+                    case "f" : return "\f";
  379
+                    case "0" : return "\0";
  380
+                    case "x" : return String.fromCharCode(hex_bytes(2));
  381
+                    case "u" : return String.fromCharCode(hex_bytes(4));
  382
+                    default  : return ch;
  383
+                }
  384
+        };
  385
+
  386
+        function hex_bytes(n) {
  387
+                var num = 0;
  388
+                for (; n > 0; --n) {
  389
+                        var digit = parseInt(next(true), 16);
  390
+                        if (isNaN(digit))
  391
+                                parse_error("Invalid hex-character pattern in string");
  392
+                        num = (num << 4) | digit;
  393
+                }
  394
+                return num;
  395
+        };
  396
+
  397
+        function read_string() {
  398
+                return with_eof_error("Unterminated string constant", function(){
  399
+                        var quote = next(), ret = "";
  400
+                        for (;;) {
  401
+                                var ch = next(true);
  402
+                                if (ch == "\\") ch = read_escaped_char();
  403
+                                else if (ch == quote) break;
  404
+                                ret += ch;
  405
+                        }
  406
+                        return token("string", ret);
  407
+                });
  408
+        };
  409
+
  410
+        function read_line_comment() {
  411
+                next();
  412
+                var i = find("\n"), ret;
  413
+                if (i == -1) {
  414
+                        ret = S.text.substr(S.pos);
  415
+                        S.pos = S.text.length;
  416
+                } else {
  417
+                        ret = S.text.substring(S.pos, i);
  418
+                        S.pos = i;
  419
+                }
  420
+                return token("comment1", ret);
  421
+        };
  422
+
  423
+        function read_multiline_comment() {
  424
+                next();
  425
+                return with_eof_error("Unterminated multiline comment", function(){
  426
+                        var i = find("*/", true),
  427
+                            text = S.text.substring(S.pos, i),
  428
+                            tok = token("comment2", text);
  429
+                        S.pos = i + 2;
  430
+                        S.line += text.split("\n").length - 1;
  431
+                        S.newline_before = text.indexOf("\n") >= 0;
  432
+                        return tok;
  433
+                });
  434
+        };
  435
+
  436
+        function read_regexp() {
  437
+                return with_eof_error("Unterminated regular expression", function(){
  438
+                        var prev_backslash = false, regexp = "", ch, in_class = false;
  439
+                        while ((ch = next(true))) if (prev_backslash) {
  440
+                                regexp += "\\" + ch;
  441
+                                prev_backslash = false;
  442
+                        } else if (ch == "[") {
  443
+                                in_class = true;
  444
+                                regexp += ch;
  445
+                        } else if (ch == "]" && in_class) {
  446
+                                in_class = false;
  447
+                                regexp += ch;
  448
+                        } else if (ch == "/" && !in_class) {
  449
+                                break;
  450
+                        } else if (ch == "\\") {
  451
+                                prev_backslash = true;
  452
+                        } else {
  453
+                                regexp += ch;
  454
+                        }
  455
+                        var mods = read_while(function(ch){
  456
+                                return HOP(REGEXP_MODIFIERS, ch);
  457
+                        });
  458
+                        return token("regexp", [ regexp, mods ]);
  459
+                });
  460
+        };
  461
+
  462
+        function read_operator(prefix) {
  463
+                function grow(op) {
  464
+                        var bigger = op + peek();
  465
+                        if (HOP(OPERATORS, bigger)) {
  466
+                                next();
  467
+                                return grow(bigger);
  468
+                        } else {
  469
+                                return op;
  470
+                        }
  471
+                };
  472
+                return token("operator", grow(prefix || next()));
  473
+        };
  474
+
  475
+        var handle_slash = skip_comments ? function() {
  476
+                next();
  477
+                var regex_allowed = S.regex_allowed;
  478
+                switch (peek()) {
  479
+                    case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token();
  480
+                    case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token();
  481
+                }
  482
+                return S.regex_allowed ? read_regexp() : read_operator("/");
  483
+        } : function() {
  484
+                next();
  485
+                switch (peek()) {
  486
+                    case "/": return read_line_comment();
  487
+                    case "*": return read_multiline_comment();
  488
+                }
  489
+                return S.regex_allowed ? read_regexp() : read_operator("/");
  490
+        };
  491
+
  492
+        function handle_dot() {
  493
+                next();
  494
+                return is_digit(peek())
  495
+                        ? read_num(".")
  496
+                        : token("punc", ".");
  497
+        };
  498
+
  499
+        function read_word() {
  500
+                var word = read_while(is_identifier_char);
  501
+                return !HOP(KEYWORDS, word)
  502
+                        ? token("name", word)
  503
+                        : HOP(OPERATORS, word)
  504
+                        ? token("operator", word)
  505
+                        : HOP(KEYWORDS_ATOM, word)
  506
+                        ? token("atom", word)
  507
+                        : token("keyword", word);
  508
+        };
  509
+
  510
+        function with_eof_error(eof_error, cont) {
  511
+                try {
  512
+                        return cont();
  513
+                } catch(ex) {
  514
+                        if (ex === EX_EOF) parse_error(eof_error);
  515
+                        else throw ex;
  516
+                }
  517
+        };
  518
+
  519
+        function next_token(force_regexp) {
  520
+                if (force_regexp)
  521
+                        return read_regexp();
  522
+                skip_whitespace();
  523
+                start_token();
  524
+                var ch = peek();
  525
+                if (!ch) return token("eof");
  526
+                if (is_digit(ch)) return read_num();
  527
+                if (ch == '"' || ch == "'") return read_string();
  528
+                if (HOP(PUNC_CHARS, ch)) return token("punc", next());
  529
+                if (ch == ".") return handle_dot();
  530
+                if (ch == "/") return handle_slash();
  531
+                if (HOP(OPERATOR_CHARS, ch)) return read_operator();
  532
+                if (is_identifier_char(ch)) return read_word();
  533
+                parse_error("Unexpected character '" + ch + "'");
  534
+        };
  535
+
  536
+        next_token.context = function(nc) {
  537
+                if (nc) S = nc;
  538
+                return S;
  539
+        };
  540
+
  541
+        return next_token;
  542
+
  543
+};
  544
+
  545
+/* -----[ Parser (constants) ]----- */
  546
+
  547
+var UNARY_PREFIX = array_to_hash([
  548
+        "typeof",
  549
+        "void",
  550
+        "delete",
  551
+        "--",
  552
+        "++",
  553
+        "!",
  554
+        "~",
  555
+        "-",
  556
+        "+"
  557
+]);
  558
+
  559
+var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
  560
+
  561
+var ASSIGNMENT = (function(a, ret, i){
  562
+        while (i < a.length) {
  563
+                ret[a[i]] = a[i].substr(0, a[i].length - 1);
  564
+                i++;
  565
+        }
  566
+        return ret;
  567
+})(
  568
+        ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "~=", "%=", "|=", "^=", "&="],
  569
+        { "=": true },
  570
+        0
  571
+);
  572
+
  573
+var PRECEDENCE = (function(a, ret){
  574
+        for (var i = 0, n = 1; i < a.length; ++i, ++n) {
  575
+                var b = a[i];
  576
+                for (var j = 0; j < b.length; ++j) {
  577
+                        ret[b[j]] = n;
  578
+                }
  579
+        }
  580
+        return ret;
  581
+})(
  582
+        [
  583
+                ["||"],
  584
+                ["&&"],
  585
+                ["|"],
  586
+                ["^"],
  587
+                ["&"],
  588
+                ["==", "===", "!=", "!=="],
  589
+                ["<", ">", "<=", ">=", "in", "instanceof"],
  590
+                [">>", "<<", ">>>"],
  591
+                ["+", "-"],
  592
+                ["*", "/", "%"]
  593
+        ],
  594
+        {}
  595
+);
  596
+
  597
+var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
  598
+
  599
+var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
  600
+
  601
+/* -----[ Parser ]----- */
  602
+
  603
+function NodeWithToken(str, start, end) {
  604
+        this.name = str;
  605
+        this.start = start;
  606
+        this.end = end;
  607
+};
  608
+
  609
+NodeWithToken.prototype.toString = function() { return this.name; };
  610
+
  611
+function parse($TEXT, strict_mode, embed_tokens) {
  612
+
  613
+        var S = {
  614
+                input: tokenizer($TEXT, true),
  615
+                token: null,
  616
+                prev: null,
  617
+                peeked: null,
  618
+                in_function: 0,
  619
+                in_loop: 0,
  620
+                labels: []
  621
+        };
  622
+
  623
+        S.token = next();
  624
+
  625
+        function is(type, value) {
  626
+                return is_token(S.token, type, value);
  627
+        };
  628
+
  629
+        function peek() { return S.peeked || (S.peeked = S.input()); };
  630
+
  631
+        function next() {
  632
+                S.prev = S.token;
  633
+                if (S.peeked) {
  634
+                        S.token = S.peeked;
  635
+                        S.peeked = null;
  636
+                } else {
  637
+                        S.token = S.input();
  638
+                }
  639
+                return S.token;
  640
+        };
  641
+
  642
+        function prev() {
  643
+                return S.prev;
  644
+        };
  645
+
  646
+        function croak(msg, line, col, pos) {
  647
+                var ctx = S.input.context();
  648
+                js_error(msg,
  649
+                         line != null ? line : ctx.tokline,
  650
+                         col != null ? col : ctx.tokcol,
  651
+                         pos != null ? pos : ctx.tokpos);
  652
+        };
  653
+
  654
+        function token_error(token, msg) {
  655
+                croak(msg, token.line, token.col);
  656
+        };
  657
+
  658
+        function unexpected(token) {
  659
+                if (token == null)
  660
+                        token = S.token;
  661
+                token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
  662
+        };
  663
+
  664
+        function expect_token(type, val) {
  665
+                if (is(type, val)) {
  666
+                        return next();
  667
+                }
  668
+                token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
  669
+        };
  670
+
  671
+        function expect(punc) { return expect_token("punc", punc); };
  672
+
  673
+        function can_insert_semicolon() {
  674
+                return !strict_mode && (
  675
+                        S.token.nlb || is("eof") || is("punc", "}")
  676
+                );
  677
+        };
  678
+
  679
+        function semicolon() {
  680
+                if (is("punc", ";")) next();
  681
+                else if (!can_insert_semicolon()) unexpected();
  682
+        };
  683
+
  684
+        function as() {
  685
+                return slice(arguments);
  686
+        };
  687
+
  688
+        function parenthesised() {
  689
+                expect("(");
  690
+                var ex = expression();
  691
+                expect(")");
  692
+                return ex;
  693
+        };
  694
+
  695
+        function add_tokens(str, start, end) {
  696
+                return new NodeWithToken(str, start, end);
  697
+        };
  698
+
  699
+        var statement = embed_tokens ? function() {
  700
+                var start = S.token;
  701
+                var stmt = $statement();
  702
+                stmt[0] = add_tokens(stmt[0], start, prev());
  703
+                return stmt;
  704
+        } : $statement;
  705
+
  706
+        function $statement() {
  707
+                if (is("operator", "/")) {