From 1d65c6b496710f12827fb0853c50cb6b418fcc0f Mon Sep 17 00:00:00 2001 From: Wei Kin Huang Date: Sun, 30 Sep 2012 18:50:33 -0400 Subject: [PATCH] Moving to build submodule --- build/bridge/benchmark-node-bridge.js | 139 - build/bridge/benchmark-phantom-bridge.html | 53 - build/bridge/benchmark-phantom-hooks.js | 74 - build/bridge/coverage-node-bridge.js | 139 - build/bridge/coverage-phantom-bridge.html | 49 - build/bridge/coverage-phantom-hooks.js | 90 - build/bridge/phantom-bridge.js | 20 - build/bridge/qunit-browserstack-bridge.html | 59 - build/bridge/qunit-browserstack-hooks.js | 89 - build/bridge/qunit-coverage-bridge.html | 68 - build/bridge/qunit-node-bridge.js | 129 - build/bridge/qunit-phantom-bridge.html | 49 - build/bridge/qunit-phantom-hooks.js | 82 - build/build.js | 455 -- build/coverage/jscoverage-highlight.css | 38 - build/coverage/jscoverage-ie.css | 108 - build/coverage/jscoverage-throbber.gif | Bin 425 -> 0 bytes build/coverage/jscoverage.css | 355 -- build/coverage/jscoverage.html | 164 - build/coverage/jscoverage.js | 1176 ----- build/jscoverage.html | 170 - build/module/browserstack.js | 408 -- build/module/clean.js | 25 - build/module/concat.js | 23 - build/module/coverage.js | 371 -- build/module/creport.js | 19 - build/module/doc.js | 569 --- build/module/lint.js | 72 - build/module/min.js | 31 - build/module/perf.js | 205 - build/module/pkg.js | 22 - build/module/size.js | 30 - build/module/unit.js | 182 - build/perf.html | 88 - build/perf/benchmark.js | 3802 -------------- build/perf/perf.css | 176 - build/perf/perf.js | 87 - build/qunit.html | 68 - build/qunit/qunit.css | 236 - build/qunit/qunit.js | 1803 ------- build/vendor/browserstack/browserstack.js | 272 - build/vendor/classify/classify-array.min.js | 9 - build/vendor/classify/classify.min.js | 9 - .../vendor/highlight/highlight.javascript.js | 58 - build/vendor/highlight/highlight.js | 663 --- build/vendor/jshint/jshint.js | 4551 ----------------- build/vendor/uglify/consolidator.js | 1220 ----- build/vendor/uglify/parse-js.js | 1362 ----- build/vendor/uglify/process.js | 2080 -------- build/vendor/uglify/squeeze-more.js | 74 - 50 files changed, 22021 deletions(-) delete mode 100755 build/bridge/benchmark-node-bridge.js delete mode 100755 build/bridge/benchmark-phantom-bridge.html delete mode 100755 build/bridge/benchmark-phantom-hooks.js delete mode 100755 build/bridge/coverage-node-bridge.js delete mode 100755 build/bridge/coverage-phantom-bridge.html delete mode 100755 build/bridge/coverage-phantom-hooks.js delete mode 100755 build/bridge/phantom-bridge.js delete mode 100755 build/bridge/qunit-browserstack-bridge.html delete mode 100755 build/bridge/qunit-browserstack-hooks.js delete mode 100755 build/bridge/qunit-coverage-bridge.html delete mode 100755 build/bridge/qunit-node-bridge.js delete mode 100755 build/bridge/qunit-phantom-bridge.html delete mode 100755 build/bridge/qunit-phantom-hooks.js delete mode 100755 build/build.js delete mode 100755 build/coverage/jscoverage-highlight.css delete mode 100755 build/coverage/jscoverage-ie.css delete mode 100755 build/coverage/jscoverage-throbber.gif delete mode 100755 build/coverage/jscoverage.css delete mode 100755 build/coverage/jscoverage.html delete mode 100755 build/coverage/jscoverage.js delete mode 100755 build/jscoverage.html delete mode 100755 build/module/browserstack.js delete mode 100755 build/module/clean.js delete mode 100755 build/module/concat.js delete mode 100755 build/module/coverage.js delete mode 100755 build/module/creport.js delete mode 100755 build/module/doc.js delete mode 100755 build/module/lint.js delete mode 100755 build/module/min.js delete mode 100755 build/module/perf.js delete mode 100755 build/module/pkg.js delete mode 100755 build/module/size.js delete mode 100755 build/module/unit.js delete mode 100755 build/perf.html delete mode 100755 build/perf/benchmark.js delete mode 100755 build/perf/perf.css delete mode 100755 build/perf/perf.js delete mode 100755 build/qunit.html delete mode 100755 build/qunit/qunit.css delete mode 100755 build/qunit/qunit.js delete mode 100755 build/vendor/browserstack/browserstack.js delete mode 100755 build/vendor/classify/classify-array.min.js delete mode 100755 build/vendor/classify/classify.min.js delete mode 100755 build/vendor/highlight/highlight.javascript.js delete mode 100755 build/vendor/highlight/highlight.js delete mode 100755 build/vendor/jshint/jshint.js delete mode 100755 build/vendor/uglify/consolidator.js delete mode 100755 build/vendor/uglify/parse-js.js delete mode 100755 build/vendor/uglify/process.js delete mode 100755 build/vendor/uglify/squeeze-more.js diff --git a/build/bridge/benchmark-node-bridge.js b/build/bridge/benchmark-node-bridge.js deleted file mode 100755 index ce49ed2..0000000 --- a/build/bridge/benchmark-node-bridge.js +++ /dev/null @@ -1,139 +0,0 @@ -//include the fs module -var fs = require("fs"), -// sandboxing module -vm = require("vm"), -// path utilities -path = require("path"), -// read options from commandline -options = JSON.parse(process.argv[2]); - -// globals needed by qunit sandbox -var sandbox = { - require : require, - exports : {}, - setTimeout : setTimeout, - setInterval : setInterval, - clearTimeout : clearTimeout, - clearInterval : clearInterval, - console : console -}; -//window/global/root is a circualr reference -sandbox.window = sandbox; -sandbox.global = sandbox; -sandbox.root = sandbox; - -//create a new context -var context = vm.createContext(sandbox); - -// load the benchmark library into the sandbox -context.Benchmark = require(path.join(__dirname, "..", "perf/benchmark.js")); - -// create a new global test suite -context.___benchmarks = new context.Benchmark.Suite(); - -// bind the response handlers to the parent process -context.___benchmarks.on("add", function(e) { - var i = 0, test = e.target, testData = { - id : test.id, - name : test.name - }; - - // bind events - test.on("start", function(e) { - i = 0; - process.send({ - event : "testStart", - data : testData - }); - }).on("cycle", function(e) { - process.send({ - event : "testCycle", - data : { - id : this.id, - name : this.name, - size : ++i, - count : this.count - } - }); - }).on("error", function(e) { - process.send({ - event : "testError", - data : testData - }); - }).on("reset", function(e) { - process.send({ - event : "testReset", - data : testData - }); - }).on("complete", function(e) { - var data = { - id : this.id, - name : this.name, - stats : this.stats, - times : this.times, - count : this.count, - cycles : this.cycles, - hz : this.hz - }; - if (this.error) { - data.error = this.error.message; - } - - process.send({ - event : "testComplete", - data : data - }); - }); -}); - -// notify the parent process that tests are finished -context.___benchmarks.on("complete", function() { - process.send({ - event : "done", - data : {} - }); -}); - -// wrapper function to add a test group -context.Benchmark.test = function(group, testGroup) { - testGroup(function(name, test) { - context.___benchmarks.add.call(context.___benchmarks, group + "." + name, test); - }); -}; - -// load source and tests into the sandbox -function load(src, root) { - var files = []; - // build up the source file - src.forEach(function(file) { - try { - files.push(fs.readFileSync(root + "/" + file, "utf8")); - } catch (e) { - console.log(e.message + " in " + file); - process.exit(1); - } - }); - - // run the source in the sandbox - try { - vm.runInContext(files.join("\n"), context); - } catch (e) { - console.log(e.message); - process.exit(1); - } -} - -// load dependencies -load(options.source.external, options.dir.vendor); - -// load up the source files -load(options.source.src, options.dir.src); - -// load up the test files -load(options.source.perf, options.dir.perf); - -// start the tests -context.___benchmarks.run({ - async : true, - queued : true -}); diff --git a/build/bridge/benchmark-phantom-bridge.html b/build/bridge/benchmark-phantom-bridge.html deleted file mode 100755 index 1de42be..0000000 --- a/build/bridge/benchmark-phantom-bridge.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - -Benchmark Test Suite - - - -

Benchmark Test Suite

- - - - - - - - - - - - - \ No newline at end of file diff --git a/build/bridge/benchmark-phantom-hooks.js b/build/bridge/benchmark-phantom-hooks.js deleted file mode 100755 index b1babea..0000000 --- a/build/bridge/benchmark-phantom-hooks.js +++ /dev/null @@ -1,74 +0,0 @@ -(function(window, tests) { - // pass data to the process - function send(data) { - alert(JSON.stringify(data)); - } - - tests.on("add", function(e) { - var i = 0, test = e.target, testData = { - id : test.id, - name : test.name - }; - - // bind events - test.on("start", function(e) { - i = 0; - send({ - event : "testStart", - data : testData - }); - }).on("cycle", function(e) { - send({ - event : "testCycle", - data : { - id : this.id, - name : this.name, - size : ++i, - count : this.count - } - }); - }).on("error", function(e) { - send({ - event : "testError", - data : testData - }); - }).on("reset", function(e) { - send({ - event : "testReset", - data : testData - }); - }).on("complete", function(e) { - var data = { - id : this.id, - name : this.name, - stats : this.stats, - times : this.times, - count : this.count, - cycles : this.cycles, - hz : this.hz - }; - if (this.error) { - data.error = this.error.message; - } - - send({ - event : "testComplete", - data : data - }); - }); - }); - - tests.on("complete", function() { - send({ - event : "done", - data : {} - }); - }); - - // wrapper function to add a test group - window.Benchmark.test = function(group, testGroup) { - testGroup(function(name, test) { - tests.add.call(tests, group + "." + name, test); - }); - }; -})(window, ___benchmarks); diff --git a/build/bridge/coverage-node-bridge.js b/build/bridge/coverage-node-bridge.js deleted file mode 100755 index 1f82ba5..0000000 --- a/build/bridge/coverage-node-bridge.js +++ /dev/null @@ -1,139 +0,0 @@ -// include the fs module -var fs = require("fs"), -// sandboxing module -vm = require("vm"), -// path utilities -path = require("path"), -// read options from commandline -options = JSON.parse(process.argv[2]), -// misc variables -currentmodule; - -// globals needed by qunit sandbox -var sandbox = { - require : require, - exports : {}, - setTimeout : setTimeout, - setInterval : setInterval, - clearTimeout : clearTimeout, - clearInterval : clearInterval, - console : console -}; -// window/global/root is a circualr reference -sandbox.window = sandbox; -sandbox.global = sandbox; -sandbox.root = sandbox; - -// create a new context -var context = vm.createContext(sandbox); - -try { - vm.runInContext(fs.readFileSync(path.join(__dirname, "..", "qunit/qunit.js"), "utf8"), context); -} catch (err) { - process.exit(1); -} - -// have a global reference to QUnit within the sandbox -context.QUnit = context.exports; -context.exports = {}; - -// don't have qunit reorder tests -context.QUnit.config.reorder = false; - -// add event listeners to the qunit test events -context.QUnit.log(function(data) { - data.test = this.config.current.testName; - data.module = currentmodule; - process.send({ - event : "assertionDone", - data : data - }); -}); -context.QUnit.testStart(function(data) { - // use last module name if no module name defined - currentmodule = data.module || currentmodule; - data.test = this.config.current.testName; - data.module = currentmodule; - process.send({ - event : "testStart", - data : data - }); -}); -context.QUnit.testDone(function(data) { - // use last module name if no module name defined - data.module = data.module || currentmodule; - process.send({ - event : "testDone", - data : data - }); -}); -context.QUnit.moduleStart(function(data) { - process.send({ - event : "moduleStart", - data : data - }); -}); -context.QUnit.moduleDone(function(data) { - process.send({ - event : "moduleDone", - data : data - }); -}); - -// override the done function to signal back to the parent process that this unit test is done -context.QUnit.done((function() { - var timeout = null, later = function(data) { - timeout = null; - - var coverage = {}; - Object.keys(context._$jscoverage).forEach(function(key) { - coverage[key] = { - lines : Array.prototype.slice.call(context._$jscoverage[key], 0), - conditionals : context._$jscoverage[key].conditionals || [] - }; - }); - data.coverage = coverage; - - process.send({ - event : "done", - data : data - }); - }; - return function(data) { - clearTimeout(timeout); - timeout = setTimeout(function() { - later(data); - }, 1000); - }; -})()); - -// load source and tests into the sandbox -function load(src, root) { - var files = []; - // build up the source file - src.forEach(function(file) { - try { - files.push(fs.readFileSync(root + "/" + file, "utf8")); - } catch (e) { - console.log(e.message + " in " + file); - process.exit(1); - } - }); - - // run the source in the sandbox - try { - vm.runInContext(files.join("\n"), context); - } catch (e) { - console.log(e.message); - process.exit(1); - } -} - -// load dependencies -load(options.source.external, options.dir.vendor); - -// load up the source files -load(options.source.src, options.dir.coverage); - -// load up the test files -load(options.source.tests, options.dir.test); diff --git a/build/bridge/coverage-phantom-bridge.html b/build/bridge/coverage-phantom-bridge.html deleted file mode 100755 index 89144b7..0000000 --- a/build/bridge/coverage-phantom-bridge.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - -QUnit Test Suite - - - - -

QUnit Test Suite

-

-
-

-
    - - - - - - - - - - - \ No newline at end of file diff --git a/build/bridge/coverage-phantom-hooks.js b/build/bridge/coverage-phantom-hooks.js deleted file mode 100755 index 5e12344..0000000 --- a/build/bridge/coverage-phantom-hooks.js +++ /dev/null @@ -1,90 +0,0 @@ -(function() { - var currentmodule = null, currenttest = null; - - // Run tests in the order they were defined. - QUnit.config.reorder = false; - // Run tests in series. - QUnit.config.autorun = false; - - // keep reference to original functions - var original_log = QUnit.log, - // original test hooks - original_testStart = QUnit.testStart, original_testDone = QUnit.testDone, - // original module hooks - original_moduleStart = QUnit.moduleStart, original_moduleDone = QUnit.moduleDone, - // original done hook - original_done = QUnit.done; - - // pass data to the process - function send(data) { - alert(JSON.stringify(data)); - } - - QUnit.log = function(data) { - if (data.message === '[dataect Object], undefined:undefined') { - return; - } - data.module = currentmodule; - data.test = currenttest; - data.actual = QUnit.jsDump.parse(data.actual); - data.expected = QUnit.jsDump.parse(data.expected); - send({ - event : "assertionDone", - data : data - }); - original_log.apply(this, arguments); - }; - - QUnit.testStart = function(data) { - currentmodule = data.module || currentmodule; - currenttest = data.name || currenttest; - - send({ - event : "testStart", - data : data - }); - original_testStart.apply(this, arguments); - }; - - QUnit.testDone = function(data) { - data.module = data.module || currentmodule; - - send({ - event : "testDone", - data : data - }); - original_testDone.apply(this, arguments); - }; - - QUnit.moduleStart = function(data) { - send({ - event : "moduleStart", - data : data - }); - original_moduleStart.apply(this, arguments); - }; - - QUnit.moduleDone = function(data) { - send({ - event : "moduleDone", - data : data - }); - original_moduleDone.apply(this, arguments); - }; - - QUnit.done = function(data) { - var coverage = {}; - Object.keys(window._$jscoverage).forEach(function(key) { - coverage[key] = { - lines : Array.prototype.slice.call(window._$jscoverage[key], 0), - conditionals : window._$jscoverage[key].conditionals || [] - }; - }); - data.coverage = coverage; - send({ - event : "done", - data : data - }); - original_done.apply(this, arguments); - }; -})(); diff --git a/build/bridge/phantom-bridge.js b/build/bridge/phantom-bridge.js deleted file mode 100755 index 8ccaab3..0000000 --- a/build/bridge/phantom-bridge.js +++ /dev/null @@ -1,20 +0,0 @@ -// create a new webpage -var page = require("webpage").create(), -// path to the bridge html file -bridge_url = phantom.args[0]; - -page.onAlert = function(args) { - console.log(args); - try { - if (JSON.parse(args).event === "done") { - phantom.exit(0); - } - } catch (e) { - } -}; - -page.open(bridge_url, function(status) { - if (status !== "success") { - phantom.exit(1); - } -}); diff --git a/build/bridge/qunit-browserstack-bridge.html b/build/bridge/qunit-browserstack-bridge.html deleted file mode 100755 index 6cc5900..0000000 --- a/build/bridge/qunit-browserstack-bridge.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - -QUnit Test Suite - - - -

    QUnit Test Suite

    -

    -
    -

    -
      - - - - - - - - - - - - \ No newline at end of file diff --git a/build/bridge/qunit-browserstack-hooks.js b/build/bridge/qunit-browserstack-hooks.js deleted file mode 100755 index 9e35c5c..0000000 --- a/build/bridge/qunit-browserstack-hooks.js +++ /dev/null @@ -1,89 +0,0 @@ -(function() { - var currentmodule = null, currenttest = null; - - // Run tests in the order they were defined. - QUnit.config.reorder = false; - // Run tests in series. - QUnit.config.autorun = false; - - // keep reference to original functions - var original_log = QUnit.log, - // original test hooks - original_testStart = QUnit.testStart, original_testDone = QUnit.testDone, - // original module hooks - original_moduleStart = QUnit.moduleStart, original_moduleDone = QUnit.moduleDone, - // original done hook - original_done = QUnit.done; - - var socket = io.connect(); - var browser = decodeURIComponent((/__browser=(.+?)(&|$)/).exec(window.location.search)[1] || "Unknown 0.0 unknown"); - socket.emit("browserConnect", { - ua : navigator.userAgent, - browser : browser - }); - - // pass data to the process - function send(data) { - socket.emit(data.event, data.data); - } - - QUnit.log = function(data) { - if (data.message === "[dataect Object], undefined:undefined") { - return; - } - data.module = currentmodule; - data.test = currenttest; - data.actual = QUnit.jsDump.parse(data.actual); - data.expected = QUnit.jsDump.parse(data.expected); - send({ - event : "assertionDone", - data : data - }); - original_log.apply(this, arguments); - }; - - QUnit.testStart = function(data) { - currentmodule = data.module || currentmodule; - currenttest = data.name || currenttest; - - send({ - event : "testStart", - data : data - }); - original_testStart.apply(this, arguments); - }; - - QUnit.testDone = function(data) { - data.module = data.module || currentmodule; - - send({ - event : "testDone", - data : data - }); - original_testDone.apply(this, arguments); - }; - - QUnit.moduleStart = function(data) { - send({ - event : "moduleStart", - data : data - }); - original_moduleStart.apply(this, arguments); - }; - - QUnit.moduleDone = function(data) { - send({ - event : "moduleDone", - data : data - }); - original_moduleDone.apply(this, arguments); - }; - - QUnit.done = function(data) { - send({ - event : "done", - data : data - }); - original_done.apply(this, arguments); - }; -})(); diff --git a/build/bridge/qunit-coverage-bridge.html b/build/bridge/qunit-coverage-bridge.html deleted file mode 100755 index 16789cc..0000000 --- a/build/bridge/qunit-coverage-bridge.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - -

      -
      -

      -
        - - - - - - - - \ No newline at end of file diff --git a/build/bridge/qunit-node-bridge.js b/build/bridge/qunit-node-bridge.js deleted file mode 100755 index 08a828c..0000000 --- a/build/bridge/qunit-node-bridge.js +++ /dev/null @@ -1,129 +0,0 @@ -// include the fs module -var fs = require("fs"), -// sandboxing module -vm = require("vm"), -// path utilities -path = require("path"), -// read options from commandline -options = JSON.parse(process.argv[2]), -// misc variables -currentmodule; - -// globals needed by qunit sandbox -var sandbox = { - require : require, - exports : {}, - setTimeout : setTimeout, - setInterval : setInterval, - clearTimeout : clearTimeout, - clearInterval : clearInterval, - console : console -}; -// window/global/root is a circualr reference -sandbox.window = sandbox; -sandbox.global = sandbox; -sandbox.root = sandbox; - -// create a new context -var context = vm.createContext(sandbox); - -try { - vm.runInContext(fs.readFileSync(path.join(__dirname, "..", "qunit/qunit.js"), "utf8"), context); -} catch (err) { - process.exit(1); -} - -// have a global reference to QUnit within the sandbox -context.QUnit = context.exports; -context.exports = {}; - -// don't have qunit reorder tests -context.QUnit.config.reorder = false; - -// add event listeners to the qunit test events -context.QUnit.log(function(data) { - data.test = this.config.current.testName; - data.module = currentmodule; - process.send({ - event : "assertionDone", - data : data - }); -}); -context.QUnit.testStart(function(data) { - // use last module name if no module name defined - currentmodule = data.module || currentmodule; - data.test = this.config.current.testName; - data.module = currentmodule; - process.send({ - event : "testStart", - data : data - }); -}); -context.QUnit.testDone(function(data) { - // use last module name if no module name defined - data.module = data.module || currentmodule; - process.send({ - event : "testDone", - data : data - }); -}); -context.QUnit.moduleStart(function(data) { - process.send({ - event : "moduleStart", - data : data - }); -}); -context.QUnit.moduleDone(function(data) { - process.send({ - event : "moduleDone", - data : data - }); -}); - -// override the done function to signal back to the parent process that this unit test is done -context.QUnit.done((function() { - var timeout = null, later = function(data) { - timeout = null; - process.send({ - event : "done", - data : data - }); - }; - return function(data) { - clearTimeout(timeout); - timeout = setTimeout(function() { - later(data); - }, 1000); - }; -})()); - -// load source and tests into the sandbox -function load(src, root) { - var files = []; - // build up the source file - src.forEach(function(file) { - try { - files.push(fs.readFileSync(root + "/" + file, "utf8")); - } catch (e) { - console.log(e.message + " in " + file); - process.exit(1); - } - }); - - // run the source in the sandbox - try { - vm.runInContext(files.join("\n"), context); - } catch (e) { - console.log(e.message); - process.exit(1); - } -} - -// load dependencies -load(options.source.external, options.dir.vendor); - -// load up the source files -load(options.source.src, options.dir.src); - -// load up the test files -load(options.source.tests, options.dir.test); diff --git a/build/bridge/qunit-phantom-bridge.html b/build/bridge/qunit-phantom-bridge.html deleted file mode 100755 index 13a739b..0000000 --- a/build/bridge/qunit-phantom-bridge.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - -QUnit Test Suite - - - - -

        QUnit Test Suite

        -

        -
        -

        -
          - - - - - - - - - - - \ No newline at end of file diff --git a/build/bridge/qunit-phantom-hooks.js b/build/bridge/qunit-phantom-hooks.js deleted file mode 100755 index ed5014c..0000000 --- a/build/bridge/qunit-phantom-hooks.js +++ /dev/null @@ -1,82 +0,0 @@ -(function() { - var currentmodule = null, currenttest = null; - - // Run tests in the order they were defined. - QUnit.config.reorder = false; - // Run tests in series. - QUnit.config.autorun = false; - - // keep reference to original functions - var original_log = QUnit.log, - // original test hooks - original_testStart = QUnit.testStart, original_testDone = QUnit.testDone, - // original module hooks - original_moduleStart = QUnit.moduleStart, original_moduleDone = QUnit.moduleDone, - // original done hook - original_done = QUnit.done; - - // pass data to the process - function send(data) { - alert(JSON.stringify(data)); - } - - QUnit.log = function(data) { - if (data.message === '[dataect Object], undefined:undefined') { - return; - } - data.module = currentmodule; - data.test = currenttest; - data.actual = QUnit.jsDump.parse(data.actual); - data.expected = QUnit.jsDump.parse(data.expected); - send({ - event : "assertionDone", - data : data - }); - original_log.apply(this, arguments); - }; - - QUnit.testStart = function(data) { - currentmodule = data.module || currentmodule; - currenttest = data.name || currenttest; - - send({ - event : "testStart", - data : data - }); - original_testStart.apply(this, arguments); - }; - - QUnit.testDone = function(data) { - data.module = data.module || currentmodule; - - send({ - event : "testDone", - data : data - }); - original_testDone.apply(this, arguments); - }; - - QUnit.moduleStart = function(data) { - send({ - event : "moduleStart", - data : data - }); - original_moduleStart.apply(this, arguments); - }; - - QUnit.moduleDone = function(data) { - send({ - event : "moduleDone", - data : data - }); - original_moduleDone.apply(this, arguments); - }; - - QUnit.done = function(data) { - send({ - event : "done", - data : data - }); - original_done.apply(this, arguments); - }; -})(); diff --git a/build/build.js b/build/build.js deleted file mode 100755 index 12e1ecf..0000000 --- a/build/build.js +++ /dev/null @@ -1,455 +0,0 @@ -// include the fs mmodule -var fs = require("fs"), -// path utilities -path = require("path"), -// execute system commands -childProcess = require("child_process"), -// the util library -util = require("util"), -// quick reference to root dir -__DIR__ = path.dirname(__dirname), -// classify library -Classify = require("./vendor/classify/classify.min.js"); -// require the special array library -require("./vendor/classify/classify-array.min.js")(Classify); -var cArray = Classify("/Array"); -var colors = { - black : 30, - red : 31, - green : 32, - yellow : 33, - blue : 34, - magenta : 35, - purple : 35, - cyan : 36, - white : 37 -}; - -function gzip(data, callback) { - var child = childProcess.spawn("gzip", [ "-c", "-q", "-" ]), output = ""; - // Promise events - child.stdout.setEncoding("utf8"); - child.stdout.on("data", function(stdout) { - output += stdout.toString(); - }); - child.on("exit", function(code) { - callback(output, output.length); - }); - child.stdin.end((data || "").toString(), "utf8"); -} - -var Build = Classify.create({ - __static_ : { - build : function(config) { - return Build(config || require(__DIR__ + "/config.js")).build(); - } - }, - init : function(config) { - this.sourceCache = {}; - this.dir = { - base : __DIR__, - build : __DIR__ + "/build", - dist : __DIR__ + "/dist", - src : __DIR__ + "/src", - perf : __DIR__ + "/perf", - test : __DIR__ + "/test", - coverage : __DIR__ + "/coverage", - doc : __DIR__ + "/docs", - vendor : __DIR__ + "/vendor" - }; - - // default values for file sources - this.wrap = {}; - this.src = []; - this.unit = []; - this.perf = []; - this.external = []; - this.env = {}; - this.name = ""; - this.version = "0.0.0"; - this.repoUrl = ""; - - this.optStore = null; - this.options = {}; - this.taskOptions = {}; - this.replaceTokens = []; - this.currentStep = null; - this.defaultTasks = []; - - // call the config function to populate the internal options - config(this); - - this.writeParsedOptions(); - }, - - setNameVersion : function(name, version) { - this.name = name; - this.version = version || "0.0.0"; - return this; - }, - setRepoName : function(repo) { - this.repoUrl = repo; - return this; - }, - addSourceFile : function() { - this.src.push.apply(this.src, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addUnitTestFile : function() { - this.unit.push.apply(this.unit, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addBenchmarkFile : function() { - this.perf.push.apply(this.perf, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addExternalFile : function() { - this.external.push.apply(this.external, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addCopyright : function() { - if (!this.wrap.copy) { - this.wrap.copy = []; - } - this.wrap.copy.push.apply(this.wrap.copy, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addSourceWrap : function() { - if (!this.wrap.wrap) { - this.wrap.wrap = []; - } - this.wrap.wrap.push.apply(this.wrap.wrap, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - addReplaceToken : function(name, value) { - this.replaceTokens.push({ - name : name, - value : value - }); - return this; - }, - enableEnvironment : function() { - var self = this; - Array.prototype.slice.call(Array.isArray(arguments[0]) ? arguments[0] : arguments, 0).forEach(function(env) { - self.env[env] = true; - }); - return this; - }, - addTaskOptions : function(name, options) { - this.taskOptions[name] = options || {}; - return this; - }, - addOption : function(name, options) { - this.options[name] = options || {}; - return this; - }, - setDefaultTasks : function() { - this.defaultTasks.push.apply(this.defaultTasks, Array.isArray(arguments[0]) ? arguments[0] : arguments); - return this; - }, - writeParsedOptions : function() { - var data = {}; - data.name = this.name; - data.src = this.src; - data.unit = this.unit; - data.perf = this.perf; - data.external = this.external; - this.writeCacheFile("options", data, true, "module.exports = %j;"); - }, - - getOption : function(name) { - var self = this, opt = null, temp; - - // try to pull from the task options first - if (this.currentStep !== null && this.taskOptions[this.currentStep]) { - // do a nested loop to check the options object - temp = this.taskOptions[this.currentStep]; - name.split(".").some(function(part, i) { - // skip the first step if it's name is the same as the step - if (!part || i === 0 && part === self.currentStep) { - return; - } - if (temp == null || !temp.hasOwnProperty(part)) { - temp = null; - return false; - } - temp = temp[part]; - }); - if (temp != null) { - return temp; - } - } - - // do a nested loop to check the options object - temp = this.options; - name.split(".").some(function(part) { - if (temp == null || !temp.hasOwnProperty(part)) { - temp = null; - return false; - } - temp = temp[part]; - }); - if (temp != null) { - return temp; - } - // check params array - Array.prototype.slice.call(process.argv, 2).some(function(param) { - if (param.indexOf("--" + name + "=") === 0) { - opt = param.replace(new RegExp("^--" + name.replace(/\./g, "\\.") + "="), "").replace(/^["']+|["']+$/g, ""); - return false; - } - }); - if (opt != null) { - return opt; - } - // then check the local config file - if (this.optStore === null) { - this.optStore = this.readCacheFile("config", true) || {}; - } - - // do a nested loop to check the options object - temp = this.optStore; - name.split(".").some(function(part) { - if (temp == null || !temp.hasOwnProperty(part)) { - temp = null; - return false; - } - temp = temp[part]; - }); - if (temp != null) { - return temp; - } - - // lastly try to pull from a different task option - if (this.taskOptions[name]) { - return this.taskOptions[name]; - } - - return null; - }, - - getSource : function(callback) { - if (this.sourceCache.full != null) { - callback(this.sourceCache.full); - return; - } - var self = this, data = ""; - this.src.forEach(function(file) { - data += fs.readFileSync(self.dir.src + "/" + file, "utf8"); - }); - (this.wrap && this.wrap.wrap || []).forEach(function(file) { - data = fs.readFileSync(self.dir.src + "/" + file, "utf8").replace(/"@SOURCE\b";/g, data); - }); - - data = data.replace(/@VERSION\b/g, this.version); - data.replace(/@DATE\b/g, (new Date()).toUTCString()); - - this.replaceTokens.forEach(function(token) { - data = data.replace(new RegExp("@" + token.name + "\\b", "g"), token.value); - }); - this.sourceCache.full = data; - callback(data); - }, - getMinifiedSource : function(callback) { - if (this.sourceCache.min != null) { - callback(this.sourceCache.min); - return; - } - var parser = require(this.dir.build + "/vendor/uglify/parse-js"); - var uglify = require(this.dir.build + "/vendor/uglify/process"); - var consolidator = require(this.dir.build + "/vendor/uglify/consolidator"); - var options = this.getOption("min") || {}; - var self = this; - - this.getSource(function(src) { - if (options.preparse) { - src = options.preparse(src); - } - - // parse code and get the initial AST - var ast = parser.parse(src, options.strict_semicolons || false); - - if (options.consolidate) { - ast = consolidator.ast_consolidate(ast); - } - if (options.lift_vars) { - ast = uglify.ast_lift_variables(ast); - } - - // get a new AST with mangled names - if (options.mangle) { - ast = uglify.ast_mangle(ast, options.mangle); - } - - // get an AST with compression optimizations - if (options.squeeze) { - options.squeeze.keep_comps = !(options.unsafe || false); - ast = uglify.ast_squeeze(ast, options.squeeze); - - // unsafe optimizations - if (options.unsafe) { - ast = uglify.ast_squeeze_more(ast); - } - } - - // compressed code here - var data = uglify.gen_code(ast, options.generate); - self.sourceCache.min = data; - callback(data); - }); - }, - getGzippedSource : function(callback) { - if (this.sourceCache.gzip != null) { - callback(this.sourceCache.gzip); - return; - } - var self = this; - this.getMinifiedSource(function(src) { - gzip(src, function(data) { - self.sourceCache.gzip = data; - callback(data); - }); - }); - }, - getCopyright : function(callback) { - if (this.sourceCache.copyright != null) { - callback(this.sourceCache.copyright); - return; - } - var self = this, copy = ""; - (this.wrap.copy || []).forEach(function(file) { - copy += fs.readFileSync(self.dir.src + "/" + file, "utf8"); - }); - copy = copy.replace(/@VERSION\b/g, this.version); - copy = copy.replace(/@DATE\b/g, (new Date()).toUTCString()); - this.replaceTokens.forEach(function(token) { - copy = copy.replace(new RegExp("@" + token.name + "\\b", "g"), token.value); - }); - this.sourceCache.copyright = copy; - callback(copy); - }, - readCacheFile : function(name, callback) { - var filename = this.dir.build + "/.cache." + name + ".json"; - if (callback === true) { - try { - return JSON.parse(fs.readFileSync(filename, "utf8")); - } catch (e) { - return null; - } - } else { - fs.readFile(filename, "utf8", function(error, data) { - if (error) { - callback(null); - return; - } - try { - callback(JSON.parse(data)); - } catch (e) { - callback(null); - } - }); - } - }, - writeCacheFile : function(name, data, callback, format) { - var filename = this.dir.build + "/.cache." + name + ".json"; - if (callback === true) { - fs.writeFileSync(filename, util.format(format || "%j", data), "utf8"); - } else { - fs.writeFile(filename, util.format(format || "%j", data), "utf8", function() { - callback(); - }); - } - }, - build : function() { - var steps = []; - Array.prototype.slice.call(process.argv, 2).forEach(function(arg) { - // push which build options we want - if (/^\w+$/.test(arg)) { - steps.push(arg); - } - }); - this.steps = cArray().getNewObject(steps.length === 0 ? (this.defaultTasks || []) : steps); - this.startTime = new Date(); - this.steps.serialEach(this.processStep, this.onComplete, this); - }, - processStep : function(next, step, index) { - var self = this; - this.time = (+new Date()); - this.currentStep = step.toLowerCase(); - try { - require(this.dir.build + "/module/" + this.currentStep + ".js")(this, function(data) { - data = data || {}; - data.name = step; - if (!data.time) { - data.time = (+new Date()) - self.time; - } - // trigger error handler - if (data.error) { - self.onError(data); - return; - } - self.printLine("Finished in " + self.color((data.time / 1000).toFixed(3), 171) + " seconds.\n"); - self.currentStep = null; - next(); - }); - } catch (e) { - this.onError({ - name : step, - error : e, - time : 0 - }); - } - }, - onError : function(data) { - this.printLine(); - this.printHeader(this.color("\u2716 ", 160) + "Build process failed on: " + this.color(data.name, 160) + " [" + data.error.message + " " + (data.error.stack.split("\n")[1] || "").trim() + "]\n"); - this.stop(); - }, - onComplete : function() { - var time = (+new Date()) - this.startTime; - this.printHeader(this.color("\u2714 ", 34) + "Build process completed in " + this.color((time / 1000).toFixed(3), 171) + " seconds.\n"); - setTimeout(function() { - process.exit(0); - }, 1); - }, - printHeader : function() { - process.stdout.write("\x1B[2K" + util.format.apply(this, arguments) + "\n"); - }, - printLine : function() { - process.stdout.write("\x1B[2K" + " " + util.format.apply(this, arguments) + "\n"); - }, - printTemp : function() { - process.stdout.write("\x1B[2K" + " " + util.format.apply(this, arguments) + "\r"); - }, - print : function() { - process.stdout.write(util.format.apply(this, arguments)); - }, - lpad : function(str, len, chr) { - var padLength = len - (str + "").replace(/\\x1B\[[0-9;]+m/g, "").length; - return Array(padLength + 1).join(chr || " ") + str; - }, - rpad : function(str, len, chr) { - var padLength = len - (str + "").replace(/\\x1B\[[0-9;]+m/g, "").length; - return str + Array(padLength + 1).join(chr || " "); - }, - color : function(string, color) { - if (typeof color === "number") { - return "\x1B[38;5;" + color + "m" + string + "\x1B[0m"; - } - if (color === "bold") { - return "\x1B[1m" + string + "\x1B[0m"; - } - return "\x1B[" + colors[color] + "m" + string + "\x1B[0m"; - }, - formatNumber : function(number) { - number = String(number).split("."); - return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ",") + (number[1] ? "." + number[1] : ""); - }, - stop : function() { - setTimeout(function() { - process.exit(1); - }, 1); - } -}); - -module.exports = Build; diff --git a/build/coverage/jscoverage-highlight.css b/build/coverage/jscoverage-highlight.css deleted file mode 100755 index d2ad01d..0000000 --- a/build/coverage/jscoverage-highlight.css +++ /dev/null @@ -1,38 +0,0 @@ -/* - jscoverage-highlight.css - JSCoverage syntax highlighting style sheet - Copyright (C) 2008, 2009, 2010 siliconforks.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -/* keyword, type, symbol, cbracket */ -#sourceTable .k { - font-weight: bold; -} - -/* string, regexp, number */ -#sourceTable .s { - color: #006400; -} - -/* specialchar */ -#sourceTable .t { - color: #2e8b57; -} - -/* comment */ -#sourceTable .c { - font-style: italic; -} diff --git a/build/coverage/jscoverage-ie.css b/build/coverage/jscoverage-ie.css deleted file mode 100755 index 05cad2a..0000000 --- a/build/coverage/jscoverage-ie.css +++ /dev/null @@ -1,108 +0,0 @@ -/* - jscoverage-ie.css - JSCoverage style sheet for Internet Explorer - Copyright (C) 2007, 2008, 2009, 2010 siliconforks.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#headingDiv { - position: static; - margin-left: 10px; - margin-right: 10px; - padding-top: 0.5em; -} - -#tabs { - clear: all; - position: static; - top: auto; - left: auto; - right: auto; - height: auto; - margin-left: 10px; - margin-right: 10px; -} - -#tabs div { - position: relative; - height: auto; - line-height: normal; - padding-top: 5px; - padding-bottom: 5px; -} - -#tabs div.selected { - padding-bottom: 6px; - z-index: 2; -} - -.TabPage { - position: relative; - top: -1px; - left: auto; - right: auto; - bottom: auto; - clear: left; - margin-left: 10px; - margin-right: 10px; - padding: 10px; - z-index: 1; -} - -#locationDiv { - margin-bottom: 10px; -} - -#iframeDiv { - position: static; - width: 100%; -} - -#summaryDiv { - position: static; - width: 100%; -} - -#fileDiv { - margin-bottom: 10px; -} - -#sourceDiv { - position: static; - width: 100%; -} - -#storeDiv { - position: static; - width: 100%; -} - -/* some defaults */ - -.TabPage { - height: 650px; -} - -#iframeDiv { - height: 600px; -} - -#summaryDiv { - height: 600px; -} - -#sourceDiv { - height: 600px; -} diff --git a/build/coverage/jscoverage-throbber.gif b/build/coverage/jscoverage-throbber.gif deleted file mode 100755 index f13c0b4ecc4327d891568b6494d60f0428741094..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 425 zcmZ?wbhEHbWM^P!c+AZJ1gxyA3JMB#c6JU94habfwY9Yk4GjwxEI4rBz=H=5{-XlL z|J;7AA;Hd$0j@@R2F#2={fa+X7`Yhu8FWB~fsAEf5&Ph&u(TrN>S}q#&`BOgn?s%^ zhV^T?;!vunS}Ag6b-d=(MIOf|ho~muQL2<$8FFRyeM?aWj}wbSQt>D~sr0mR%9Yjf zPE!>;PBMoq#ivwRwQ38{0bZhx9;cK;R1@$xKqa;6%azshgF*v64mgJ_#iR73%F-$k kU smaller than surrounding text. Because -the table already has font-size small, this would make the font-size within the -
           x-small.  So we don't rely on the default.
          -*/
          -table#sourceTable pre {
          -  font-size: medium;
          -}
          -
          -table#sourceTable td {
          -  border: 0px;
          -  padding-top: 0px;
          -  padding-bottom: 0px;
          -  padding-left: 10px;
          -  padding-right: 10px;
          -}
          -
          -table#sourceTable pre {
          -  border: 0px;
          -  margin: 0px;
          -}
          -
          -.g {
          -  background-color: #bfffbf;
          -}
          -
          -.y {
          -  background-color: #ffffbf;
          -}
          -
          -.r {
          -  background-color: #ffbfbf;
          -}
          -
          -/*******************************************************************************
          -store tab
          -*/
          -
          -#storeDiv {
          -  position: absolute;
          -  top: 3em;
          -  left: 1em;
          -  right: 1em;
          -  bottom: 1em;
          -  overflow: auto;
          -}
          -
          -/*******************************************************************************
          -about tab
          -*/
          -
          -p {
          -  margin-top: 0;
          -}
          -
          -/*******************************************************************************
          -tabs
          -*/
          -
          -#tabs {
          -  position: absolute;
          -  top: 3em;
          -  left: 1.5em;
          -  right: 1.5em;
          -  height: 2em;
          -}
          -
          -#tabs div {
          -  background-color: white;
          -  position: relative;
          -  float: left;
          -  border: 1px solid black;
          -  border-bottom-width: 0;
          -  cursor: pointer;
          -  margin-left: 0.5em;
          -  margin-right: 0.5em;
          -  padding-left: 0.5em;
          -  padding-right: 0.5em;
          -  height: 2em;
          -  z-index: 1;
          -  line-height: 1.8em;
          -}
          -
          -#tabs div.selected {
          -  z-index: 3;
          -  cursor: default;
          -}
          -
          -#tabs div.disabled {
          -  /* windows system color GrayText */
          -  color: #808080;
          -  cursor: default; 
          -}
          -
          -.TabPage {
          -  background-color: white;
          -  border: 1px solid black;
          -  position: absolute;
          -  top: 5em;
          -  left: 1.5em;
          -  right: 1.5em;
          -  bottom: 1.5em;
          -  z-index: 2;
          -  padding: 1em;
          -  display: none;
          -}
          -
          -#tabPages div.selected {
          -  display: block;
          -}
          -
          -img {
          -  visibility: hidden;
          -}
          diff --git a/build/coverage/jscoverage.html b/build/coverage/jscoverage.html
          deleted file mode 100755
          index 00d3518..0000000
          --- a/build/coverage/jscoverage.html
          +++ /dev/null
          @@ -1,164 +0,0 @@
          -
          -
          -
          -
          -
          -
          -JSCoverage
          -
          -
          -
          -
          -
          -
          -
          -
          - - -
          -

          -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you do either of the -following: -

          -
            -
          • If you are using the jscoverage program to instrument your -JavaScript code, install the instrumented files on a web server.
          • -
          • Use the jscoverage-server program (which itself acts as a web -server).
          • -
          -

          -See the -manual -for further details. -

          - -
          - -
          -

          -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you view coverage -reports stored to the filesystem by serving them from a web server. -

          -

          -See the -manual -for further details. -

          - -
          - -
          -
          Browser
          -
          Summary
          -
          Source
          -
          Store
          -
          About
          -
          -
          -
          -
          - URL: - - -
          -
          - -
          -
          -
          - -
          -
          - - - - - - - - - - - - - - - - - - - - - -
          FileStatementsExecutedCoverage
          - Total: - 0 - 00 -
          -
          -
          - 0% -
          -
          -
          -
          -
          -
          -
          -
          - - loading... -
          -
          -
          -

          - This is version 0.5.1 of JSCoverage, a program that calculates code - coverage statistics for JavaScript. -

          -

          - See http://siliconforks.com/jscoverage/ for more information. -

          -

          - Copyright © 2007, 2008, 2009, 2010 siliconforks.com -

          -
          -
          -
          - - diff --git a/build/coverage/jscoverage.js b/build/coverage/jscoverage.js deleted file mode 100755 index 4233615..0000000 --- a/build/coverage/jscoverage.js +++ /dev/null @@ -1,1176 +0,0 @@ -/* - jscoverage.js - code coverage for JavaScript - Copyright (C) 2007, 2008, 2009, 2010 siliconforks.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -function jscoverage_openWarningDialog() { - var id; - if (jscoverage_isReport) { - id = 'reportWarningDialog'; - } - else { - id = 'warningDialog'; - } - var dialog = document.getElementById(id); - dialog.style.display = 'block'; -} - -function jscoverage_closeWarningDialog() { - var id; - if (jscoverage_isReport) { - id = 'reportWarningDialog'; - } - else { - id = 'warningDialog'; - } - var dialog = document.getElementById(id); - dialog.style.display = 'none'; -} - -/** -Initializes the _$jscoverage object in a window. This should be the first -function called in the page. -@param w this should always be the global window object -*/ -function jscoverage_init(w) { - try { - // in Safari, "import" is a syntax error - Components.utils['import']('resource://app/modules/jscoverage.jsm'); - jscoverage_isInvertedMode = true; - return; - } - catch (e) {} - - // check if we are in inverted mode - if (w.opener) { - try { - if (w.opener.top._$jscoverage) { - jscoverage_isInvertedMode = true; - if (! w._$jscoverage) { - w._$jscoverage = w.opener.top._$jscoverage; - } - } - else { - jscoverage_isInvertedMode = false; - } - } - catch (e) { - try { - if (w.opener._$jscoverage) { - jscoverage_isInvertedMode = true; - if (! w._$jscoverage) { - w._$jscoverage = w.opener._$jscoverage; - } - } - else { - jscoverage_isInvertedMode = false; - } - } - catch (e2) { - jscoverage_isInvertedMode = false; - } - } - } - else { - jscoverage_isInvertedMode = false; - } - - if (! jscoverage_isInvertedMode) { - if (! w._$jscoverage) { - w._$jscoverage = {}; - } - } -} - -var jscoverage_currentFile = null; -var jscoverage_currentLine = null; - -var jscoverage_inLengthyOperation = false; - -/* -Possible states: - isInvertedMode isServer isReport tabs -normal false false false Browser -inverted true false false -server, normal false true false Browser, Store -server, inverted true true false Store -report false false true -*/ -var jscoverage_isInvertedMode = false; -var jscoverage_isServer = false; -var jscoverage_isReport = false; - -jscoverage_init(window); - -function jscoverage_createRequest() { - // Note that the IE7 XMLHttpRequest does not support file URL's. - // http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html - // http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx -//#JSCOVERAGE_IF - if (window.ActiveXObject) { - return new ActiveXObject("Microsoft.XMLHTTP"); - } - else { - return new XMLHttpRequest(); - } -} - -// http://www.quirksmode.org/js/findpos.html -function jscoverage_findPos(obj) { - var result = 0; - do { - result += obj.offsetTop; - obj = obj.offsetParent; - } - while (obj); - return result; -} - -// http://www.quirksmode.org/viewport/compatibility.html -function jscoverage_getViewportHeight() { -//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) - if (self.innerHeight) { - // all except Explorer - return self.innerHeight; - } - else if (document.documentElement && document.documentElement.clientHeight) { - // Explorer 6 Strict Mode - return document.documentElement.clientHeight; - } - else if (document.body) { - // other Explorers - return document.body.clientHeight; - } - else { - throw "Couldn't calculate viewport height"; - } -//#JSCOVERAGE_ENDIF -} - -/** -Indicates visually that a lengthy operation has begun. The progress bar is -displayed, and the cursor is changed to busy (on browsers which support this). -*/ -function jscoverage_beginLengthyOperation() { - jscoverage_inLengthyOperation = true; - - var progressBar = document.getElementById('progressBar'); - progressBar.style.visibility = 'visible'; - ProgressBar.setPercentage(progressBar, 0); - var progressLabel = document.getElementById('progressLabel'); - progressLabel.style.visibility = 'visible'; - - /* blacklist buggy browsers */ -//#JSCOVERAGE_IF - if (! /Opera|WebKit/.test(navigator.userAgent)) { - /* - Change the cursor style of each element. Note that changing the class of the - element (to one with a busy cursor) is buggy in IE. - */ - var tabs = document.getElementById('tabs').getElementsByTagName('div'); - var i; - for (i = 0; i < tabs.length; i++) { - tabs.item(i).style.cursor = 'wait'; - } - } -} - -/** -Removes the progress bar and busy cursor. -*/ -function jscoverage_endLengthyOperation() { - var progressBar = document.getElementById('progressBar'); - ProgressBar.setPercentage(progressBar, 100); - setTimeout(function() { - jscoverage_inLengthyOperation = false; - progressBar.style.visibility = 'hidden'; - var progressLabel = document.getElementById('progressLabel'); - progressLabel.style.visibility = 'hidden'; - progressLabel.innerHTML = ''; - - var tabs = document.getElementById('tabs').getElementsByTagName('div'); - var i; - for (i = 0; i < tabs.length; i++) { - tabs.item(i).style.cursor = ''; - } - }, 50); -} - -function jscoverage_setSize() { -//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) - var viewportHeight = jscoverage_getViewportHeight(); - - /* - border-top-width: 1px - padding-top: 10px - padding-bottom: 10px - border-bottom-width: 1px - margin-bottom: 10px - ---- - 32px - */ - var tabPages = document.getElementById('tabPages'); - var tabPageHeight = (viewportHeight - jscoverage_findPos(tabPages) - 32) + 'px'; - var nodeList = tabPages.childNodes; - var length = nodeList.length; - for (var i = 0; i < length; i++) { - var node = nodeList.item(i); - if (node.nodeType !== 1) { - continue; - } - node.style.height = tabPageHeight; - } - - var iframeDiv = document.getElementById('iframeDiv'); - // may not exist if we have removed the first tab - if (iframeDiv) { - iframeDiv.style.height = (viewportHeight - jscoverage_findPos(iframeDiv) - 21) + 'px'; - } - - var summaryDiv = document.getElementById('summaryDiv'); - summaryDiv.style.height = (viewportHeight - jscoverage_findPos(summaryDiv) - 21) + 'px'; - - var sourceDiv = document.getElementById('sourceDiv'); - sourceDiv.style.height = (viewportHeight - jscoverage_findPos(sourceDiv) - 21) + 'px'; - - var storeDiv = document.getElementById('storeDiv'); - if (storeDiv) { - storeDiv.style.height = (viewportHeight - jscoverage_findPos(storeDiv) - 21) + 'px'; - } -//#JSCOVERAGE_ENDIF -} - -/** -Returns the boolean value of a string. Values 'false', 'f', 'no', 'n', 'off', -and '0' (upper or lower case) are false. -@param s the string -@return a boolean value -*/ -function jscoverage_getBooleanValue(s) { - s = s.toLowerCase(); - if (s === 'false' || s === 'f' || s === 'no' || s === 'n' || s === 'off' || s === '0') { - return false; - } - return true; -} - -function jscoverage_removeTab(id) { - var tab = document.getElementById(id + 'Tab'); - tab.parentNode.removeChild(tab); - var tabPage = document.getElementById(id + 'TabPage'); - tabPage.parentNode.removeChild(tabPage); -} - -function jscoverage_isValidURL(url) { - // RFC 3986 - var matches = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/.exec(url); - if (matches === null) { - return false; - } - var scheme = matches[1]; - if (typeof scheme === 'string') { - scheme = scheme.toLowerCase(); - return scheme === '' || scheme === 'file:' || scheme === 'http:' || scheme === 'https:'; - } - return true; -} - -/** -Initializes the contents of the tabs. This sets the initial values of the -input field and iframe in the "Browser" tab and the checkbox in the "Summary" -tab. -@param queryString this should always be location.search -*/ -function jscoverage_initTabContents(queryString) { - var showMissingColumn = false; - var url = null; - var windowURL = null; - var parameters, parameter, i, index, name, value; - if (queryString.length > 0) { - // chop off the question mark - queryString = queryString.substring(1); - parameters = queryString.split(/&|;/); - for (i = 0; i < parameters.length; i++) { - parameter = parameters[i]; - index = parameter.indexOf('='); - if (index === -1) { - // still works with old syntax - url = decodeURIComponent(parameter); - } - else { - name = parameter.substr(0, index); - value = decodeURIComponent(parameter.substr(index + 1)); - if (name === 'missing' || name === 'm') { - showMissingColumn = jscoverage_getBooleanValue(value); - } - else if (name === 'url' || name === 'u' || name === 'frame' || name === 'f') { - url = value; - } - else if (name === 'window' || name === 'w') { - windowURL = value; - } - } - } - } - - var checkbox = document.getElementById('checkbox'); - checkbox.checked = showMissingColumn; - if (showMissingColumn) { - jscoverage_appendMissingColumn(); - } - - var isValidURL = function (url) { - var result = jscoverage_isValidURL(url); - if (! result) { - alert('Invalid URL: ' + url); - } - return result; - }; - - if (url !== null && isValidURL(url)) { - // this will automatically propagate to the input field - frames[0].location = url; - } - else if (windowURL !== null && isValidURL(windowURL)) { - window.open(windowURL); - } - - // if the browser tab is absent, we have to initialize the summary tab - if (! document.getElementById('browserTab')) { - jscoverage_recalculateSummaryTab(); - } -} - -function jscoverage_body_load() { - // check if this is a file: URL - if (window.location && window.location.href && /^file:/i.test(window.location.href)) { - var warningDiv = document.getElementById('warningDiv'); - warningDiv.style.display = 'block'; - } - - var progressBar = document.getElementById('progressBar'); - ProgressBar.init(progressBar); - - function reportError(e) { - jscoverage_endLengthyOperation(); - var summaryThrobber = document.getElementById('summaryThrobber'); - summaryThrobber.style.visibility = 'hidden'; - var div = document.getElementById('summaryErrorDiv'); - div.innerHTML = 'Error: ' + e; - } - - if (jscoverage_isReport) { - jscoverage_beginLengthyOperation(); - var summaryThrobber = document.getElementById('summaryThrobber'); - summaryThrobber.style.visibility = 'visible'; - var request = jscoverage_createRequest(); - try { - request.open('GET', 'jscoverage.json', true); - request.onreadystatechange = function (event) { - if (request.readyState === 4) { - try { - if (request.status !== 0 && request.status !== 200) { - throw request.status; - } - var response = request.responseText; - if (response === '') { - throw 404; - } - - var json; - if (window.JSON && window.JSON.parse) { - json = window.JSON.parse(response); - } - else { - json = eval('(' + response + ')'); - } - - var file; - for (file in json) { - if (! json.hasOwnProperty(file)) { - continue; - } - - var fileCoverage = json[file]; - _$jscoverage[file] = fileCoverage.coverage; - _$jscoverage[file].source = fileCoverage.source; - } - jscoverage_recalculateSummaryTab(); - summaryThrobber.style.visibility = 'hidden'; - } - catch (e) { - reportError(e); - } - } - }; - request.send(null); - } - catch (e) { - reportError(e); - } - - jscoverage_removeTab('browser'); - jscoverage_removeTab('store'); - } - else { - if (jscoverage_isInvertedMode) { - jscoverage_removeTab('browser'); - } - - if (! jscoverage_isServer) { - jscoverage_removeTab('store'); - } - } - - jscoverage_initTabControl(); - - jscoverage_initTabContents(location.search); -} - -function jscoverage_body_resize() { - if (/MSIE/.test(navigator.userAgent)) { - jscoverage_setSize(); - } -} - -// ----------------------------------------------------------------------------- -// tab 1 - -function jscoverage_updateBrowser() { - var input = document.getElementById("location"); - frames[0].location = input.value; -} - -function jscoverage_openWindow() { - var input = document.getElementById("location"); - var url = input.value; - window.open(url); -} - -function jscoverage_input_keypress(e) { - if (e.keyCode === 13) { - if (e.shiftKey) { - jscoverage_openWindow(); - } - else { - jscoverage_updateBrowser(); - } - } -} - -function jscoverage_openInFrameButton_click() { - jscoverage_updateBrowser(); -} - -function jscoverage_openInWindowButton_click() { - jscoverage_openWindow(); -} - -function jscoverage_browser_load() { - /* update the input box */ - var input = document.getElementById("location"); - - /* sometimes IE seems to fire this after the tab has been removed */ - if (input) { - input.value = frames[0].location; - } -} - -// ----------------------------------------------------------------------------- -// tab 2 - -function jscoverage_createHandler(file, line) { - return function () { - jscoverage_get(file, line); - return false; - }; -} - -function jscoverage_createLink(file, line) { - var link = document.createElement("a"); - link.href = '#'; - link.onclick = jscoverage_createHandler(file, line); - - var text; - if (line) { - text = line.toString(); - } - else { - text = file; - } - - link.appendChild(document.createTextNode(text)); - - return link; -} - -function jscoverage_recalculateSummaryTab(cc) { - var checkbox = document.getElementById('checkbox'); - var showMissingColumn = checkbox.checked; - - if (! cc) { - cc = window._$jscoverage; - } - if (! cc) { -//#JSCOVERAGE_IF 0 - throw "No coverage information found."; -//#JSCOVERAGE_ENDIF - } - - var tbody = document.getElementById("summaryTbody"); - while (tbody.hasChildNodes()) { - tbody.removeChild(tbody.firstChild); - } - - var totals = { files:0, statements:0, executed:0 }; - - var file; - var files = []; - for (file in cc) { - if (! cc.hasOwnProperty(file)) { - continue; - } - - files.push(file); - } - files.sort(); - - var rowCounter = 0; - for (var f = 0; f < files.length; f++) { - file = files[f]; - var lineNumber; - var num_statements = 0; - var num_executed = 0; - var missing = []; - var fileCC = cc[file]; - var length = fileCC.length; - var currentConditionalEnd = 0; - var conditionals = null; - if (fileCC.conditionals) { - conditionals = fileCC.conditionals; - } - for (lineNumber = 0; lineNumber < length; lineNumber++) { - var n = fileCC[lineNumber]; - - if (lineNumber === currentConditionalEnd) { - currentConditionalEnd = 0; - } - else if (currentConditionalEnd === 0 && conditionals && conditionals[lineNumber]) { - currentConditionalEnd = conditionals[lineNumber]; - } - - if (currentConditionalEnd !== 0) { - continue; - } - - if (n === undefined || n === null) { - continue; - } - - if (n === 0) { - missing.push(lineNumber); - } - else { - num_executed++; - } - num_statements++; - } - - var percentage = ( num_statements === 0 ? 0 : parseInt(100 * num_executed / num_statements) ); - - var row = document.createElement("tr"); - row.className = ( rowCounter++ % 2 == 0 ? "odd" : "even" ); - - var cell = document.createElement("td"); - cell.className = 'leftColumn'; - var link = jscoverage_createLink(file); - cell.appendChild(link); - - row.appendChild(cell); - - cell = document.createElement("td"); - cell.className = 'numeric'; - cell.appendChild(document.createTextNode(num_statements)); - row.appendChild(cell); - - cell = document.createElement("td"); - cell.className = 'numeric'; - cell.appendChild(document.createTextNode(num_executed)); - row.appendChild(cell); - - // new coverage td containing a bar graph - cell = document.createElement("td"); - cell.className = 'coverage'; - var pctGraph = document.createElement("div"), - covered = document.createElement("div"), - pct = document.createElement("span"); - pctGraph.className = "pctGraph"; - if( num_statements === 0 ) { - covered.className = "skipped"; - pct.appendChild(document.createTextNode("N/A")); - } else { - covered.className = "covered"; - covered.style.width = percentage + "px"; - pct.appendChild(document.createTextNode(percentage + '%')); - } - pct.className = "pct"; - pctGraph.appendChild(covered); - cell.appendChild(pctGraph); - cell.appendChild(pct); - row.appendChild(cell); - - if (showMissingColumn) { - cell = document.createElement("td"); - for (var i = 0; i < missing.length; i++) { - if (i !== 0) { - cell.appendChild(document.createTextNode(", ")); - } - link = jscoverage_createLink(file, missing[i]); - - // group contiguous missing lines; e.g., 10, 11, 12 -> 10-12 - var j, start = missing[i]; - for (;;) { - j = 1; - while (i + j < missing.length && missing[i + j] == missing[i] + j) { - j++; - } - var nextmissing = missing[i + j], cur = missing[i] + j; - if (isNaN(nextmissing)) { - break; - } - while (cur < nextmissing && ! fileCC[cur]) { - cur++; - } - if (cur < nextmissing || cur >= length) { - break; - } - i += j; - } - if (start != missing[i] || j > 1) { - i += j - 1; - link.innerHTML += "-" + missing[i]; - } - - cell.appendChild(link); - } - row.appendChild(cell); - } - - tbody.appendChild(row); - - totals['files'] ++; - totals['statements'] += num_statements; - totals['executed'] += num_executed; - - // write totals data into summaryTotals row - var tr = document.getElementById("summaryTotals"); - if (tr) { - var tds = tr.getElementsByTagName("td"); - tds[0].getElementsByTagName("span")[1].firstChild.nodeValue = totals['files']; - tds[1].firstChild.nodeValue = totals['statements']; - tds[2].firstChild.nodeValue = totals['executed']; - - var coverage = parseInt(100 * totals['executed'] / totals['statements']); - if( isNaN( coverage ) ) { - coverage = 0; - } - tds[3].getElementsByTagName("span")[0].firstChild.nodeValue = coverage + '%'; - tds[3].getElementsByTagName("div")[1].style.width = coverage + 'px'; - } - - } - jscoverage_endLengthyOperation(); -} - -function jscoverage_appendMissingColumn() { - var headerRow = document.getElementById('headerRow'); - var missingHeader = document.createElement('th'); - missingHeader.id = 'missingHeader'; - missingHeader.innerHTML = 'Missing'; - headerRow.appendChild(missingHeader); - var summaryTotals = document.getElementById('summaryTotals'); - var empty = document.createElement('td'); - empty.id = 'missingCell'; - summaryTotals.appendChild(empty); -} - -function jscoverage_removeMissingColumn() { - var missingNode; - missingNode = document.getElementById('missingHeader'); - missingNode.parentNode.removeChild(missingNode); - missingNode = document.getElementById('missingCell'); - missingNode.parentNode.removeChild(missingNode); -} - -function jscoverage_checkbox_click() { - if (jscoverage_inLengthyOperation) { - return false; - } - jscoverage_beginLengthyOperation(); - var checkbox = document.getElementById('checkbox'); - var showMissingColumn = checkbox.checked; - setTimeout(function() { - if (showMissingColumn) { - jscoverage_appendMissingColumn(); - } - else { - jscoverage_removeMissingColumn(); - } - jscoverage_recalculateSummaryTab(); - }, 50); - return true; -} - -// ----------------------------------------------------------------------------- -// tab 3 - -function jscoverage_makeTable() { - var coverage = _$jscoverage[jscoverage_currentFile]; - var lines = coverage.source; - - // this can happen if there is an error in the original JavaScript file - if (! lines) { - lines = []; - } - - var rows = ['']; - var i = 0; - var progressBar = document.getElementById('progressBar'); - var tableHTML; - var currentConditionalEnd = 0; - - function joinTableRows() { - tableHTML = rows.join(''); - ProgressBar.setPercentage(progressBar, 60); - /* - This may be a long delay, so set a timeout of 100 ms to make sure the - display is updated. - */ - setTimeout(appendTable, 100); - } - - function appendTable() { - var sourceDiv = document.getElementById('sourceDiv'); - sourceDiv.innerHTML = tableHTML; - ProgressBar.setPercentage(progressBar, 80); - setTimeout(jscoverage_scrollToLine, 0); - } - - while (i < lines.length) { - var lineNumber = i + 1; - - if (lineNumber === currentConditionalEnd) { - currentConditionalEnd = 0; - } - else if (currentConditionalEnd === 0 && coverage.conditionals && coverage.conditionals[lineNumber]) { - currentConditionalEnd = coverage.conditionals[lineNumber]; - } - - var row = ''; - row += ''; - var timesExecuted = coverage[lineNumber]; - if (timesExecuted !== undefined && timesExecuted !== null) { - if (currentConditionalEnd !== 0) { - row += ''; - } - else { - row += ''; - } - row += ''; - row += ''; - row += '\n'; - rows[lineNumber] = row; - i++; - } - rows[i + 1] = '
          ' + lineNumber + ''; - } - else if (timesExecuted === 0) { - row += ''; - } - else { - row += ''; - } - row += timesExecuted; - row += '
          ' + lines[i] + '
          '; - ProgressBar.setPercentage(progressBar, 40); - setTimeout(joinTableRows, 0); -} - -function jscoverage_scrollToLine() { - jscoverage_selectTab('sourceTab'); - if (! window.jscoverage_currentLine) { - jscoverage_endLengthyOperation(); - return; - } - var div = document.getElementById('sourceDiv'); - if (jscoverage_currentLine === 1) { - div.scrollTop = 0; - } - else { - var cell = document.getElementById('line-' + jscoverage_currentLine); - - // this might not be there if there is an error in the original JavaScript - if (cell) { - var divOffset = jscoverage_findPos(div); - var cellOffset = jscoverage_findPos(cell); - div.scrollTop = cellOffset - divOffset; - } - } - jscoverage_currentLine = 0; - jscoverage_endLengthyOperation(); -} - -/** -Loads the given file (and optional line) in the source tab. -*/ -function jscoverage_get(file, line) { - if (jscoverage_inLengthyOperation) { - return; - } - jscoverage_beginLengthyOperation(); - setTimeout(function() { - var sourceDiv = document.getElementById('sourceDiv'); - sourceDiv.innerHTML = ''; - jscoverage_selectTab('sourceTab'); - if (file === jscoverage_currentFile) { - jscoverage_currentLine = line; - jscoverage_recalculateSourceTab(); - } - else { - if (jscoverage_currentFile === null) { - var tab = document.getElementById('sourceTab'); - tab.className = ''; - tab.onclick = jscoverage_tab_click; - } - jscoverage_currentFile = file; - jscoverage_currentLine = line || 1; // when changing the source, always scroll to top - var fileDiv = document.getElementById('fileDiv'); - fileDiv.innerHTML = jscoverage_currentFile; - jscoverage_recalculateSourceTab(); - return; - } - }, 50); -} - -/** -Calculates coverage statistics for the current source file. -*/ -function jscoverage_recalculateSourceTab() { - if (! jscoverage_currentFile) { - jscoverage_endLengthyOperation(); - return; - } - var progressLabel = document.getElementById('progressLabel'); - progressLabel.innerHTML = 'Calculating coverage ...'; - var progressBar = document.getElementById('progressBar'); - ProgressBar.setPercentage(progressBar, 20); - setTimeout(jscoverage_makeTable, 0); -} - -// ----------------------------------------------------------------------------- -// tabs - -/** -Initializes the tab control. This function must be called when the document is -loaded. -*/ -function jscoverage_initTabControl() { - var tabs = document.getElementById('tabs'); - var i; - var child; - var tabNum = 0; - for (i = 0; i < tabs.childNodes.length; i++) { - child = tabs.childNodes.item(i); - if (child.nodeType === 1) { - if (child.className !== 'disabled') { - child.onclick = jscoverage_tab_click; - } - tabNum++; - } - } - jscoverage_selectTab(0); -} - -/** -Selects a tab. -@param tab the integer index of the tab (0, 1, 2, or 3) - OR - the ID of the tab element - OR - the tab element itself -*/ -function jscoverage_selectTab(tab) { - if (typeof tab !== 'number') { - tab = jscoverage_tabIndexOf(tab); - } - var tabs = document.getElementById('tabs'); - var tabPages = document.getElementById('tabPages'); - var nodeList; - var tabNum; - var i; - var node; - - nodeList = tabs.childNodes; - tabNum = 0; - for (i = 0; i < nodeList.length; i++) { - node = nodeList.item(i); - if (node.nodeType !== 1) { - continue; - } - - if (node.className !== 'disabled') { - if (tabNum === tab) { - node.className = 'selected'; - } - else { - node.className = ''; - } - } - tabNum++; - } - - nodeList = tabPages.childNodes; - tabNum = 0; - for (i = 0; i < nodeList.length; i++) { - node = nodeList.item(i); - if (node.nodeType !== 1) { - continue; - } - - if (tabNum === tab) { - node.className = 'selected TabPage'; - } - else { - node.className = 'TabPage'; - } - tabNum++; - } -} - -/** -Returns an integer (0, 1, 2, or 3) representing the index of a given tab. -@param tab the ID of the tab element - OR - the tab element itself -*/ -function jscoverage_tabIndexOf(tab) { - if (typeof tab === 'string') { - tab = document.getElementById(tab); - } - var tabs = document.getElementById('tabs'); - var i; - var child; - var tabNum = 0; - for (i = 0; i < tabs.childNodes.length; i++) { - child = tabs.childNodes.item(i); - if (child.nodeType === 1) { - if (child === tab) { - return tabNum; - } - tabNum++; - } - } -//#JSCOVERAGE_IF 0 - throw "Tab not found"; -//#JSCOVERAGE_ENDIF -} - -function jscoverage_tab_click(e) { - if (jscoverage_inLengthyOperation) { - return; - } - var target; -//#JSCOVERAGE_IF - if (e) { - target = e.target; - } - else if (window.event) { - // IE - target = window.event.srcElement; - } - if (target.className === 'selected') { - return; - } - jscoverage_beginLengthyOperation(); - setTimeout(function() { - if (target.id === 'summaryTab') { - var tbody = document.getElementById("summaryTbody"); - while (tbody.hasChildNodes()) { - tbody.removeChild(tbody.firstChild); - } - } - else if (target.id === 'sourceTab') { - var sourceDiv = document.getElementById('sourceDiv'); - sourceDiv.innerHTML = ''; - } - jscoverage_selectTab(target); - if (target.id === 'summaryTab') { - jscoverage_recalculateSummaryTab(); - } - else if (target.id === 'sourceTab') { - jscoverage_recalculateSourceTab(); - } - else { - jscoverage_endLengthyOperation(); - } - }, 50); -} - -// ----------------------------------------------------------------------------- -// progress bar - -var ProgressBar = { - init: function(element) { - element._percentage = 0; - - /* doing this via JavaScript crashes Safari */ -/* - var pctGraph = document.createElement('div'); - pctGraph.className = 'pctGraph'; - element.appendChild(pctGraph); - var covered = document.createElement('div'); - covered.className = 'covered'; - pctGraph.appendChild(covered); - var pct = document.createElement('span'); - pct.className = 'pct'; - element.appendChild(pct); -*/ - - ProgressBar._update(element); - }, - setPercentage: function(element, percentage) { - element._percentage = percentage; - ProgressBar._update(element); - }, - _update: function(element) { - var pctGraph = element.getElementsByTagName('div').item(0); - var covered = pctGraph.getElementsByTagName('div').item(0); - var pct = element.getElementsByTagName('span').item(0); - pct.innerHTML = element._percentage.toString() + '%'; - covered.style.width = element._percentage + 'px'; - } -}; - -// ----------------------------------------------------------------------------- -// reports - -function jscoverage_pad(s) { - return '0000'.substr(s.length) + s; -} - -function jscoverage_quote(s) { - return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) { - switch (c) { - case '\b': - return '\\b'; - case '\f': - return '\\f'; - case '\n': - return '\\n'; - case '\r': - return '\\r'; - case '\t': - return '\\t'; - // IE doesn't support this - /* - case '\v': - return '\\v'; - */ - case '"': - return '\\"'; - case '\\': - return '\\\\'; - default: - return '\\u' + jscoverage_pad(c.charCodeAt(0).toString(16)); - } - }) + '"'; -} - -function jscoverage_serializeCoverageToJSON() { - var json = []; - for (var file in _$jscoverage) { - if (! _$jscoverage.hasOwnProperty(file)) { - continue; - } - - var coverage = _$jscoverage[file]; - - var array = []; - var length = coverage.length; - for (var line = 0; line < length; line++) { - var value = coverage[line]; - if (value === undefined || value === null) { - value = 'null'; - } - array.push(value); - } - - var source = coverage.source; - var lines = []; - length = source.length; - for (var line = 0; line < length; line++) { - lines.push(jscoverage_quote(source[line])); - } - - json.push(jscoverage_quote(file) + ':{"coverage":[' + array.join(',') + '],"source":[' + lines.join(',') + ']}'); - } - return '{' + json.join(',') + '}'; -} - -function jscoverage_storeButton_click() { - if (jscoverage_inLengthyOperation) { - return; - } - - jscoverage_beginLengthyOperation(); - var img = document.getElementById('storeImg'); - img.style.visibility = 'visible'; - - var request = jscoverage_createRequest(); - request.open('POST', '/jscoverage-store', true); - request.onreadystatechange = function (event) { - if (request.readyState === 4) { - var message; - try { - if (request.status !== 200 && request.status !== 201 && request.status !== 204) { - throw request.status; - } - message = request.responseText; - } - catch (e) { - if (e.toString().search(/^\d{3}$/) === 0) { - message = e + ': ' + request.responseText; - } - else { - message = 'Could not connect to server: ' + e; - } - } - - jscoverage_endLengthyOperation(); - var img = document.getElementById('storeImg'); - img.style.visibility = 'hidden'; - - var div = document.getElementById('storeDiv'); - div.appendChild(document.createTextNode(new Date() + ': ' + message)); - div.appendChild(document.createElement('br')); - } - }; - request.setRequestHeader('Content-Type', 'application/json'); - var json = jscoverage_serializeCoverageToJSON(); - request.setRequestHeader('Content-Length', json.length.toString()); - request.send(json); -} diff --git a/build/jscoverage.html b/build/jscoverage.html deleted file mode 100755 index 6c49352..0000000 --- a/build/jscoverage.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - -JSCoverage - - - - - - - -
          - - -
          -

          -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you do either of the -following: -

          -
            -
          • If you are using the jscoverage program to instrument your -JavaScript code, install the instrumented files on a web server.
          • -
          • Use the jscoverage-server program (which itself acts as a web -server).
          • -
          -

          -See the -manual -for further details. -

          - -
          - -
          -

          -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you view coverage -reports stored to the filesystem by serving them from a web server. -

          -

          -See the -manual -for further details. -

          - -
          - -
          -
          Browser
          -
          Summary
          -
          Source
          -
          Store
          -
          About
          -
          -
          -
          -
          - URL: - - -
          -
          - -
          -
          -
          - -
          -
          - - - - - - - - - - - - - - - - - - - - - -
          FileStatementsExecutedCoverage
          - Total: - 0 - 00 -
          -
          -
          - 0% -
          -
          -
          -
          -
          -
          -
          -
          - - loading... -
          -
          -
          -

          - This is version 0.5.1 of JSCoverage, a program that calculates code - coverage statistics for JavaScript. -

          -

          - See http://siliconforks.com/jscoverage/ for more information. -

          -

          - Copyright © 2007, 2008, 2009, 2010 siliconforks.com -

          -
          -
          -
          - - - diff --git a/build/module/browserstack.js b/build/module/browserstack.js deleted file mode 100755 index 4828350..0000000 --- a/build/module/browserstack.js +++ /dev/null @@ -1,408 +0,0 @@ -// include the necessary module -var fs = require("fs"); -var childProcess = childProcess = require("child_process"); -var http = require("http"); -var url = require("url"); -var path = require("path"); -var BrowserStack = require("../vendor/browserstack/browserstack.js"); -var io = require("socket.io"); -// classify library -var Classify = require("../vendor/classify/classify.min.js"); -// require the special array library -require("../vendor/classify/classify-array.min.js")(Classify); -var cArray = Classify("/Array"); - -var Browser = Classify.create({ - __static_ : { - uaBrowserMatch : { - chrome : /chrome\/(\d+(\.\d+)?)/, - safari : /version\/(\d+(\.\d+)?)/, - opera : /version\/(\d+(\.\d+)?)/, - firefox : /firefox\/(\d+(\.\d+)?)/, - msie : /msie (\d+(\.\d+)?)/ - }, - uaToBrowser : function(ua) { - var browser = { - browser : "none", - version : 0, - os : "other" - }; - var osMatches, browserMatches, versionMatches; - ua = ua.toLowerCase(); - - osMatches = /(windows|mac|linux)/.exec(ua); - if (osMatches == null) { - return; - } - browser.os = osMatches[1]; - - browserMatches = /(chrome|safari|opera|firefox|msie)/.exec(ua); - if (browserMatches == null) { - return; - } - browser.browser = browserMatches[1]; - versionMatches = this.uaBrowserMatch[browser.browser].exec(ua); - if (versionMatches == null) { - return; - } - // clean up - if (browser.browser === "msie") { - browser.browser = "ie"; - } - if (browser.os === "windows") { - browser.os = "win"; - } - - browser.version = versionMatches[1]; - return browser.browser + " " + browser.version + " " + browser.os; - } - }, - init : function(build, config) { - this.os = config.os; - this.device = config.device; - this.browser = config.browser; - this.version = config.version; - this.name = (this.browser || this.device) + " " + this.version + " " + this.os; - this.build = build; - this.id = 0; - - this.runtime = 0; - this.failed = 0; - this.passed = 0; - this.total = 0; - this.results = {}; - }, - setBrowserStackClient : function(client) { - this.browserstack = client; - }, - setSocket : function(socket) { - var self = this, index = 0; - this.socket = socket; - this.build.printLine(this.build.color("= ", 34) + "Browser " + this.build.color(this.name, "bold") + " connected"); - socket.on("assertionDone", function(data) { - data.index = ++index; - self.logEvent("assertionDone", data); - }); - socket.on("testStart", function(data) { - self.logEvent("testStart", data); - }); - socket.on("testDone", function(data) { - self.logEvent("testDone", data); - }); - socket.on("moduleStart", function(data) { - self.logEvent("moduleStart", data); - }); - socket.on("moduleDone", function(data) { - self.logEvent("moduleDone", data); - }); - socket.on("done", function(data) { - self.logEvent("done", data); - }); - }, - setCallback : function(callback) { - this.callback = callback; - }, - start : function() { - var self = this; - var options = { - version : this.version, - os : this.os, - url : "http://" + (self.build.getOption("browserstack.ip") || "127.0.0.1") + ":" + parseInt(self.build.getOption("browserstack.port") || 80, 10) + "/build/bridge/qunit-browserstack-bridge.html?__browser=" + encodeURIComponent(this.name), - timeout : 60 - }; - if (this.browser) { - options.browser = this.browser; - } else if (this.device) { - options.device = this.device; - } - - this.browserstack.createWorker(options, function(error, worker) { - if (error) { - self.callback(); - return; - } - self.build.printLine(self.build.color("* ", 34) + "Browser " + self.build.color(self.name, "bold") + " initialized"); - self.id = worker.id; - self.onWait(); - }); - }, - stopWorker : function(callback) { - var self = this; - if (this.id) { - this.browserstack.terminateWorker(this.id, function() { - self.id = 0; - if (callback) { - callback(); - } - }); - } else { - if (callback) { - callback(); - } - } - return this; - }, - onWait : function() { - var self = this, i = 0, pattern = [ "|", "/", "-", "\\" ]; - var runner = function() { - self.browserstack.getWorker(self.id, function(error, worker) { - if (worker.status !== "running") { - self.build.printTemp(pattern[i++ % 4] + " Waiting for: " + self.build.color(self.name, "bold")); - setTimeout(runner, 1000); - } - }); - }; - runner(); - }, - logEvent : function(type, data) { - switch (type) { - case "assertionDone": - if (data.result === false) { - if (!this.results[data.module]) { - this.results[data.module] = []; - } - this.results[data.module].push(data); - } - break; - case "testStart": - this.build.printTemp("Running: " + this.name + " " + this.build.color(data.module, "bold") + " " + data.name); - break; - case "testDone": - break; - case "moduleStart": - break; - case "moduleDone": - break; - case "done": - this.failed = data.failed; - this.passed = data.passed; - this.total = data.total; - this.runtime = data.runtime; - if (this.failed > 0) { - this.build.printLine(this.build.color("\u2716 ", 160) + "Browser " + this.build.color(this.name, "bold") + " completed tests"); - } else { - this.build.printLine(this.build.color("\u2714 ", 34) + "Browser " + this.build.color(this.name, "bold") + " completed tests"); - } - this.stopWorker(); - this.callback(); - break; - } - }, - process : function() { - var self = this, build = this.build; - build.printLine("Tests results for: " + build.color(this.name, "bold")); - Object.keys(this.results).forEach(function(test) { - build.printLine(build.color("Module: ", "bold") + test); - self.results[test].forEach(function(assertion) { - build.printLine(" " + (assertion.result ? build.color("\u2714 ", 34) : build.color("\u2716 ", 160)) + build.color("Test # ", "bold") + assertion.index + "/" + self.total); - build.printLine(" " + assertion.message + " [" + build.color(assertion.test, 248) + "]"); - if (typeof assertion.expected !== "undefined") { - build.printLine(" -> " + build.color("Expected: " + assertion.expected, 34)); - // if test failed, then we need to output the result - if (!assertion.result) { - build.printLine(" -> " + build.color("Result: " + assertion.actual, 160)); - } - } - }); - }); - - if (this.failed > 0) { - build.printLine(build.color("\u2716 ", 160) + this.failed + " / " + this.total + " Failed"); - } else { - build.printLine(build.color("\u2714 ", 34) + "All tests [" + this.passed + " / " + this.total + "] passed!"); - } - build.printLine(); - } -}); - -var BrowserList = Classify.create({ - init : function(build, server) { - this.build = build; - this.browsers = {}; - this.validbrowsers = null; - this.client = BrowserStack.createClient({ - username : this.build.getOption("browserstack.username"), - password : this.build.getOption("browserstack.password") - }); - }, - setCallback : function(callback) { - this.callback = callback; - }, - setServer : function(server) { - this.server = server; - }, - terminateOldWorkers : function() { - // kill existing workers - var self = this; - this.client.getWorkers(function(error, workers) { - workers.forEach(function(worker) { - self.client.terminateWorker(worker.id, function() { - self.build.printTemp("Terminated worker: " + worker.id); - }); - }); - }); - }, - listBrowsers : function(callback) { - var self = this; - if (this.validbrowsers !== null) { - callback(this.validbrowsers); - return this; - } - this.client.getBrowsers(function(error, browsers) { - if (error) { - throw error; - } - self.validbrowsers = browsers; - callback(browsers); - }); - return this; - }, - addBrowser : function(config) { - var browser = new Browser(this.build, config); - browser.setBrowserStackClient(this.client); - this.browsers[browser.name] = browser; - return browser; - }, - getBrowser : function(name) { - return this.browsers[name]; - }, - start : function() { - var self = this, list = cArray().getNewObject(Object.keys(this.browsers)); - list.threadEach(function(next, name) { - var browser = this.getBrowser(name); - browser.setCallback(next); - browser.start(); - }, function() { - this.server.stop(); - // output results && kill all the running workers before stopping - self.build.printLine(); - list.threadEach(function(next, name) { - var browser = this.getBrowser(name); - browser.process(); - browser.stopWorker(next); - }, function() { - self.callback(); - }, this); - }, this); - } -}); - -var Server = Classify.create({ - __static_ : { - contentType : { - js : "text/javascript", - json : "text/javascript", - css : "text/css", - html : "text/html" - } - }, - init : function(build) { - this.build = build; - this.server = null; - this.tunnel = null; - }, - setList : function(list) { - this.list = list; - }, - start : function(callback) { - if (this.server) { - callback(); - return this; - } - var self = this; - this.server = http.createServer(function(request, response) { - var uri = url.parse(request.url).pathname, filename = path.join(self.build.dir.base, uri); - self.build.printTemp(filename); - fs.exists(filename, function(exists) { - if (!exists) { - response.writeHead(404, { - "Content-Type" : "text/plain" - }); - response.write("404 Not Found\n"); - response.end(); - return; - } - - if (fs.statSync(filename).isDirectory()) { - filename = filename.replace(/\/$/, "") + "/index.html"; - } - - fs.readFile(filename, "binary", function(err, file) { - if (err) { - response.writeHead(500, { - "Content-Type" : "text/plain" - }); - response.write(err + "\n"); - response.end(); - return; - } - - response.writeHead(200, { - "Content-Type" : self.constructor.contentType[filename.split(".").pop()] || "text/html" - }); - response.write(file, "binary"); - response.end(); - }); - }); - }).listen(parseInt(this.build.getOption("browserstack.port") || 80, 10), function() { - var host = self.build.getOption("browserstack.ip") || "127.0.0.1"; - var port = parseInt(self.build.getOption("browserstack.port") || 80, 10); - self.build.printLine("Unit test server running at => http://" + host + ":" + port); - - if (self.build.getOption("browserstack.tunnel") === true || self.build.getOption("browserstack.tunnel") === "true") { - self.tunnel = childProcess.spawn("ssh", [ "-R", port + ":localhost:" + port, host, "-N" ], { - env : process.env - }); - self.tunnel.stderr.setEncoding("utf8"); - self.tunnel.stderr.on("data", function(stderr) { - self.build.printLine(stderr); - }); - setTimeout(callback, 1000); - } else { - self.build.printLine("Possibly create a reverse tunnel with: \"ssh -f -R " + port + ":localhost:" + port + " " + host + " -N\""); - setTimeout(callback, 1); - } - }); - - io.listen(this.server, { - log : false, - transports : [ "websocket", "flashsocket", "htmlfile", "jsonp-polling" ], - "flash policy port" : parseInt(this.build.getOption("browserstack.port") || 80, 10) - }).sockets.on("connection", function(socket) { - socket.on("browserConnect", function(data) { - self.list.getBrowser(data.browser).setSocket(socket); - }); - }); - - return this; - }, - stop : function() { - if (this.server) { - this.server.close(); - } - if (this.tunnel) { - this.tunnel.kill(); - } - return this; - } -}); - -module.exports = function(build, callback) { - build.printHeader(build.color("Running unit tests on BrowserStack.com...", "bold")); - - var server = new Server(build); - server.start(function() { - var list = new BrowserList(build); - // kill existing workers - list.terminateOldWorkers(); - list.setCallback(callback); - list.setServer(server); - server.setList(list); - list.listBrowsers(function(browsers) { - (build.getOption("browserstack.browsers") || []).forEach(function(browser) { - list.addBrowser(browser); - }); - list.start(); - }); - }); -}; diff --git a/build/module/clean.js b/build/module/clean.js deleted file mode 100755 index 620f075..0000000 --- a/build/module/clean.js +++ /dev/null @@ -1,25 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Cleaning up the distribution directory...", "bold")); - try { - // delete contents of directory - fs.readdirSync(build.dir.dist).forEach(function(file) { - fs.unlinkSync(build.dir.dist + "/" + file); - }); - } catch (e) { - return callback({ - error : e - }); - } - try { - // create the dist dir for next iteration - fs.mkdir(build.dir.dist); - } catch (e) { - return callback({ - error : e - }); - } - callback(); -}; diff --git a/build/module/concat.js b/build/module/concat.js deleted file mode 100755 index f578d01..0000000 --- a/build/module/concat.js +++ /dev/null @@ -1,23 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Building the source file from parts...", "bold")); - try { - build.getSource(function(src) { - build.getCopyright(function(copyright) { - // remove all jscoverage comments - src = src.replace(/^\/\/#JSCOVERAGE_(?:END)?IF.*[\n\r]+/mg, ""); - fs.writeFile(build.dir.dist + "/" + build.name + ".js", copyright + "\n" + src, "utf8", function(error) { - return callback({ - error : error - }); - }); - }); - }); - } catch (e) { - return callback({ - error : e - }); - } -}; diff --git a/build/module/coverage.js b/build/module/coverage.js deleted file mode 100755 index c1eb8dd..0000000 --- a/build/module/coverage.js +++ /dev/null @@ -1,371 +0,0 @@ -// include the fs mmodule -var fs = require("fs"), -// execute system commands -childProcess = require("child_process"); -// classify library -var Classify = require("../vendor/classify/classify.min.js"); -// require the special array library -require("../vendor/classify/classify-array.min.js")(Classify); -var cArray = Classify("/Array"); - -var CodeCoverage = Classify.create({ - __static_ : { - instrument : function(build, callback) { - var error = []; - fs.readdir(build.dir.src, function(e, files) { - if (e) { - return; - } - var filter = []; - files.forEach(function(v) { - if (build.src.indexOf(v) === -1) { - filter.push(v); - } - }); - var params = []; - filter.forEach(function(v) { - params.push("--no-instrument=" + v); - }); - params.push("src"); - params.push("coverage"); - - // delete contents of directory - try { - fs.readdirSync(build.dir.coverage).forEach(function(file) { - fs.unlinkSync(build.dir.coverage + "/" + file); - }); - fs.unlinkSync(build.dir.coverage); - } catch (e) { - } - - var child = childProcess.spawn("jscoverage", params, { - env : process.env - }); - child.stderr.setEncoding("utf8"); - child.stderr.on("data", function(stderr) { - error.push(stderr.toString()); - }); - child.on("exit", function(code) { - if (code === 127) { - return callback(null); - } - if (code !== 0) { - return callback(false, error); - } - // delete files that were not instrumented - fs.readdir(build.dir.coverage, function(e, files) { - if (e) { - return; - } - files.forEach(function(v) { - if (build.src.indexOf(v) === -1) { - fs.unlinkSync(build.dir.coverage + "/" + v); - } - }); - }); - return callback(true); - }); - }); - } - }, - init : function(build) { - this.build = build; - this.runtime = 0; - this.failed = 0; - this.passed = 0; - this.total = 0; - this.files = 0; - this.executed = 0; - this.statements = 0; - this.coverage = {}; - this.missedLines = []; - }, - setCallback : function(callback) { - this.callback = callback; - return this; - }, - onComplete : function() { - this.build.printLine(); - this.callback(); - }, - start : function() { - this.build.printLine("Running in " + this.build.color(this.name, "bold") + " environment..."); - }, - logEvent : function(type, data) { - switch (type) { - case "assertionDone": - break; - case "testStart": - this.build.printTemp("Running: " + this.build.color(data.module, "bold") + " " + data.name); - break; - case "testDone": - break; - case "moduleStart": - break; - case "moduleDone": - break; - case "done": - this.build.printTemp("Unit tests done."); - this.failed = data.failed; - this.passed = data.passed; - this.total = data.total; - this.runtime = data.runtime; - this.coverage = data.coverage; - this.process(); - break; - } - }, - process : function() { - var self = this; - this.processCoverageData(function(summary) { - self.outputSummaryTable(summary); - self.generateReport(summary); - self.onComplete(); - }); - }, - processCoverageData : function(callback) { - var self = this, files = [], summary = []; - this.build.src.forEach(function(v) { - if (self.coverage.hasOwnProperty(v)) { - files.push(v); - } - }); - // generage the coverage data - files.forEach(function(filename) { - var executed = 0, statements = 0, missing = [], coverage = {}, conditionals = self.coverage[filename].conditionals, currentConditionalEnd = 0; - self.coverage[filename].lines.forEach(function(n, ln) { - // skip conditional lines that were not executed - if (ln === currentConditionalEnd) { - currentConditionalEnd = 0; - } else if (currentConditionalEnd === 0 && conditionals[ln]) { - currentConditionalEnd = conditionals[ln]; - } - if (currentConditionalEnd !== 0 || n === undefined || n === null) { - return; - } - if (n === 0) { - missing.push(ln); - } else { - executed++; - } - statements++; - }); - coverage.executed = executed; - coverage.statements = statements; - coverage.missing = missing; - coverage.name = filename; - - self.files++; - self.executed += executed; - self.statements += statements; - - var source = fs.readFileSync(self.build.dir.src + "/" + filename, "utf8").replace(/\r/g, "").replace(/\t/g, " ").split("\n"); - source.unshift(null); - coverage.source = source; - summary.push(coverage); - }); - callback(summary); - }, - outputSummaryTable : function(summary) { - var self = this, longestName = 0; - this.build.src.forEach(function(filename) { - if (self.coverage.hasOwnProperty(filename) && longestName < filename.length) { - longestName = filename.length; - } - }); - - // print header - var rowHeader = []; - rowHeader.push(this.build.rpad("File", longestName + 4)); - rowHeader.push(this.build.lpad("CLOC", 6)); - rowHeader.push(this.build.lpad("LOC", 6)); - rowHeader.push(this.build.lpad("%", 5)); - rowHeader.push("Missing"); - this.build.printLine(rowHeader.join(" | ")); - - // print divider - this.build.printLine(this.build.rpad("", 50, "-")); - - // print summary - var total_percentage = (this.statements === 0 ? 0 : parseInt(100 * this.executed / this.statements, 10)); - var rowSummary = []; - rowSummary.push(this.build.lpad(this.files, longestName + 4)); - rowSummary.push(this.build.lpad(this.executed, 6)); - rowSummary.push(this.build.lpad(this.statements, 6)); - rowSummary.push(this.build.lpad(total_percentage + " %", 5)); - rowSummary.push(""); - this.build.printLine(rowSummary.join(" | ")); - - // print divider - this.build.printLine(this.build.rpad("", 50, "-")); - - summary.forEach(function(report) { - var percentage = (report.statements === 0 ? 0 : parseInt(100 * report.executed / report.statements, 10)); - var row = [], missing = [], missingLnStart = -1; - row.push(self.build.rpad(report.name, longestName + 4)); - row.push(self.build.lpad(report.executed, 6)); - row.push(self.build.lpad(report.statements, 6)); - row.push(self.build.lpad(percentage + " %", 5)); - - // group up non covered lines to 1,2,3,5,7,8,9 => 1-3,5,7-9 - report.missing.forEach(function(ln, idx) { - if (missingLnStart === -1 && ln + 1 === report.missing[idx + 1]) { - missingLnStart = ln; - return; - } - if (ln + 1 === report.missing[idx + 1]) { - return; - } - if (missingLnStart !== -1) { - missing.push(missingLnStart + "-" + ln); - missingLnStart = -1; - return; - } - missingLnStart = -1; - missing.push(ln); - }); - row.push(missing.join(",")); - - self.build.printLine(row.join(" | ")); - }); - }, - generateReport : function(summary) { - var self = this; - summary.forEach(function(report) { - var is_continue = false; - - self.missedLines.push(""); - self.missedLines.push(self.build.color(self.build.rpad(report.name + " ", 80, "="), "bold")); - - report.missing.forEach(function(line, i) { - if (line > 1 && !is_continue) { - // context line - self.missedLines.push(self.build.lpad(line - 1, 5) + " | " + report.source[line - 1]); - } - // the current line - self.missedLines.push(self.build.lpad(line, 5) + " | " + self.build.color(report.source[line], 160)); - - // if the next line is also missing then just continue - if (report.missing[i + 1] === line + 1) { - is_continue = true; - } else { - // otherwise output another context line - is_continue = false; - if (report.source[line + 1]) { - // context line - self.missedLines.push(self.build.lpad(line + 1, 5) + " | " + report.source[line + 1]); - self.missedLines.push(""); - } - } - }); - }); - } -}); - -var CodeCoverageNodeJs = Classify.create(CodeCoverage, { - name : "NodeJs", - start : function() { - this.parent(); - var self = this, child; - - child = childProcess.fork(this.build.dir.build + "/bridge/coverage-node-bridge.js", [ JSON.stringify({ - source : { - src : this.build.src, - tests : this.build.unit, - external : this.build.external - }, - dir : this.build.dir - }) ], { - env : process.env - }); - child.on("message", function(message) { - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - } -}); - -var CodeCoveragePhantomJs = Classify.create(CodeCoverage, { - name : "PhantomJs", - start : function() { - var self = this, child; - this.parent(); - - child = childProcess.spawn("phantomjs", [ this.build.dir.build + "/bridge/phantom-bridge.js", this.build.dir.build + "/bridge/coverage-phantom-bridge.html" ], { - env : process.env - }); - - child.stdout.setEncoding("utf8"); - child.stdout.on("data", function(stdout) { - stdout.toString().split("{\"event\"").forEach(function(data) { - if (!data) { - return; - } - var message = {}; - try { - message = JSON.parse("{\"event\"" + data); - } catch (e) { - throw e; - } - - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - }); - child.on("exit", function(code) { - // phantomjs doesn't exist - if (code === 127) { - self.build.printLine(self.build.color("\u2716 ", 160) + "Environment " + self.name + " not found!"); - self.onComplete(); - } - }); - } -}); - -module.exports = function(build, callback) { - build.printHeader(build.color("Generating Code Coverage Report with JsCoverage...", "bold")); - CodeCoverage.instrument(build, function(result, data) { - if (result === null) { - build.printLine(build.color("\u2716 ", 160) + "JsCoverage not found!"); - build.printLine(); - return callback(); - } - if (result === false) { - if (data) { - data.forEach(function(msg) { - msg = msg.replace(/^\s*jscoverage:\s*/, ""); - if (msg) { - build.printLine(msg); - } - }); - } - build.printLine(); - return callback({ - error : new Error("Parsing javascript files failed.") - }); - } - - var tests = cArray(); - if (build.env.node === true) { - tests.push(new CodeCoverageNodeJs(build)); - } - if (build.env.web === true) { - tests.push(new CodeCoveragePhantomJs(build)); - } - tests.serialEach(function(next, test) { - test.setCallback(next).start(); - }, function() { - var logs = []; - tests.forEach(function(test) { - logs.push.apply(logs, test.missedLines); - }); - build.writeCacheFile("coverage", logs, function() { - callback(); - }); - }); - }); -}; diff --git a/build/module/creport.js b/build/module/creport.js deleted file mode 100755 index 3ce3814..0000000 --- a/build/module/creport.js +++ /dev/null @@ -1,19 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Generating Code Coverage Report...", "bold")); - - build.readCacheFile("coverage", function(data) { - data = data || []; - if (data.length === 0) { - return callback({ - error : new Error("Code Coverage reports not yet generated!") - }); - } - data.forEach(function(msg) { - build.printLine(msg); - }); - callback(); - }); -}; diff --git a/build/module/doc.js b/build/module/doc.js deleted file mode 100755 index 2419857..0000000 --- a/build/module/doc.js +++ /dev/null @@ -1,569 +0,0 @@ -// include the fs mmodule -var fs = require("fs"), -// include the path module -path = require("path"), -// execute system commands -exec = require("child_process"), -// syntax highlighter -hljs = require('../vendor/highlight/highlight.js').hljs; -hljs.LANGUAGES.javascript = require('../vendor/highlight/highlight.javascript.js')(hljs); - -function highlight(string) { - var code = hljs.highlight("javascript", string); - return (code && code.value) || string; -} - -function roundFileSize(b, d) { - var i = 0; - while ((b / 1000) > 1) { - b /= 1000; - i++; - } - return b.toFixed(d === 0 || d ? d : 2) + " " + [ "b", "kb", "Mb", "Gb", "Tb" ][i]; -} - -function parseDocs(source) { - var docRegexp = /\s*\/\*\*(?:[\S\s]+?)\*\//mg; - var fnRegexp = /\bfunction(\s*|[^\(]+)?\(/; - var commentRegexp = /^\/\*\*[\S\s]+?\s*(\*\s+@|\*\/$)/; - var returnsRegexp = /@returns\s+([\S\s]+?)\s*(\*\s+@|\*\/$)/; - var paramsRegexp = /@param\s+([\S\s]+?)\s*(?:\*\s*@|\*\/$)/; - var exampleRegexp = /@example\s+([\S\s]+?)<\/code>/g; - var referenceExampleRegexp = /@refexample\s+([\S\s]+?)$/m; - var staticRegexp = /@static\b/; - var privateRegexp = /@private\b/; - var constructorRegexp = /@constructor\b/; - var memberOfRegexp = /@memberOf\s+.+$/m; - var nameRegexp = /@name\s+.+$/m; - var superRegexp = /@super\s+.+$/m; - var augmentsRegexp = /@augments\s+.+$/m; - var typeRegexp = /@type\s+.+$/m; - var docs = []; - // get all docblocks and the line right after it - source.replace(docRegexp, function(match, index) { - var docblock = match.trim(); - var definition = source.substr(match.length + index).split(/\n/g)[1]; - docs.push({ - doc : docblock, - def : definition - }); - }); - var docblocks = []; - docs.forEach(function(block) { - var doc = {}; - // pull out the docblock comment - var commentMatch = commentRegexp.exec(block.doc); - if (commentMatch && commentMatch[0]) { - doc.comment = commentMatch[0].replace(/^\/\*\*/, "").replace(/^\s*\*\s*/gm, "").replace(/^\s*\*\s*@\s*$/gm, "").split(/\n/g).join(" ").replace(/\s+/g, " ").trim(); - } - // parse example if any - var exampleMatch = exampleRegexp.exec(block.doc); - if (exampleMatch && exampleMatch[1]) { - doc.example = exampleMatch[1].trim().replace(/^\s*\* ?/gm, "").replace(/\t/g, " ").trim(); - } - // parse reference example if any - var refExampleMatch = referenceExampleRegexp.exec(block.doc); - if (refExampleMatch && refExampleMatch[1]) { - doc.refexample = refExampleMatch[1].trim(); - } - - var memberOfMatch = memberOfRegexp.exec(block.doc); - if (memberOfMatch && memberOfMatch[0]) { - doc.memberOf = memberOfMatch[0].replace(/@memberOf\s+/, "").trim().replace(/^\{|\}$/g, ""); - } - var typeMatch = typeRegexp.exec(block.doc); - if (typeMatch && typeMatch[0]) { - doc.type = typeMatch[0].replace(/@type\s+/, "").trim().replace(/^\{|\}$/g, ""); - } - - doc.isStatic = staticRegexp.test(block.doc); - doc.isPrivate = privateRegexp.test(block.doc); - - // check if it is a function or not - if (fnRegexp.test(block.def)) { - doc.varType = "function"; - doc.isConstructor = constructorRegexp.test(block.doc); - var returnsMatch = returnsRegexp.exec(block.doc); - if (returnsMatch && returnsMatch[0]) { - var returnsMatchParts = {}; - var returnsMatchClean = returnsMatch[1].replace(/^\s*\*\s*/gm, "").split(/\n/g).join(" ").replace(/\s+/g, " ").trim(); - returnsMatchParts.type = (/^\{?([^\s]+)\}/.exec(returnsMatchClean) || [])[1] || null; - returnsMatchParts.comment = (/^\{?[^\s]+\}(.+)$/.exec(returnsMatchClean) || [])[1] || null; - doc.returns = returnsMatchParts; - } - var params = [], paramMatcher, paramBlock = block.doc, matchCleaner = function(match, part) { - return match.substr(-1); - }; - // strip out all the params from block - while ((paramMatcher = paramsRegexp.exec(paramBlock)) !== null) { - var paramsMatchParts = {}; - var paramsMatchClean = paramMatcher[1].replace(/^\s*\*\s*/gm, "").split(/\n/g).join(" ").replace(/\s+/g, " ").trim(); - paramsMatchParts.type = (/^\{?([^\s]+)\}/.exec(paramsMatchClean) || [])[1] || null; - paramsMatchParts.name = (/^\{?[^\s]+\}\s+([^\s]+)\s+.+$/.exec(paramsMatchClean) || [])[1] || null; - paramsMatchParts.isOptional = false; - if (/^\[.+\]$/.test(paramsMatchParts.name)) { - var nameParts = paramsMatchParts.name.replace(/^\[|\]$/g, "").split("="); - paramsMatchParts.isOptional = true; - paramsMatchParts.name = nameParts.shift(); - paramsMatchParts.value = nameParts.join("="); - } - paramsMatchParts.comment = (/^\{?[^\s]+\}\s+([^\s]+)\s+(.+)$/.exec(paramsMatchClean) || [])[2] || null; - params.push(paramsMatchParts); - paramBlock = paramBlock.replace(paramsRegexp, matchCleaner); - } - doc.params = params; - - var superMatch = superRegexp.exec(block.doc); - if (superMatch && superMatch[0]) { - doc.superClass = superMatch[0].replace(/@super\s+/, "").trim().replace(/^\{|\}$/g, ""); - } - var augmentsMatch = augmentsRegexp.exec(block.doc); - if (augmentsMatch && augmentsMatch[0]) { - doc.augments = augmentsMatch[0].replace(/@augments\s+/, "").trim().replace(/^\{|\}$/g, ""); - } - if (block.def.indexOf("=") > -1) { - doc.name = (block.def.split("=")[0] || "").replace(/^\s*var\s+/, "").trim(); - } else { - doc.name = block.def.replace(/^\s*function\s+/, "").replace(/([^\(]+).+$/, "$1").trim(); - } - } else { - doc.varType = "var"; - doc.name = (block.def.split("=")[0] || "").replace(/^\s*var\s+/, "").trim(); - } - - // override the name property if defined - var nameMatch = nameRegexp.exec(block.doc); - if (nameMatch && nameMatch[0]) { - doc.name = nameMatch[0].replace(/@name\s+/, "").trim().replace(/^\{|\}$/g, ""); - } - - docblocks.push(doc); - }); - return docblocks; -} - -function groupByMembers(docblocks) { - var groups = {}, sortedGroups = {}, validGroups = {}; - docblocks.forEach(function(doc) { - var memberOf; - if (doc.memberOf) { - memberOf = doc.memberOf; - } else { - var name = doc.name.split("."); - name.pop(); - memberOf = name.length === 0 ? doc : name.join("."); - } - validGroups[memberOf] = true; - if (!groups[memberOf]) { - groups[memberOf] = { - statics : [], - prototypes : [] - }; - } - }); - docblocks.forEach(function(doc) { - var memberOf; - if (doc.memberOf) { - memberOf = doc.memberOf; - } else { - var name = doc.name.split("."); - name.pop(); - memberOf = name.length === 0 ? doc : name.join("."); - } - if (doc.name === memberOf || validGroups[doc.name]) { - groups[doc.name].base = doc; - } else { - groups[memberOf][/\.prototype\b/.test(doc.name) ? "prototypes" : "statics"].push(doc); - } - }); - Object.keys(groups).sort().forEach(function(key) { - sortedGroups[key] = groups[key]; - }); - return sortedGroups; -} - -function getExamples(build) { - var examples = {}; - - (build.getOption("doc.examples") || []).forEach(function(file) { - var block = require(build.dir.doc + "/" + file); - Object.keys(block).forEach(function(key) { - examples[key] = block[key]; - }); - }); - - return examples; -} - -function createMarkdown(build, docGroups, callback) { - var markdown = []; - var examples = getExamples(build); - markdown.push("# " + build.name + " `v" + build.version + "`"); - markdown.push("=================================================="); - markdown.push(""); - Object.keys(docGroups).forEach(function(key) { - var group = docGroups[key]; - // section header - markdown.push("## `" + key + "`"); - if (group.base) { - markdown.push(" * [`" + key + "`](#" + key + ")"); - } - if (group.statics.length > 0) { - group.statics.forEach(function(doc) { - markdown.push(" * [`" + doc.name + "`](#" + doc.name + ")"); - }); - } - if (group.prototypes.length > 0) { - markdown.push(""); - markdown.push(""); - markdown.push("## `" + key + ".prototype`"); - group.prototypes.forEach(function(doc) { - markdown.push(" * [`" + doc.name.replace(/\.prototype\./, "#") + "`](#" + doc.name + ")"); - }); - } - markdown.push(""); - markdown.push(""); - }); - - Object.keys(docGroups).forEach(function(key) { - var group = docGroups[key]; - // section header - markdown.push("## `" + key + "`"); - if (group.base) { - markdown.push(""); - outputMarkdownBlock(group.base, markdown, examples); - } - if (group.statics.length > 0) { - group.statics.forEach(function(doc) { - outputMarkdownBlock(doc, markdown, examples); - }); - } - if (group.prototypes.length > 0) { - markdown.push(""); - markdown.push(""); - markdown.push("## `" + key + ".prototype`"); - group.prototypes.forEach(function(doc) { - outputMarkdownBlock(doc, markdown, examples); - }); - } - markdown.push(""); - markdown.push(""); - }); - callback(markdown.join("\n").trim()); -} - -function outputMarkdownBlock(block, messages, examples) { - var name = block.name; - if (block.varType === "function") { - name += "("; - if (block.params && block.params.length > 0) { - block.params.forEach(function(param, i) { - var param_str = ""; - if (i > 0) { - param_str += ", "; - } - param_str += param.name; - if (param.isOptional) { - if (param.value) { - param_str += "=" + param.value; - } - param_str = "[" + param_str + "]"; - } - name += param_str; - }); - } - name += ")"; - } - messages.push('### `' + name + "`"); - messages.push(block.comment.replace(/\.$/, "") + "."); - messages.push("[▲](#)"); - messages.push(""); - if (block.varType === "function") { - if (block.isConstructor) { - messages.push(""); - messages.push("##### Constructor method"); - } - if (block.superClass || block.augments) { - messages.push(""); - messages.push("##### Extends `" + (block.superClass || block.augments) + "`"); - } - if (block.params && block.params.length > 0) { - messages.push(""); - messages.push("##### Arguments"); - block.params.forEach(function(param, i) { - var param_str = ""; - param_str += param.name; - if (param.isOptional) { - if (param.value) { - param_str += "=" + param.value; - } - param_str = "[" + param_str + "]"; - } - name += param_str; - var param_line = (i + 1) + ". `" + param_str + "` `{" + param.type + "}`"; - if (param.comment) { - param_line += ": " + param.comment; - } - messages.push(param_line); - }); - } - - if (block.returns) { - messages.push(""); - messages.push("##### Returns"); - if (block.returns.comment) { - messages.push("`" + block.returns.type + "`: " + block.returns.comment); - } else { - messages.push("`" + block.returns.type + "`"); - } - } - } else { - if (block.comment) { - messages.push("`" + block.type + "`: " + block.comment); - } else { - messages.push("`" + block.type + "`"); - } - } - if (block.example) { - messages.push(""); - messages.push("##### Example"); - messages.push("```javascript"); - messages.push(block.example); - messages.push("```"); - } else if (block.refexample && examples[block.refexample]) { - messages.push(""); - messages.push("##### Example"); - messages.push("```javascript"); - messages.push(highlight(examples[block.refexample].toString().replace(/^\t/gm, "").replace(/\t/g, " ").replace(/^\s*func.+[\n\r]+/, "").replace(/[\n\r]+\s*\}\s*$/, ""))); - messages.push("```"); - } - messages.push(""); -} - -function parseChangelog(build) { - var changelog_doc = fs.readFileSync(build.dir.doc + "/CHANGELOG.md", "utf8"); - changelog_doc = changelog_doc.replace(/\r/g, ""); - var changegroups = changelog_doc.split("####"); - var changelog = {}; - changegroups.forEach(function(group) { - group = group.trim(); - if (!group) { - return; - } - var changes = group.split("\n"); - var version = changes.shift(); - var changedata = []; - changes.forEach(function(change) { - var c = change.trim(); - if (c) { - changedata.push(c); - } - }); - if (changedata.length > 0) { - changelog[version] = changedata; - } - }); - return changelog; -} - -function outputHtmlChangelogBlock(build, changelog) { - var changetemplate = []; - Object.keys(changelog).forEach(function(version) { - changetemplate.push("
          "); - changetemplate.push("" + version + ""); - changetemplate.push("
            "); - changelog[version].forEach(function(change) { - changetemplate.push("
          • " + change + "
          • "); - }); - changetemplate.push("
          "); - changetemplate.push("
          "); - }); - return changetemplate.join("\n"); -} - -function createHtmlDoc(build, docGroups) { - var markdown = []; - var examples = getExamples(build); - - Object.keys(docGroups).forEach(function(key) { - var group = docGroups[key]; - // section header - markdown.push("

          " + key + "

          "); - if (group.base) { - outputHtmlDocBlock(group.base, markdown, examples); - } - if (group.statics.length > 0) { - group.statics.forEach(function(doc) { - outputHtmlDocBlock(doc, markdown, examples); - }); - } - if (group.prototypes.length > 0) { - group.prototypes.forEach(function(doc) { - outputHtmlDocBlock(doc, markdown, examples); - }); - } - }); - return markdown.join("\n").trim(); -} - -function outputHtmlDocBlock(block, messages, examples) { - var name = block.name; - if (block.varType === "function") { - name += "("; - if (block.params && block.params.length > 0) { - block.params.forEach(function(param, i) { - var param_str = ""; - if (i > 0) { - param_str += ", "; - } - param_str += param.name; - if (param.isOptional) { - if (param.value) { - param_str += "=" + param.value; - } - param_str = "[" + param_str + "]"; - } - name += param_str; - }); - } - name += ")"; - } - messages.push("
          "); - - messages.push("

          " + block.name + "

          "); - messages.push("" + name + ""); - - messages.push("
          "); - messages.push(block.comment.replace(/\.$/, "").replace(/\n/g, "
          \n") + "."); - messages.push("
          "); - - if (block.varType === "function") { - if (block.isConstructor) { - messages.push("
          Constructor method
          "); - } - if (block.superClass || block.augments) { - messages.push("
          Extends " + (block.superClass || block.augments) + "
          "); - } - if (block.params && block.params.length > 0) { - messages.push("
          "); - messages.push("Arguments"); - messages.push("
            "); - block.params.forEach(function(param, i) { - var param_str = ""; - param_str += param.name; - if (param.isOptional) { - if (param.value) { - param_str += "=" + param.value; - } - param_str = "[" + param_str + "]"; - } - name += param_str; - var param_line = "" + param_str + " {" + param.type + "}"; - if (param.comment) { - param_line += " " + param.comment; - } - messages.push("
          1. "); - messages.push("" + (i + 1) + "."); - messages.push(param_line); - messages.push("
          2. "); - }); - messages.push("
          "); - messages.push("
          "); - } - - if (block.returns) { - messages.push("
          "); - messages.push("Returns"); - if (block.returns.comment) { - messages.push("" + block.returns.type + " " + block.returns.comment); - } else { - messages.push("" + block.returns.type + ""); - } - messages.push("
          "); - } - } else { - if (block.comment) { - messages.push("" + block.type + " " + block.comment); - } else { - messages.push("" + block.type + ""); - } - } - - messages.push("
          "); - - if (block.example) { - messages.push("
          ");
          -		messages.push(highlight(block.example));
          -		messages.push("
          "); - } else if (block.refexample && examples[block.refexample]) { - messages.push("
          ");
          -		messages.push(highlight(examples[block.refexample].toString().trim().replace(/^\t/gm, "").replace(/\t/g, "    ").replace(/^\s*func.+[\n\r]+/, "").replace(/[\n\r]+\s*\}\s*$/, "")));
          -		messages.push("
          "); - } -} - -function createHtmlIndex(build, docGroups, callback) { - build.getMinifiedSource(function(min) { - build.getGzippedSource(function(zip) { - var examples = getExamples(build); - - var htmlInputName = typeof build.getOption("doc.html") === "string" ? build.getOption("doc.html") : build.name; - var template = fs.readFileSync(build.dir.doc + "/" + htmlInputName + ".html", "utf8"); - template = template.replace(/@VERSION\b/g, build.version); - template = template.replace(/@REPO_URI\b/g, build.repoUrl); - template = template.replace(/@FULLSIZE\b/g, roundFileSize(min.length)); - template = template.replace(/@MINSIZE\b/g, roundFileSize(zip.length)); - template = template.replace(/@CHANGELOG\b/g, outputHtmlChangelogBlock(build, parseChangelog(build))); - template = template.replace(/@DOCUMENTATION\b/g, createHtmlDoc(build, docGroups)); - template = template.replace(/@EXAMPLE\[(.+?)]/g, function(m, name) { - var block = "
          ";
          -				block += highlight(examples[name].toString().replace(/^\t/gm, "").replace(/\t/g, "    ").replace(/^\s*func.+[\n\r]+/, "").replace(/[\n\r]+\s*\}\s*$/, ""));
          -				block += "
          "; - return block; - }); - callback(template); - }); - }); -} - -module.exports = function(build, callback) { - build.printHeader(build.color("Generating documentation files...", "bold")); - - if (!build.getOption("doc.files") || build.getOption("doc.files").length === 0) { - callback(); - return; - } - - var docsfile = [], num_processed = 0; - build.getOption("doc.files").forEach(function(file) { - docsfile.push(fs.readFileSync(build.dir.doc + "/" + file, "utf8").replace(/\r/g, "")); - }); - var docblocks = parseDocs(docsfile.join("\n")); - var groups = groupByMembers(docblocks); - - if (build.getOption("doc.markdown")) { - num_processed++; - var markdownOutputName = typeof build.getOption("doc.markdown") === "string" ? build.getOption("doc.markdown") : build.name; - createMarkdown(build, groups, function(doc) { - fs.writeFileSync(build.dir.doc + "/" + markdownOutputName + ".md", doc, "utf8"); - setTimeout(function() { - if (--num_processed === 0) { - callback(); - } - }, 1); - }); - } - - if (build.getOption("doc.html")) { - num_processed++; - var htmlOutputName = typeof build.getOption("doc.html") === "string" ? build.getOption("doc.html") : build.name; - createHtmlIndex(build, groups, function(doc) { - fs.writeFileSync(build.dir.doc + "/" + htmlOutputName + ".out.html", doc, "utf8"); - setTimeout(function() { - if (--num_processed === 0) { - callback(); - } - }, 1); - }); - } -}; diff --git a/build/module/lint.js b/build/module/lint.js deleted file mode 100755 index c67797d..0000000 --- a/build/module/lint.js +++ /dev/null @@ -1,72 +0,0 @@ -var fs = require("fs"); -var jshint = require("../vendor/jshint/jshint").JSHINT; - -var lint = function(build, src) { - // run the linter - jshint(src, build.getOption("lint.options")); - return { - data : jshint.data(), - errors : jshint.errors || [] - }; -}; - -var output = function(build, data) { - if (data.errors.length > 0) { - data.errors.forEach(function(e) { - if (!e) { - return; - } - build.printLine(" Problem at line " + e.line + ":" + (e.character === true ? "EOL" : e.character) + ": " + build.color(e.reason, 160)); - build.printLine(" " + (e.evidence || "").replace(/\t/g, " ").trim()); - }); - return; - } - build.printLine(build.color("\u2714 ", 34) + "Code linting passed!"); - if (data.data.globals && data.data.globals.length > 0) { - build.printLine("Globals: \x1B[38;5;33m" + data.data.globals.join("\x1B[0m, \x1B[38;5;33m") + "\x1B[0m"); - } - if (data.data.unused) { - data.data.unused.forEach(function(e, i) { - var msg = ""; - msg += (i === 0 ? "Unused variable: " : " "); - msg += "\"" + build.color(e.name, 73) + "\" at line " + e.line + " in " + e["function"]; - build.printLine(msg); - }); - } -}; - -module.exports = function(build, callback) { - build.printHeader(build.color("Checking code quality with JsHint...", "bold")); - - // if we want to lint on a per file basis - if (build.getOption("lint.perFile") === true) { - var passed = true; - build.src.some(function(file) { - var src = fs.readFileSync(build.dir.src + "/" + file, "utf8"); - var data = lint(build, src); - build.printLine("Linting file: " + build.color(file, "bold")); - output(build, data); - if (data.errors.length > 0) { - callback({ - error : new Error(jshint.errors.length + " Linting error(s) found.") - }); - passed = false; - return false; - } - }); - if(passed) { - callback(); - } - } else { - build.getSource(function(src) { - var data = lint(build, src); - output(build, data); - if (data.errors.length > 0) { - return callback({ - error : new Error(jshint.errors.length + " Linting error(s) found.") - }); - } - callback(); - }); - } -}; diff --git a/build/module/min.js b/build/module/min.js deleted file mode 100755 index a5d6e22..0000000 --- a/build/module/min.js +++ /dev/null @@ -1,31 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Minifying source file with UglifyJs...", "bold")); - build.getSource(function(src) { - build.getMinifiedSource(function(min) { - build.getCopyright(function(copyright) { - try { - fs.writeFile(build.dir.dist + "/" + build.name + ".min.js", copyright + ";" + min + ";", "utf8", function(error) { - if (error) { - return callback({ - error : error - }); - } - - var length = src.length; - var minLength = min.length; - var savingPercentage = ((length - minLength) / length * 100).toFixed(2); - build.printLine("Saved " + (length - minLength) + " bytes (" + savingPercentage + "%)."); - return callback(); - }); - } catch (e) { - return callback({ - error : e - }); - } - }); - }); - }); -}; diff --git a/build/module/perf.js b/build/module/perf.js deleted file mode 100755 index 5bea040..0000000 --- a/build/module/perf.js +++ /dev/null @@ -1,205 +0,0 @@ -// execute system commands -var childProcess = require("child_process"); -// classify library -var Classify = require("../vendor/classify/classify.min.js"); -// require the special array library -require("../vendor/classify/classify-array.min.js")(Classify); -var cArray = Classify("/Array"); - -var Benchmark = Classify.create({ - init : function(name, build) { - this.build = build; - this.name = name; - this.failed = 0; - this.passed = 0; - this.total = 0; - this.results = []; - }, - setCallback : function(callback) { - this.callback = callback; - return this; - }, - onComplete : function() { - this.build.printLine(); - this.callback(); - }, - start : function() { - this.build.printLine("Running in " + this.build.color(this.name, "bold") + " environment..."); - }, - logEvent : function(type, data) { - var modules; - switch (type) { - case "testStart": - modules = data.name.split("."); - this.build.printTemp("Starting: " + this.build.color(modules.shift(), "bold") + " " + modules.join(".")); - break; - case "testCycle": - modules = data.name.split("."); - this.build.printTemp(this.build.color(modules.shift(), "bold") + " " + modules.join(".") + " x " + this.build.formatNumber(data.count) + " (" + data.size + " sample" + (data.size == 1 ? "" : "s") + ")"); - break; - case "testError": - break; - case "testComplete": - this[data.error ? "failed" : "passed"]++; - this.results.push(data); - break; - case "done": - this.build.printTemp("Benchmarks done."); - this.total = this.results.length; - this.process(); - break; - } - }, - process : function(prevResults) { - var self = this; - this.build.readCacheFile("perf." + this.name, function(data) { - var currentPerfStats = {}; - self.results.forEach(function(test) { - currentPerfStats[test.name] = test; - }); - self.build.writeCacheFile("perf." + self.name, currentPerfStats, function() { - self.output(data || {}); - }); - }); - }, - output : function(prevResults) { - var self = this; - this.results.forEach(function(test) { - self.outputTest(test, prevResults[test.name]); - }); - - if (this.failed > 0) { - this.build.printLine(this.build.color("\u2716 ", 160) + this.failed + " / " + this.total + " Failed"); - } else { - this.build.printLine(this.build.color("\u2714 ", 34) + "All benchmarks run successfully!"); - } - this.build.printLine(); - this.onComplete(); - }, - outputTest : function(test, prev) { - var message = [ " " ], prevCompare; - if (test.error) { - message.push(this.build.color(this.build.rpad(test.name, 35), 160)); - } else { - message.push(this.build.rpad(test.name, 35)); - } - message.push(this.build.lpad(this.build.formatNumber(test.hz.toFixed(test.hz < 100 ? 2 : 0)), 12)); - message.push(" ops/s (\u00B1" + test.stats.rme.toFixed(2) + "%)"); - message.push(" [" + this.build.formatNumber(test.count) + "x in " + test.times.cycle.toFixed(3) + "s]"); - - if (prev) { - prevCompare = test.hz - prev.hz; - message.push(" [Vs. "); - message.push(prevCompare >= 0 ? "+" : "-"); - message.push(this.build.formatNumber(Math.abs(prevCompare).toFixed(Math.abs(prevCompare) < 100 ? 2 : 0))); - message.push(" ops/s "); - message.push("("); - message.push(prevCompare >= 0 ? "+" : "-"); - message.push(Math.abs(((test.hz - prev.hz) / test.hz) * 100).toFixed(3) + "%"); - message.push(")"); - message.push("]"); - } - - this.build.printLine(message.join("")); - if (test.error) { - this.build.printLine(" " + this.build.color("\u2716 ", 160) + test.error); - } - } -}); - -var BenchmarkNodeJs = Classify.create(Benchmark, { - init : function(build) { - this.parent("NodeJs", build); - }, - start : function() { - this.parent(); - - var self = this, index = 0, child; - child = childProcess.fork(this.build.dir.build + "/bridge/benchmark-node-bridge.js", [ JSON.stringify({ - source : { - src : this.build.src, - perf : this.build.perf, - external : this.build.external - }, - dir : this.build.dir - }) ], { - env : process.env - }); - - child.on("message", function(message) { - if (message.event === "testComplete") { - message.data.index = ++index; - } - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - } -}); - -var BenchmarkPhantomJs = Classify.create(Benchmark, { - init : function(build) { - this.parent("PhantomJs", build); - }, - start : function() { - this.parent(); - var self = this, index = 0, child; - - child = childProcess.spawn("phantomjs", [ this.build.dir.build + "/bridge/phantom-bridge.js", this.build.dir.build + "/bridge/benchmark-phantom-bridge.html" ], { - env : process.env - }); - - child.stdout.setEncoding("utf8"); - child.stdout.on("data", function(stdout) { - stdout.toString().split("{\"event\"").forEach(function(data) { - if (!data) { - return; - } - var message = {}; - try { - message = JSON.parse("{\"event\"" + data); - } catch (e) { - throw e; - } - - if (message.event === "testComplete") { - message.data.index = ++index; - } - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - }); - child.on("exit", function(code) { - // phantomjs doesn't exist - if (code === 127) { - self.build.printLine(self.build.color("\u2716 ", 160) + "Environment " + self.name + " not found!"); - self.onComplete(); - } - }); - } -}); - -module.exports = function(build, callback) { - build.printHeader(build.color("Running benchmarks with Benchmark.js...", "bold")); - var tests = cArray(); - if (build.env.node === true) { - tests.push(new BenchmarkNodeJs(build)); - } - if (build.env.web === true) { - tests.push(new BenchmarkPhantomJs(build)); - } - tests.serialEach(function(next, test) { - test.setCallback(next).start(); - }, function() { - var failed = 0; - tests.forEach(function(test) { - failed += test.failed; - }); - callback({ - error : failed > 0 ? new Error(failed + " Benchmarks(s) failed.") : null - }); - }); -}; diff --git a/build/module/pkg.js b/build/module/pkg.js deleted file mode 100755 index da77dbb..0000000 --- a/build/module/pkg.js +++ /dev/null @@ -1,22 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Generation package.json file...", "bold")); - - if (!build.getOption("pkg")) { - callback(); - return; - } - - var pkgStr = JSON.stringify(build.getOption("pkg.desc"), true, 4); - pkgStr = pkgStr.replace(/@VERSION\b/g, build.version); - pkgStr = pkgStr.replace(/@DATE\b/g, (new Date()).toUTCString()); - build.replaceTokens.forEach(function(token) { - pkgStr = pkgStr.replace(new RegExp("@" + token.name + "\\b", "g"), token.value); - }); - - fs.writeFile(build.dir.base + "/" + build.getOption("pkg.file"), pkgStr, "utf8", function() { - callback(); - }); -}; diff --git a/build/module/size.js b/build/module/size.js deleted file mode 100755 index 78d19a1..0000000 --- a/build/module/size.js +++ /dev/null @@ -1,30 +0,0 @@ -// include the fs mmodule -var fs = require("fs"); - -module.exports = function(build, callback) { - build.printHeader(build.color("Checking sizes against previous build...", "bold")); - - build.getSource(function(src) { - build.getMinifiedSource(function(min) { - build.getGzippedSource(function(zip) { - build.readCacheFile("size", function(data) { - data = data || {}; - var sizes = {}; - sizes[build.name + ".js"] = src.length; - sizes[build.name + ".min.js"] = min.length; - sizes[build.name + ".min.js.gz"] = zip.length; - - Object.keys(sizes).forEach(function(key) { - var diff = data[key] && (sizes[key] - data[key]); - if (diff > 0) { - diff = "+" + diff; - } - build.printLine(build.lpad(sizes[key], 8) + " " + build.lpad(diff ? "(" + diff + ")" : "(-)", 8) + " " + key); - }); - - build.writeCacheFile("size", sizes, callback); - }); - }); - }); - }); -}; \ No newline at end of file diff --git a/build/module/unit.js b/build/module/unit.js deleted file mode 100755 index 676a372..0000000 --- a/build/module/unit.js +++ /dev/null @@ -1,182 +0,0 @@ -// execute system commands -var childProcess = require("child_process"); -// classify library -var Classify = require("../vendor/classify/classify.min.js"); -// require the special array library -require("../vendor/classify/classify-array.min.js")(Classify); -var cArray = Classify("/Array"); - -var UnitTest = Classify.create({ - init : function(name, build) { - this.build = build; - this.name = name; - this.runtime = 0; - this.failed = 0; - this.passed = 0; - this.total = 0; - this.results = {}; - }, - setCallback : function(callback) { - this.callback = callback; - return this; - }, - onComplete : function() { - this.build.printLine(); - this.callback(); - }, - start : function() { - this.build.printLine("Running in " + this.build.color(this.name, "bold") + " environment..."); - }, - logEvent : function(type, data) { - switch (type) { - case "assertionDone": - if (data.result === false) { - if (!this.results[data.module]) { - this.results[data.module] = []; - } - this.results[data.module].push(data); - } - break; - case "testStart": - this.build.printTemp("Running: " + this.build.color(data.module, "bold") + " " + data.name); - break; - case "testDone": - break; - case "moduleStart": - break; - case "moduleDone": - break; - case "done": - this.build.printTemp("Unit tests done."); - this.failed = data.failed; - this.passed = data.passed; - this.total = data.total; - this.runtime = data.runtime; - this.process(); - break; - } - }, - process : function() { - var self = this, build = this.build; - Object.keys(this.results).forEach(function(test) { - build.printLine(build.color("Module: ", "bold") + test); - self.results[test].forEach(function(assertion) { - build.printLine(" " + (assertion.result ? build.color("\u2714 ", 34) : build.color("\u2716 ", 160)) + build.color("Test # ", "bold") + assertion.index + "/" + self.total); - build.printLine(" " + assertion.message + " [" + build.color(assertion.test, 248) + "]"); - if (typeof assertion.expected !== "undefined") { - build.printLine(" -> " + build.color("Expected: " + assertion.expected, 34)); - // if test failed, then we need to output the result - if (!assertion.result) { - build.printLine(" -> " + build.color("Result: " + assertion.actual, 160)); - } - } - }); - }); - - if (this.failed > 0) { - build.printLine(build.color("\u2716 ", 160) + this.failed + " / " + this.total + " Failed"); - } else { - build.printLine(build.color("\u2714 ", 34) + "All tests [" + this.passed + " / " + this.total + "] passed!"); - } - this.onComplete(); - } -}); - -var UnitTestNodeJs = Classify.create(UnitTest, { - init : function(build) { - this.parent("NodeJs", build); - }, - start : function() { - this.parent(); - var self = this, index = 0, child; - - child = childProcess.fork(this.build.dir.build + "/bridge/qunit-node-bridge.js", [ JSON.stringify({ - source : { - src : this.build.src, - tests : this.build.unit, - external : this.build.external - }, - dir : this.build.dir - }) ], { - env : process.env - }); - - child.on("message", function(message) { - if (message.event === "assertionDone") { - message.data.index = ++index; - } - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - } -}); - -var UnitTestPhantomJs = Classify.create(UnitTest, { - init : function(build) { - this.parent("PhantomJs", build); - }, - start : function() { - this.parent(); - var self = this, index = 0, child; - - child = childProcess.spawn("phantomjs", [ this.build.dir.build + "/bridge/phantom-bridge.js", this.build.dir.build + "/bridge/qunit-phantom-bridge.html" ], { - env : process.env - }); - - child.stdout.setEncoding("utf8"); - child.stdout.on("data", function(stdout) { - stdout.toString().split("{\"event\"").forEach(function(data) { - if (!data) { - return; - } - var message = {}; - try { - message = JSON.parse("{\"event\"" + data); - } catch (e) { - throw e; - } - - if (message.event === "assertionDone") { - message.data.index = ++index; - } - if (message.event === "done") { - child.kill(); - } - self.logEvent(message.event, message.data || {}); - }); - }); - child.on("exit", function(code) { - // phantomjs doesn't exist - if (code === 127) { - self.build.printLine(self.build.color("\u2716 ", 160) + "Environment " + self.name + " not found!"); - self.onComplete(); - } - }); - } -}); - -module.exports = function(build, callback) { - build.printHeader(build.color("Running unit tests against QUnit...", "bold")); - var tests = cArray(); - if (build.env.node === true) { - tests.push(new UnitTestNodeJs(build)); - } - if (build.env.web === true) { - tests.push(new UnitTestPhantomJs(build)); - } - tests.serialEach(function(next, test) { - test.setCallback(next).start(); - }, function() { - var failed = 0, runtime = 0; - tests.forEach(function(test) { - failed += test.failed; - runtime += test.runtime; - }); - callback({ - error : failed > 0 ? new Error(failed + " Unit Test(s) failed.") : null, - time : runtime - }); - }); -}; diff --git a/build/perf.html b/build/perf.html deleted file mode 100755 index 4c656c5..0000000 --- a/build/perf.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -
          Initializing...
          NameOps/secTest
          - - - - - - - - - - - \ No newline at end of file diff --git a/build/perf/benchmark.js b/build/perf/benchmark.js deleted file mode 100755 index f20d1a1..0000000 --- a/build/perf/benchmark.js +++ /dev/null @@ -1,3802 +0,0 @@ -/*! - * Benchmark.js v1.0.0-pre - * Copyright 2010-2012 Mathias Bynens - * Based on JSLitmus.js, copyright Robert Kieffer - * Modified by John-David Dalton - * Available under MIT license - */ -;(function(window, undefined) { - 'use strict'; - - /** Used to assign each benchmark an incrimented id */ - var counter = 0; - - /** Detect DOM document object */ - var doc = isHostType(window, 'document') && document; - - /** Detect free variable `define` */ - var freeDefine = typeof define == 'function' && - typeof define.amd == 'object' && define.amd && define; - - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports && - (typeof global == 'object' && global && global == global.global && (window = global), exports); - - /** Detect free variable `require` */ - var freeRequire = typeof require == 'function' && require; - - /** Used to crawl all properties regardless of enumerability */ - var getAllKeys = Object.getOwnPropertyNames; - - /** Used to get property descriptors */ - var getDescriptor = Object.getOwnPropertyDescriptor; - - /** Used in case an object doesn't have its own method */ - var hasOwnProperty = {}.hasOwnProperty; - - /** Used to check if an object is extensible */ - var isExtensible = Object.isExtensible || function() { return true; }; - - /** Used to check if an own property is enumerable */ - var propertyIsEnumerable = {}.propertyIsEnumerable; - - /** Used to set property descriptors */ - var setDescriptor = Object.defineProperty; - - /** Used to resolve a value's internal [[Class]] */ - var toString = {}.toString; - - /** Used to prevent a `removeChild` memory leak in IE < 9 */ - var trash = doc && doc.createElement('div'); - - /** Used to integrity check compiled tests */ - var uid = 'uid' + (+new Date); - - /** Used to avoid infinite recursion when methods call each other */ - var calledBy = {}; - - /** Used to avoid hz of Infinity */ - var divisors = { - '1': 4096, - '2': 512, - '3': 64, - '4': 8, - '5': 0 - }; - - /** - * T-Distribution two-tailed critical values for 95% confidence - * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm - */ - var tTable = { - '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, - '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, - '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, - '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, - '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, - 'infinity': 1.96 - }; - - /** - * Critical Mann-Whitney U-values for 95% confidence - * http://www.saburchill.com/IBbiology/stats/003.html - */ - var uTable = { - '5': [0, 1, 2], - '6': [1, 2, 3, 5], - '7': [1, 3, 5, 6, 8], - '8': [2, 4, 6, 8, 10, 13], - '9': [2, 4, 7, 10, 12, 15, 17], - '10': [3, 5, 8, 11, 14, 17, 20, 23], - '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], - '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], - '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], - '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], - '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], - '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], - '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], - '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], - '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], - '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], - '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], - '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], - '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], - '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], - '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], - '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], - '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], - '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], - '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], - '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] - }; - - /** - * An object used to flag environments/features. - * - * @static - * @memberOf Benchmark - * @type Object - */ - var support = {}; - - (function() { - - /** - * Detect Adobe AIR. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); - - /** - * Detect if `arguments` objects have the correct internal [[Class]] value. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.argumentsClass = isClassOf(arguments, 'Arguments'); - - /** - * Detect if in a browser environment. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.browser = doc && isHostType(window, 'navigator'); - - /** - * Detect if strings support accessing characters by index. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByIndex = - // IE 8 supports indexes on string literals but not string objects - ('x'[0] + Object('x')[0]) == 'xx'; - - /** - * Detect if strings have indexes as own properties. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByOwnIndex = - // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on - // strings but don't detect them as own properties - support.charByIndex && hasKey('x', '0'); - - /** - * Detect if Java is enabled/exposed. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.java = isClassOf(window.java, 'JavaPackage'); - - /** - * Detect if the Timers API exists. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); - - /** - * Detect if functions support decompilation. - * - * @name decompilation - * @memberOf Benchmark.support - * @type Boolean - */ - try { - // Safari 2.x removes commas in object literals - // from Function#toString results - // http://webk.it/11609 - // Firefox 3.6 and Opera 9.25 strip grouping - // parentheses from Function#toString results - // http://bugzil.la/559438 - support.decompilation = Function( - 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' - )()(0).x === '1'; - } catch(e) { - support.decompilation = false; - } - - /** - * Detect ES5+ property descriptor API. - * - * @name descriptors - * @memberOf Benchmark.support - * @type Boolean - */ - try { - var o = {}; - support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); - } catch(e) { - support.descriptors = false; - } - - /** - * Detect ES5+ Object.getOwnPropertyNames(). - * - * @name getAllKeys - * @memberOf Benchmark.support - * @type Boolean - */ - try { - support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); - } catch(e) { - support.getAllKeys = false; - } - }()); - - /** - * Timer object used by `clock()` and `Deferred#resolve`. - * - * @private - * @type Object - */ - var timer = { - - /** - * The timer namespace object or constructor. - * - * @private - * @memberOf timer - * @type Function|Object - */ - 'ns': Date, - - /** - * Starts the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'start': null, // lazy defined in `clock()` - - /** - * Stops the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'stop': null // lazy defined in `clock()` - }; - - /** Shortcut for inverse results */ - var noArgumentsClass = !support.argumentsClass, - noCharByIndex = !support.charByIndex, - noCharByOwnIndex = !support.charByOwnIndex; - - /** Math shortcuts */ - var abs = Math.abs, - floor = Math.floor, - max = Math.max, - min = Math.min, - pow = Math.pow, - sqrt = Math.sqrt; - - /*--------------------------------------------------------------------------*/ - - /** - * The Benchmark constructor. - * - * @constructor - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var bench = new Benchmark(fn); - * - * // or using a name first - * var bench = new Benchmark('foo', fn); - * - * // or with options - * var bench = new Benchmark('foo', fn, { - * - * // displayed by Benchmark#toString if `name` is not available - * 'id': 'xyz', - * - * // called when the benchmark starts running - * 'onStart': onStart, - * - * // called after each run cycle - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the benchmark completes running - * 'onComplete': onComplete, - * - * // compiled/called before the test loop - * 'setup': setup, - * - * // compiled/called after the test loop - * 'teardown': teardown - * }); - * - * // or name and options - * var bench = new Benchmark('foo', { - * - * // a flag to indicate the benchmark is deferred - * 'defer': true, - * - * // benchmark test function - * 'fn': function(deferred) { - * // call resolve() when the deferred test is finished - * deferred.resolve(); - * } - * }); - * - * // or options only - * var bench = new Benchmark({ - * - * // benchmark name - * 'name': 'foo', - * - * // benchmark test as a string - * 'fn': '[1,2,3,4].sort()' - * }); - * - * // a test's `this` binding is set to the benchmark instance - * var bench = new Benchmark('foo', function() { - * 'My name is '.concat(this.name); // My name is foo - * }); - */ - function Benchmark(name, fn, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Benchmark) { - return new Benchmark(name, fn, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } - else if (isClassOf(name, 'Function')) { - // 2 arguments (fn, options) - options = fn; - fn = name; - } - else if (isClassOf(fn, 'Object')) { - // 2 arguments (name, options) - options = fn; - fn = null; - me.name = name; - } - else { - // 3 arguments (name, fn [, options]) - me.name = name; - } - setOptions(me, options); - me.id || (me.id = ++counter); - me.fn == null && (me.fn = fn); - me.stats = deepClone(me.stats); - me.times = deepClone(me.times); - } - - /** - * The Deferred constructor. - * - * @constructor - * @memberOf Benchmark - * @param {Object} clone The cloned benchmark instance. - */ - function Deferred(clone) { - var me = this; - if (me == null || me.constructor != Deferred) { - return new Deferred(clone); - } - me.benchmark = clone; - clock(me); - } - - /** - * The Event constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String|Object} type The event type. - */ - function Event(type) { - var me = this; - return (me == null || me.constructor != Event) - ? new Event(type) - : (type instanceof Event) - ? type - : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); - } - - /** - * The Suite constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String} name A name to identify the suite. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var suite = new Benchmark.Suite; - * - * // or using a name first - * var suite = new Benchmark.Suite('foo'); - * - * // or with options - * var suite = new Benchmark.Suite('foo', { - * - * // called when the suite starts running - * 'onStart': onStart, - * - * // called between running benchmarks - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the suite completes running - * 'onComplete': onComplete - * }); - */ - function Suite(name, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Suite) { - return new Suite(name, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } else { - // 2 arguments (name [, options]) - me.name = name; - } - setOptions(me, options); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Note: Some array methods have been implemented in plain JavaScript to avoid - * bugs in IE, Opera, Rhino, and Mobile Safari. - * - * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` - * functions that fail to remove the last element, `object[0]`, of - * array-like-objects even though the `length` property is set to `0`. - * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` - * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. - * - * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` - * generically to augment the `arguments` object will pave the value at index 0 - * without incrimenting the other values's indexes. - * https://github.com/documentcloud/underscore/issues/9 - * - * Rhino and environments it powers, like Narwhal and RingoJS, may have - * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and - * `unshift()` functions that make sparse arrays non-sparse by assigning the - * undefined indexes a value of undefined. - * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd - */ - - /** - * Creates an array containing the elements of the host array followed by the - * elements of each argument in order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The new array. - */ - function concat() { - var value, - j = -1, - length = arguments.length, - result = slice.call(this), - index = result.length; - - while (++j < length) { - value = arguments[j]; - if (isClassOf(value, 'Array')) { - for (var k = 0, l = value.length; k < l; k++, index++) { - if (k in value) { - result[index] = value[k]; - } - } - } else { - result[index++] = value; - } - } - return result; - } - - /** - * Utility function used by `shift()`, `splice()`, and `unshift()`. - * - * @private - * @param {Number} start The index to start inserting elements. - * @param {Number} deleteCount The number of elements to delete from the insert point. - * @param {Array} elements The elements to insert. - * @returns {Array} An array of deleted elements. - */ - function insert(start, deleteCount, elements) { - // `result` should have its length set to the `deleteCount` - // see https://bugs.ecmascript.org/show_bug.cgi?id=332 - var deleteEnd = start + deleteCount, - elementCount = elements ? elements.length : 0, - index = start - 1, - length = start + elementCount, - object = this, - result = Array(deleteCount), - tail = slice.call(object, deleteEnd); - - // delete elements from the array - while (++index < deleteEnd) { - if (index in object) { - result[index - start] = object[index]; - delete object[index]; - } - } - // insert elements - index = start - 1; - while (++index < length) { - object[index] = elements[index - start]; - } - // append tail elements - start = index--; - length = max(0, (object.length >>> 0) - deleteCount + elementCount); - while (++index < length) { - if ((index - start) in tail) { - object[index] = tail[index - start]; - } else { - delete object[index]; - } - } - // delete excess elements - deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; - while (deleteCount--) { - delete object[length + deleteCount]; - } - object.length = length; - return result; - } - - /** - * Rearrange the host array's elements in reverse order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The reversed array. - */ - function reverse() { - var upperIndex, - value, - index = -1, - object = Object(this), - length = object.length >>> 0, - middle = floor(length / 2); - - if (length > 1) { - while (++index < middle) { - upperIndex = length - index - 1; - value = upperIndex in object ? object[upperIndex] : uid; - if (index in object) { - object[upperIndex] = object[index]; - } else { - delete object[upperIndex]; - } - if (value != uid) { - object[index] = value; - } else { - delete object[index]; - } - } - } - return object; - } - - /** - * Removes the first element of the host array and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The first element of the array. - */ - function shift() { - return insert.call(this, 0, 1)[0]; - } - - /** - * Creates an array of the host array's elements from the start index up to, - * but not including, the end index. - * - * @memberOf Benchmark.Suite - * @param {Number} start The starting index. - * @param {Number} end The end index. - * @returns {Array} The new array. - */ - function slice(start, end) { - var index = -1, - object = Object(this), - length = object.length >>> 0, - result = []; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - start--; - end = end == null ? length : toInteger(end); - end = end < 0 ? max(length + end, 0) : min(end, length); - - while ((++index, ++start) < end) { - if (start in object) { - result[index] = object[start]; - } - } - return result; - } - - /** - * Allows removing a range of elements and/or inserting elements into the - * host array. - * - * @memberOf Benchmark.Suite - * @param {Number} start The start index. - * @param {Number} deleteCount The number of elements to delete. - * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. - * @returns {Array} An array of removed elements. - */ - function splice(start, deleteCount) { - var object = Object(this), - length = object.length >>> 0; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - deleteCount = min(max(toInteger(deleteCount), 0), length - start); - return insert.call(object, start, deleteCount, slice.call(arguments, 2)); - } - - /** - * Converts the specified `value` to an integer. - * - * @private - * @param {Mixed} value The value to convert. - * @returns {Number} The resulting integer. - */ - function toInteger(value) { - value = +value; - return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); - } - - /** - * Appends arguments to the host array. - * - * @memberOf Benchmark.Suite - * @returns {Number} The new length. - */ - function unshift() { - var object = Object(this); - insert.call(object, 0, 0, arguments); - return object.length; - } - - /*--------------------------------------------------------------------------*/ - - /** - * A generic `Function#bind` like method. - * - * @private - * @param {Function} fn The function to be bound to `thisArg`. - * @param {Mixed} thisArg The `this` binding for the given function. - * @returns {Function} The bound function. - */ - function bind(fn, thisArg) { - return function() { fn.apply(thisArg, arguments); }; - } - - /** - * Creates a function from the given arguments string and body. - * - * @private - * @param {String} args The comma separated function arguments. - * @param {String} body The function body. - * @returns {Function} The new function. - */ - function createFunction() { - // lazy define - createFunction = function(args, body) { - var result, - anchor = freeDefine ? define.amd : Benchmark, - prop = uid + 'createFunction'; - - runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); - result = anchor[prop]; - delete anchor[prop]; - return result; - }; - // fix JaegerMonkey bug - // http://bugzil.la/639720 - createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; - return createFunction.apply(null, arguments); - } - - /** - * Delay the execution of a function based on the benchmark's `delay` property. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} fn The function to execute. - */ - function delay(bench, fn) { - bench._timerId = setTimeout(fn, bench.delay * 1e3); - } - - /** - * Destroys the given element. - * - * @private - * @param {Element} element The element to destroy. - */ - function destroyElement(element) { - trash.appendChild(element); - trash.innerHTML = ''; - } - - /** - * Iterates over an object's properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Object} options The options object. - * @returns {Object} Returns the object iterated over. - */ - function forProps() { - var forShadowed, - skipSeen, - forArgs = true, - shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; - - (function(enumFlag, key) { - // must use a non-native constructor to catch the Safari 2 issue - function Klass() { this.valueOf = 0; }; - Klass.prototype.valueOf = 0; - // check various for-in bugs - for (key in new Klass) { - enumFlag += key == 'valueOf' ? 1 : 0; - } - // check if `arguments` objects have non-enumerable indexes - for (key in arguments) { - key == '0' && (forArgs = false); - } - // Safari 2 iterates over shadowed properties twice - // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ - skipSeen = enumFlag == 2; - // IE < 9 incorrectly makes an object's properties non-enumerable if they have - // the same name as other non-enumerable properties in its prototype chain. - forShadowed = !enumFlag; - }(0)); - - // lazy define - forProps = function(object, callback, options) { - options || (options = {}); - - var result = object; - object = Object(object); - - var ctor, - key, - keys, - skipCtor, - done = !result, - which = options.which, - allFlag = which == 'all', - index = -1, - iteratee = object, - length = object.length, - ownFlag = allFlag || which == 'own', - seen = {}, - skipProto = isClassOf(object, 'Function'), - thisArg = options.bind; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - // iterate all properties - if (allFlag && support.getAllKeys) { - for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { - key = keys[index]; - if (callback(object[key], key, object) === false) { - break; - } - } - } - // else iterate only enumerable properties - else { - for (key in object) { - // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 - // (if the prototype or a property on the prototype has been set) - // incorrectly set a function's `prototype` property [[Enumerable]] value - // to `true`. Because of this we standardize on skipping the `prototype` - // property of functions regardless of their [[Enumerable]] value. - if ((done = - !(skipProto && key == 'prototype') && - !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && - (!ownFlag || ownFlag && hasKey(object, key)) && - callback(object[key], key, object) === false)) { - break; - } - } - // in IE < 9 strings don't support accessing characters by index - if (!done && (forArgs && isArguments(object) || - ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && - (iteratee = noCharByIndex ? object.split('') : object)))) { - while (++index < length) { - if ((done = - callback(iteratee[index], String(index), object) === false)) { - break; - } - } - } - if (!done && forShadowed) { - // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing - // property and the `constructor` property of a prototype defaults to - // non-enumerable, we manually skip the `constructor` property when we - // think we are iterating over a `prototype` object. - ctor = object.constructor; - skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; - for (index = 0; index < 7; index++) { - key = shadowed[index]; - if (!(skipCtor && key == 'constructor') && - hasKey(object, key) && - callback(object[key], key, object) === false) { - break; - } - } - } - } - return result; - }; - return forProps.apply(null, arguments); - } - - /** - * Gets the name of the first argument from a function's source. - * - * @private - * @param {Function} fn The function. - * @returns {String} The argument name. - */ - function getFirstArgument(fn) { - return (!hasKey(fn, 'toString') && - (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; - } - - /** - * Computes the arithmetic mean of a sample. - * - * @private - * @param {Array} sample The sample. - * @returns {Number} The mean. - */ - function getMean(sample) { - return reduce(sample, function(sum, x) { - return sum + x; - }) / sample.length || 0; - } - - /** - * Gets the source code of a function. - * - * @private - * @param {Function} fn The function. - * @param {String} altSource A string used when a function's source code is unretrievable. - * @returns {String} The function's source code. - */ - function getSource(fn, altSource) { - var result = altSource; - if (isStringable(fn)) { - result = String(fn); - } else if (support.decompilation) { - // escape the `{` for Firefox 1 - result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; - } - return (result || '').replace(/^\s+|\s+$/g, ''); - } - - /** - * Checks if a value is an `arguments` object. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. - */ - function isArguments() { - // lazy define - isArguments = function(value) { - return toString.call(value) == '[object Arguments]'; - }; - if (noArgumentsClass) { - isArguments = function(value) { - return hasKey(value, 'callee') && - !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); - }; - } - return isArguments(arguments[0]); - } - - /** - * Checks if an object is of the specified class. - * - * @private - * @param {Mixed} value The value to check. - * @param {String} name The name of the class. - * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. - */ - function isClassOf(value, name) { - return value != null && toString.call(value) == '[object ' + name + ']'; - } - - /** - * Host objects can return type values that are different from their actual - * data type. The objects we are concerned with usually return non-primitive - * types of object, function, or unknown. - * - * @private - * @param {Mixed} object The owner of the property. - * @param {String} property The property to check. - * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. - */ - function isHostType(object, property) { - var type = object != null ? typeof object[property] : 'number'; - return !/^(?:boolean|number|string|undefined)$/.test(type) && - (type == 'object' ? !!object[property] : true); - } - - /** - * Checks if the specified `value` is an object created by the `Object` - * constructor assuming objects created by the `Object` constructor have no - * inherited enumerable properties and assuming there are no `Object.prototype` - * extensions. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if `value` is an object, else `false`. - */ - function isObject(value) { - var ctor, - result = !!value && toString.call(value) == '[object Object]'; - - if (result && noArgumentsClass) { - // avoid false positives for `arguments` objects in IE < 9 - result = !isArguments(value); - } - if (result) { - // IE < 9 presents nodes like `Object` objects: - // IE < 8 are missing the node's constructor property - // IE 8 node constructors are typeof "object" - ctor = value.constructor; - // check if the constructor is `Object` as `Object instanceof Object` is `true` - if ((result = isClassOf(ctor, 'Function') && ctor instanceof ctor)) { - // An object's own properties are iterated before inherited properties. - // If the last iterated key belongs to an object's own property then - // there are no inherited enumerable properties. - forProps(value, function(subValue, subKey) { result = subKey; }); - result = result === true || hasKey(value, result); - } - } - return result; - } - - /** - * Checks if a value can be safely coerced to a string. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. - */ - function isStringable(value) { - return hasKey(value, 'toString') || isClassOf(value, 'String'); - } - - /** - * Wraps a function and passes `this` to the original function as the - * first argument. - * - * @private - * @param {Function} fn The function to be wrapped. - * @returns {Function} The new function. - */ - function methodize(fn) { - return function() { - var args = [this]; - args.push.apply(args, arguments); - return fn.apply(null, args); - }; - } - - /** - * A no-operation function. - * - * @private - */ - function noop() { - // no operation performed - } - - /** - * A wrapper around require() to suppress `module missing` errors. - * - * @private - * @param {String} id The module id. - * @returns {Mixed} The exported module or `null`. - */ - function req(id) { - try { - var result = freeExports && freeRequire(id); - } catch(e) { } - return result || null; - } - - /** - * Runs a snippet of JavaScript via script injection. - * - * @private - * @param {String} code The code to run. - */ - function runScript(code) { - var anchor = freeDefine ? define.amd : Benchmark, - script = doc.createElement('script'), - sibling = doc.getElementsByTagName('script')[0], - parent = sibling.parentNode, - prop = uid + 'runScript', - prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; - - // Firefox 2.0.0.2 cannot use script injection as intended because it executes - // asynchronously, but that's OK because script injection is only used to avoid - // the previously commented JaegerMonkey bug. - try { - // remove the inserted script *before* running the code to avoid differences - // in the expected script element count/order of the document. - script.appendChild(doc.createTextNode(prefix + code)); - anchor[prop] = function() { destroyElement(script); }; - } catch(e) { - parent = parent.cloneNode(false); - sibling = null; - script.text = code; - } - parent.insertBefore(script, sibling); - delete anchor[prop]; - } - - /** - * A helper function for setting options/event handlers. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} [options={}] Options object. - */ - function setOptions(bench, options) { - options = extend({}, bench.constructor.options, options); - bench.options = forOwn(options, function(value, key) { - if (value != null) { - // add event listeners - if (/^on[A-Z]/.test(key)) { - forEach(key.split(' '), function(key) { - bench.on(key.slice(2).toLowerCase(), value); - }); - } else if (!hasKey(bench, key)) { - bench[key] = deepClone(value); - } - } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Handles cycling/completing the deferred benchmark. - * - * @memberOf Benchmark.Deferred - */ - function resolve() { - var me = this, - clone = me.benchmark, - bench = clone._original; - - if (bench.aborted) { - // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete - me.teardown(); - clone.running = false; - cycle(me); - } - else if (++me.cycles < clone.count) { - // continue the test loop - if (support.timeout) { - // use setTimeout to avoid a call stack overflow if called recursively - setTimeout(function() { clone.compiled.call(me, timer); }, 0); - } else { - clone.compiled.call(me, timer); - } - } - else { - timer.stop(me); - me.teardown(); - delay(clone, function() { cycle(me); }); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * A deep clone utility. - * - * @static - * @memberOf Benchmark - * @param {Mixed} value The value to clone. - * @returns {Mixed} The cloned value. - */ - function deepClone(value) { - var accessor, - circular, - clone, - ctor, - descriptor, - extensible, - key, - length, - markerKey, - parent, - result, - source, - subIndex, - data = { 'value': value }, - index = 0, - marked = [], - queue = { 'length': 0 }, - unmarked = []; - - /** - * An easily detectable decorator for cloned values. - */ - function Marker(object) { - this.raw = object; - } - - /** - * The callback used by `forProps()`. - */ - function forPropsCallback(subValue, subKey) { - // exit early to avoid cloning the marker - if (subValue && subValue.constructor == Marker) { - return; - } - // add objects to the queue - if (subValue === Object(subValue)) { - queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; - } - // assign non-objects - else { - try { - // will throw an error in strict mode if the property is read-only - clone[subKey] = subValue; - } catch(e) { } - } - } - - /** - * Gets an available marker key for the given object. - */ - function getMarkerKey(object) { - // avoid collisions with existing keys - var result = uid; - while (object[result] && object[result].constructor != Marker) { - result += 1; - } - return result; - } - - do { - key = data.key; - parent = data.parent; - source = data.source; - clone = value = source ? source[key] : data.value; - accessor = circular = descriptor = false; - - // create a basic clone to filter out functions, DOM elements, and - // other non `Object` objects - if (value === Object(value)) { - // use custom deep clone function if available - if (isClassOf(value.deepClone, 'Function')) { - clone = value.deepClone(); - } else { - ctor = value.constructor; - switch (toString.call(value)) { - case '[object Array]': - clone = new ctor(value.length); - break; - - case '[object Boolean]': - clone = new ctor(value == true); - break; - - case '[object Date]': - clone = new ctor(+value); - break; - - case '[object Object]': - isObject(value) && (clone = new ctor); - break; - - case '[object Number]': - case '[object String]': - clone = new ctor(value); - break; - - case '[object RegExp]': - clone = ctor(value.source, - (value.global ? 'g' : '') + - (value.ignoreCase ? 'i' : '') + - (value.multiline ? 'm' : '')); - } - } - // continue clone if `value` doesn't have an accessor descriptor - // http://es5.github.com/#x8.10.1 - if (clone && clone != value && - !(descriptor = source && support.descriptors && getDescriptor(source, key), - accessor = descriptor && (descriptor.get || descriptor.set))) { - // use an existing clone (circular reference) - if ((extensible = isExtensible(value))) { - markerKey = getMarkerKey(value); - if (value[markerKey]) { - circular = clone = value[markerKey].raw; - } - } else { - // for frozen/sealed objects - for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { - data = unmarked[subIndex]; - if (data.object === value) { - circular = clone = data.clone; - break; - } - } - } - if (!circular) { - // mark object to allow quickly detecting circular references and tie it to its clone - if (extensible) { - value[markerKey] = new Marker(clone); - marked.push({ 'key': markerKey, 'object': value }); - } else { - // for frozen/sealed objects - unmarked.push({ 'clone': clone, 'object': value }); - } - // iterate over object properties - forProps(value, forPropsCallback, { 'which': 'all' }); - } - } - } - if (parent) { - // for custom property descriptors - if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { - if ('value' in descriptor) { - descriptor.value = clone; - } - setDescriptor(parent, key, descriptor); - } - // for default property descriptors - else { - parent[key] = clone; - } - } else { - result = clone; - } - } while ((data = queue[index++])); - - // remove markers - for (index = 0, length = marked.length; index < length; index++) { - data = marked[index]; - delete data.object[data.key]; - } - return result; - } - - /** - * An iteration utility for arrays and objects. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array|Object} Returns the object iterated over. - */ - function each(object, callback, thisArg) { - var result = object; - object = Object(object); - - var fn = callback, - index = -1, - length = object.length, - isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), - isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), - isConvertable = isSnapshot || isSplittable || 'item' in object, - origObject = object; - - // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists - if (length === length >>> 0) { - if (isConvertable) { - // the third argument of the callback is the original non-array object - callback = function(value, index) { - return fn.call(this, value, index, origObject); - }; - // in IE < 9 strings don't support accessing characters by index - if (isSplittable) { - object = object.split(''); - } else { - object = []; - while (++index < length) { - // in Safari 2 `index in object` is always `false` for NodeLists - object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; - } - } - } - forEach(object, callback, thisArg); - } else { - forOwn(object, callback, thisArg); - } - return result; - } - - /** - * Copies enumerable properties from the source(s) object to the destination object. - * - * @static - * @memberOf Benchmark - * @param {Object} destination The destination object. - * @param {Object} [source={}] The source object. - * @returns {Object} The destination object. - */ - function extend(destination, source) { - // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` - // http://code.google.com/p/v8/issues/detail?id=839 - var result = destination; - delete arguments[0]; - - forEach(arguments, function(source) { - forProps(source, function(value, key) { - result[key] = value; - }); - }); - return result; - } - - /** - * A generic `Array#filter` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function|String} callback The function/alias called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values that passed callback filter. - * @example - * - * // get odd numbers - * Benchmark.filter([1, 2, 3, 4, 5], function(n) { - * return n % 2; - * }); // -> [1, 3, 5]; - * - * // get fastest benchmarks - * Benchmark.filter(benches, 'fastest'); - * - * // get slowest benchmarks - * Benchmark.filter(benches, 'slowest'); - * - * // get benchmarks that completed without erroring - * Benchmark.filter(benches, 'successful'); - */ - function filter(array, callback, thisArg) { - var result; - - if (callback == 'successful') { - // callback to exclude those that are errored, unrun, or have hz of Infinity - callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; - } - else if (callback == 'fastest' || callback == 'slowest') { - // get successful, sort by period + margin of error, and filter fastest/slowest - result = filter(array, 'successful').sort(function(a, b) { - a = a.stats; b = b.stats; - return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); - }); - result = filter(result, function(bench) { - return result[0].compare(bench) == 0; - }); - } - return result || reduce(array, function(result, value, index) { - return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; - }, []); - } - - /** - * A generic `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} Returns the array iterated over. - */ - function forEach(array, callback, thisArg) { - var index = -1, - length = (array = Object(array)).length >>> 0; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - while (++index < length) { - if (index in array && - callback(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * Iterates over an object's own properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Object} Returns the object iterated over. - */ - function forOwn(object, callback, thisArg) { - return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); - } - - /** - * Converts a number to a more readable comma-separated string representation. - * - * @static - * @memberOf Benchmark - * @param {Number} number The number to convert. - * @returns {String} The more readable string representation. - */ - function formatNumber(number) { - number = String(number).split('.'); - return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + - (number[1] ? '.' + number[1] : ''); - } - - /** - * Checks if an object has the specified key as a direct property. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to check. - * @param {String} key The key to check for. - * @returns {Boolean} Returns `true` if key is a direct property, else `false`. - */ - function hasKey() { - // lazy define for worst case fallback (not as accurate) - hasKey = function(object, key) { - var parent = object != null && (object.constructor || Object).prototype; - return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); - }; - // for modern browsers - if (isClassOf(hasOwnProperty, 'Function')) { - hasKey = function(object, key) { - return object != null && hasOwnProperty.call(object, key); - }; - } - // for Safari 2 - else if ({}.__proto__ == Object.prototype) { - hasKey = function(object, key) { - var result = false; - if (object != null) { - object = Object(object); - object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; - } - return result; - }; - } - return hasKey.apply(this, arguments); - } - - /** - * A generic `Array#indexOf` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Mixed} value The value to search for. - * @param {Number} [fromIndex=0] The index to start searching from. - * @returns {Number} The index of the matched value or `-1`. - */ - function indexOf(array, value, fromIndex) { - var index = toInteger(fromIndex), - length = (array = Object(array)).length >>> 0; - - index = (index < 0 ? max(0, length + index) : index) - 1; - while (++index < length) { - if (index in array && value === array[index]) { - return index; - } - } - return -1; - } - - /** - * Modify a string by replacing named tokens with matching object property values. - * - * @static - * @memberOf Benchmark - * @param {String} string The string to modify. - * @param {Object} object The template object. - * @returns {String} The modified string. - */ - function interpolate(string, object) { - forOwn(object, function(value, key) { - // escape regexp special characters in `key` - string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value); - }); - return string; - } - - /** - * Invokes a method on all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} benches Array of benchmarks to iterate over. - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - * @example - * - * // invoke `reset` on all benchmarks - * Benchmark.invoke(benches, 'reset'); - * - * // invoke `emit` with arguments - * Benchmark.invoke(benches, 'emit', 'complete', listener); - * - * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks - * Benchmark.invoke(benches, { - * - * // invoke the `run` method - * 'name': 'run', - * - * // pass a single argument - * 'args': true, - * - * // treat as queue, removing benchmarks from front of `benches` until empty - * 'queued': true, - * - * // called before any benchmarks have been invoked. - * 'onStart': onStart, - * - * // called between invoking benchmarks - * 'onCycle': onCycle, - * - * // called after all benchmarks have been invoked. - * 'onComplete': onComplete - * }); - */ - function invoke(benches, name) { - var args, - bench, - queued, - index = -1, - eventProps = { 'currentTarget': benches }, - options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop }, - result = map(benches, function(bench) { return bench; }); - - /** - * Invokes the method of the current object and if synchronous, fetches the next. - */ - function execute() { - var listeners, - async = isAsync(bench); - - if (async) { - // use `getNext` as the first listener - bench.on('complete', getNext); - listeners = bench.events.complete; - listeners.splice(0, 0, listeners.pop()); - } - // execute method - result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined; - // if synchronous return true until finished - return !async && getNext(); - } - - /** - * Fetches the next bench or executes `onComplete` callback. - */ - function getNext(event) { - var cycleEvent, - last = bench, - async = isAsync(last); - - if (async) { - last.off('complete', getNext); - last.emit('complete'); - } - // emit "cycle" event - eventProps.type = 'cycle'; - eventProps.target = last; - cycleEvent = Event(eventProps); - options.onCycle.call(benches, cycleEvent); - - // choose next benchmark if not exiting early - if (!cycleEvent.aborted && raiseIndex() !== false) { - bench = queued ? benches[0] : result[index]; - if (isAsync(bench)) { - delay(bench, execute); - } - else if (async) { - // resume execution if previously asynchronous but now synchronous - while (execute()) { } - } - else { - // continue synchronous execution - return true; - } - } else { - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // When used as a listener `event.aborted = true` will cancel the rest of - // the "complete" listeners because they were already called above and when - // used as part of `getNext` the `return false` will exit the execution while-loop. - if (event) { - event.aborted = true; - } else { - return false; - } - } - - /** - * Checks if invoking `Benchmark#run` with asynchronous cycles. - */ - function isAsync(object) { - // avoid using `instanceof` here because of IE memory leak issues with host objects - var async = args[0] && args[0].async; - return Object(object).constructor == Benchmark && name == 'run' && - ((async == null ? object.options.async : async) && support.timeout || object.defer); - } - - /** - * Raises `index` to the next defined index or returns `false`. - */ - function raiseIndex() { - var length = result.length; - if (queued) { - // if queued remove the previous bench and subsequent skipped non-entries - do { - ++index > 0 && shift.call(benches); - } while ((length = benches.length) && !('0' in benches)); - } - else { - while (++index < length && !(index in result)) { } - } - // if we reached the last index then return `false` - return (queued ? length : index < length) ? index : (index = false); - } - - // juggle arguments - if (isClassOf(name, 'String')) { - // 2 arguments (array, name) - args = slice.call(arguments, 2); - } else { - // 2 arguments (array, options) - options = extend(options, name); - name = options.name; - args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args]; - queued = options.queued; - } - - // start iterating over the array - if (raiseIndex() !== false) { - // emit "start" event - bench = result[index]; - eventProps.type = 'start'; - eventProps.target = bench; - options.onStart.call(benches, Event(eventProps)); - - // end early if the suite was aborted in an "onStart" listener - if (benches.aborted && benches.constructor == Suite && name == 'run') { - // emit "cycle" event - eventProps.type = 'cycle'; - options.onCycle.call(benches, Event(eventProps)); - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // else start - else { - if (isAsync(bench)) { - delay(bench, execute); - } else { - while (execute()) { } - } - } - } - return result; - } - - /** - * Creates a string of joined array values or object key-value pairs. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to operate on. - * @param {String} [separator1=','] The separator used between key-value pairs. - * @param {String} [separator2=': '] The separator used between keys and values. - * @returns {String} The joined result. - */ - function join(object, separator1, separator2) { - var result = [], - length = (object = Object(object)).length, - arrayLike = length === length >>> 0; - - separator2 || (separator2 = ': '); - each(object, function(value, key) { - result.push(arrayLike ? value : key + separator2 + value); - }); - return result.join(separator1 || ','); - } - - /** - * A generic `Array#map` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values returned by the callback. - */ - function map(array, callback, thisArg) { - return reduce(array, function(result, value, index) { - result[index] = callback.call(thisArg, value, index, array); - return result; - }, Array(Object(array).length >>> 0)); - } - - /** - * Retrieves the value of a specified property from all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - function pluck(array, property) { - return map(array, function(object) { - return object == null ? undefined : object[property]; - }); - } - - /** - * A generic `Array#reduce` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - function reduce(array, callback, accumulator) { - var noaccum = arguments.length < 3; - forEach(array, function(value, index) { - accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array); - }); - return accumulator; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts all benchmarks in the suite. - * - * @name abort - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function abortSuite() { - var event, - me = this, - resetting = calledBy.resetSuite; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abortSuite = true; - me.reset(); - delete calledBy.abortSuite; - - if (!resetting) { - me.aborted = true; - invoke(me, 'abort'); - } - } - } - return me; - } - - /** - * Adds a test to the benchmark suite. - * - * @memberOf Benchmark.Suite - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * suite.add(fn); - * - * // or using a name first - * suite.add('foo', fn); - * - * // or with options - * suite.add('foo', fn, { - * 'onCycle': onCycle, - * 'onComplete': onComplete - * }); - */ - function add(name, fn, options) { - var me = this, - bench = Benchmark(name, fn, options), - event = Event({ 'type': 'add', 'target': bench }); - - if (me.emit(event), !event.cancelled) { - me.push(bench); - } - return me; - } - - /** - * Creates a new suite with cloned benchmarks. - * - * @name clone - * @memberOf Benchmark.Suite - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new suite instance. - */ - function cloneSuite(options) { - var me = this, - result = new me.constructor(extend({}, me.options, options)); - - // copy own properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = value && isClassOf(value.clone, 'Function') - ? value.clone() - : deepClone(value); - } - }); - return result; - } - - /** - * An `Array#filter` like method. - * - * @name filter - * @memberOf Benchmark.Suite - * @param {Function|String} callback The function/alias called per iteration. - * @returns {Object} A new suite of benchmarks that passed callback filter. - */ - function filterSuite(callback) { - var me = this, - result = new me.constructor; - - result.push.apply(result, filter(me, callback)); - return result; - } - - /** - * Resets all benchmarks in the suite. - * - * @name reset - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function resetSuite() { - var event, - me = this, - aborting = calledBy.abortSuite; - - if (me.running && !aborting) { - // no worries, `resetSuite()` is called within `abortSuite()` - calledBy.resetSuite = true; - me.abort(); - delete calledBy.resetSuite; - } - // reset if the state has changed - else if ((me.aborted || me.running) && - (me.emit(event = Event('reset')), !event.cancelled)) { - me.running = false; - if (!aborting) { - invoke(me, 'reset'); - } - } - return me; - } - - /** - * Runs the suite. - * - * @name run - * @memberOf Benchmark.Suite - * @param {Object} [options={}] Options object. - * @returns {Object} The suite instance. - * @example - * - * // basic usage - * suite.run(); - * - * // or with options - * suite.run({ 'async': true, 'queued': true }); - */ - function runSuite(options) { - var me = this; - - me.reset(); - me.running = true; - options || (options = {}); - - invoke(me, { - 'name': 'run', - 'args': options, - 'queued': options.queued, - 'onStart': function(event) { - me.emit(event); - }, - 'onCycle': function(event) { - var bench = event.target; - if (bench.error) { - me.emit({ 'type': 'error', 'target': bench }); - } - me.emit(event); - event.aborted = me.aborted; - }, - 'onComplete': function(event) { - me.running = false; - me.emit(event); - } - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Executes all registered listeners of the specified event type. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String|Object} type The event type or object. - * @returns {Mixed} Returns the return value of the last listener executed. - */ - function emit(type) { - var listeners, - me = this, - event = Event(type), - events = me.events, - args = (arguments[0] = event, arguments); - - event.currentTarget || (event.currentTarget = me); - event.target || (event.target = me); - delete event.result; - - if (events && (listeners = hasKey(events, event.type) && events[event.type])) { - forEach(listeners.slice(), function(listener) { - if ((event.result = listener.apply(me, args)) === false) { - event.cancelled = true; - } - return !event.aborted; - }); - } - return event.result; - } - - /** - * Returns an array of event listeners for a given type that can be manipulated - * to add or remove listeners. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @returns {Array} The listeners array. - */ - function listeners(type) { - var me = this, - events = me.events || (me.events = {}); - - return hasKey(events, type) ? events[type] : (events[type] = []); - } - - /** - * Unregisters a listener for the specified event type(s), - * or unregisters all listeners for the specified event type(s), - * or unregisters all listeners for all event types. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} [type] The event type. - * @param {Function} [listener] The function to unregister. - * @returns {Object} The benchmark instance. - * @example - * - * // unregister a listener for an event type - * bench.off('cycle', listener); - * - * // unregister a listener for multiple event types - * bench.off('start cycle', listener); - * - * // unregister all listeners for an event type - * bench.off('cycle'); - * - * // unregister all listeners for multiple event types - * bench.off('start cycle complete'); - * - * // unregister all listeners for all event types - * bench.off(); - */ - function off(type, listener) { - var me = this, - events = me.events; - - events && each(type ? type.split(' ') : events, function(listeners, type) { - var index; - if (typeof listeners == 'string') { - type = listeners; - listeners = hasKey(events, type) && events[type]; - } - if (listeners) { - if (listener) { - index = indexOf(listeners, listener); - if (index > -1) { - listeners.splice(index, 1); - } - } else { - listeners.length = 0; - } - } - }); - return me; - } - - /** - * Registers a listener for the specified event type(s). - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @param {Function} listener The function to register. - * @returns {Object} The benchmark instance. - * @example - * - * // register a listener for an event type - * bench.on('cycle', listener); - * - * // register a listener for multiple event types - * bench.on('start cycle', listener); - */ - function on(type, listener) { - var me = this, - events = me.events || (me.events = {}); - - forEach(type.split(' '), function(type) { - (hasKey(events, type) - ? events[type] - : (events[type] = []) - ).push(listener); - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts the benchmark without recording times. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function abort() { - var event, - me = this, - resetting = calledBy.reset; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abort = true; - me.reset(); - delete calledBy.abort; - - if (support.timeout) { - clearTimeout(me._timerId); - delete me._timerId; - } - if (!resetting) { - me.aborted = true; - me.running = false; - } - } - } - return me; - } - - /** - * Creates a new benchmark using the same test and options. - * - * @memberOf Benchmark - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new benchmark instance. - * @example - * - * var bizarro = bench.clone({ - * 'name': 'doppelganger' - * }); - */ - function clone(options) { - var me = this, - result = new me.constructor(extend({}, me, options)); - - // correct the `options` object - result.options = extend({}, me.options, options); - - // copy own custom properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = deepClone(value); - } - }); - return result; - } - - /** - * Determines if a benchmark is faster than another. - * - * @memberOf Benchmark - * @param {Object} other The benchmark to compare. - * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate. - */ - function compare(other) { - var critical, - zStat, - me = this, - sample1 = me.stats.sample, - sample2 = other.stats.sample, - size1 = sample1.length, - size2 = sample2.length, - maxSize = max(size1, size2), - minSize = min(size1, size2), - u1 = getU(sample1, sample2), - u2 = getU(sample2, sample1), - u = min(u1, u2); - - function getScore(xA, sampleB) { - return reduce(sampleB, function(total, xB) { - return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); - }, 0); - } - - function getU(sampleA, sampleB) { - return reduce(sampleA, function(total, xA) { - return total + getScore(xA, sampleB); - }, 0); - } - - function getZ(u) { - return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); - } - - // exit early if comparing the same benchmark - if (me == other) { - return 0; - } - // reject the null hyphothesis the two samples come from the - // same population (i.e. have the same median) if... - if (size1 + size2 > 30) { - // ...the z-stat is greater than 1.96 or less than -1.96 - // http://www.statisticslectures.com/topics/mannwhitneyu/ - zStat = getZ(u); - return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0; - } - // ...the U value is less than or equal the critical U value - // http://www.geoib.com/mann-whitney-u-test.html - critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3]; - return u <= critical ? (u == u1 ? 1 : -1) : 0; - } - - /** - * Reset properties and abort if running. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function reset() { - var data, - event, - me = this, - index = 0, - changes = { 'length': 0 }, - queue = { 'length': 0 }; - - if (me.running && !calledBy.abort) { - // no worries, `reset()` is called within `abort()` - calledBy.reset = true; - me.abort(); - delete calledBy.reset; - } - else { - // a non-recursive solution to check if properties have changed - // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4 - data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) }; - do { - forOwn(data.source, function(value, key) { - var changed, - destination = data.destination, - currValue = destination[key]; - - if (value && typeof value == 'object') { - if (isClassOf(value, 'Array')) { - // check if an array value has changed to a non-array value - if (!isClassOf(currValue, 'Array')) { - changed = currValue = []; - } - // or has changed its length - if (currValue.length != value.length) { - changed = currValue = currValue.slice(0, value.length); - currValue.length = value.length; - } - } - // check if an object has changed to a non-object value - else if (!currValue || typeof currValue != 'object') { - changed = currValue = {}; - } - // register a changed object - if (changed) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue }; - } - queue[queue.length++] = { 'destination': currValue, 'source': value }; - } - // register a changed primitive - else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value }; - } - }); - } - while ((data = queue[index++])); - - // if changed emit the `reset` event and if it isn't cancelled reset the benchmark - if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) { - forEach(changes, function(data) { - data.destination[data.key] = data.value; - }); - } - } - return me; - } - - /** - * Displays relevant benchmark information when coerced to a string. - * - * @name toString - * @memberOf Benchmark - * @returns {String} A string representation of the benchmark instance. - */ - function toStringBench() { - var me = this, - error = me.error, - hz = me.hz, - id = me.id, - stats = me.stats, - size = stats.sample.length, - pm = support.java ? '+/-' : '\xb1', - result = me.name || (isNaN(id) ? id : ''); - - if (error) { - result += ': ' + join(error); - } else { - result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + - stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Clocks the time taken to execute a test per cycle (secs). - * - * @private - * @param {Object} bench The benchmark instance. - * @returns {Number} The time taken. - */ - function clock() { - var applet, - options = Benchmark.options, - template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid }, - timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; - - // lazy define for hi-res timers - clock = function(clone) { - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = deferred.benchmark; - } - - var bench = clone._original, - fn = bench.fn, - fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '', - stringable = isStringable(fn); - - var source = { - 'setup': getSource(bench.setup, preprocess('m$.setup()')), - 'fn': getSource(fn, preprocess('f$(' + fnArg + ')')), - 'fnArg': fnArg, - 'teardown': getSource(bench.teardown, preprocess('m$.teardown()')) - }; - - var compiled = bench.compiled, - count = bench.count = clone.count, - decompilable = support.decompilation || stringable, - id = bench.id, - isEmpty = !(source.fn || stringable), - name = bench.name || (typeof id == 'number' ? '' : id), - ns = timer.ns, - result = 0; - - // init `minTime` if needed - clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); - - // repair nanosecond timer - // (some Chrome builds erase the `ns` variable after millions of executions) - if (applet) { - try { - ns.nanoTime(); - } catch(e) { - // use non-element to avoid issues with libs that augment them - ns = timer.ns = new applet.Packages.nano; - } - } - - if (!compiled) { - // compile in setup/teardown functions and the test loop - compiled = bench.compiled = createFunction(preprocess('t$'), interpolate( - preprocess(deferred - ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' + - // when `deferred.cycles` is `0` then... - 'if(!d$.cycles){' + - // set `deferred.fn` - 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' + - // set `deferred.teardown` - 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' + - // execute the benchmark's `setup` - 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' + - // start timer - 't$.start(d$);' + - // execute `deferred.fn` and return a dummy object - '}d$.fn();return{}' - - : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' + - 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'), - source - )); - - try { - if (isEmpty) { - // Firefox may remove dead code from Function#toString results - // http://bugzil.la/536085 - throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); - } - else if (!deferred) { - // pretest to determine if compiled code is exits early, usually by a - // rogue `return` statement, by checking for a return object with the uid - bench.count = 1; - compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled; - bench.count = count; - } - } catch(e) { - compiled = null; - clone.error = e || new Error(String(e)); - bench.count = count; - } - // fallback when a test exits early or errors during pretest - if (decompilable && !compiled && !deferred && !isEmpty) { - compiled = createFunction(preprocess('t$'), interpolate( - preprocess( - (clone.error && !stringable - ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count' - : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count' - ) + - ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' + - 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}' - ), - source - )); - - try { - // pretest one more time to check for errors - bench.count = 1; - compiled.call(bench, timer); - bench.compiled = compiled; - bench.count = count; - delete clone.error; - } - catch(e) { - bench.count = count; - if (clone.error) { - compiled = null; - } else { - bench.compiled = compiled; - clone.error = e || new Error(String(e)); - } - } - } - } - // assign `compiled` to `clone` before calling in case a deferred benchmark - // immediately calls `deferred.resolve()` - clone.compiled = compiled; - // if no errors run the full test loop - if (!clone.error) { - result = compiled.call(deferred || bench, timer).elapsed; - } - return result; - }; - - /*------------------------------------------------------------------------*/ - - /** - * Gets the current timer's minimum resolution (secs). - */ - function getRes(unit) { - var measured, - begin, - count = 30, - divisor = 1e3, - ns = timer.ns, - sample = []; - - // get average smallest measurable time - while (count--) { - if (unit == 'us') { - divisor = 1e6; - if (ns.stop) { - ns.start(); - while (!(measured = ns.microseconds())) { } - } else { - begin = timer.ns(); - while (!(measured = ns() - begin)) { } - } - } - else if (unit == 'ns') { - divisor = 1e9; - begin = ns.nanoTime(); - while (!(measured = ns.nanoTime() - begin)) { } - } - else { - begin = new ns; - while (!(measured = new ns - begin)) { } - } - // check for broken timers (nanoTime may have issues) - // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/ - if (measured > 0) { - sample.push(measured); - } else { - sample.push(Infinity); - break; - } - } - // convert to seconds - return getMean(sample) / divisor; - } - - /** - * Replaces all occurrences of `$` with a unique number and - * template tokens with content. - */ - function preprocess(code) { - return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid)); - } - - /*------------------------------------------------------------------------*/ - - // detect nanosecond support from a Java applet - each(doc && doc.applets || [], function(element) { - return !(timer.ns = applet = 'nanoTime' in element && element); - }); - - // check type in case Safari returns an object instead of a number - try { - if (typeof timer.ns.nanoTime() == 'number') { - timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); - } - } catch(e) { } - - // detect Chrome's microsecond timer: - // enable benchmarking via the --enable-benchmarking command - // line switch in at least Chrome 7 to use chrome.Interval - try { - if ((timer.ns = new (window.chrome || window.chromium).Interval)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - } catch(e) { } - - // detect Node's microtime module: - // npm install microtime - if ((timer.ns = (req('microtime') || { 'now': 0 }).now)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - - // pick timer with highest resolution - timer = reduce(timers, function(timer, other) { - return other.res < timer.res ? other : timer; - }); - - // remove unused applet - if (timer.unit != 'ns' && applet) { - applet = destroyElement(applet); - } - // error if there are no working timers - if (timer.res == Infinity) { - throw new Error('Benchmark.js was unable to find a working timer.'); - } - // use API of chosen timer - if (timer.unit == 'ns') { - extend(template, { - 'begin': 's$=n$.nanoTime()', - 'end': 'r$=(n$.nanoTime()-s$)/1e9' - }); - } - else if (timer.unit == 'us') { - extend(template, timer.ns.stop ? { - 'begin': 's$=n$.start()', - 'end': 'r$=n$.microseconds()/1e6' - } : { - 'begin': 's$=n$()', - 'end': 'r$=(n$()-s$)/1e6' - }); - } - - // define `timer` methods - timer.start = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$')); - - timer.stop = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$')); - - // resolve time span required to achieve a percent uncertainty of at most 1% - // http://spiff.rit.edu/classes/phys273/uncert/uncert.html - options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05)); - return clock.apply(null, arguments); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Computes stats on benchmark results. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} options The options object. - */ - function compute(bench, options) { - options || (options = {}); - - var async = options.async, - elapsed = 0, - initCount = bench.initCount, - minSamples = bench.minSamples, - queue = [], - sample = bench.stats.sample; - - /** - * Adds a number of clones to the queue. - */ - function enqueue(count) { - while (count--) { - queue.push(bench.clone({ - '_original': bench, - 'events': { - 'abort': [update], - 'cycle': [update], - 'error': [update], - 'start': [update] - } - })); - } - } - - /** - * Updates the clone/original benchmarks to keep their data in sync. - */ - function update(event) { - var clone = this, - type = event.type; - - if (bench.running) { - if (type == 'start') { - // Note: `clone.minTime` prop is inited in `clock()` - clone.count = bench.initCount; - } - else { - if (type == 'error') { - bench.error = clone.error; - } - if (type == 'abort') { - bench.abort(); - bench.emit('cycle'); - } else { - event.currentTarget = event.target = bench; - bench.emit(event); - } - } - } else if (bench.aborted) { - // clear abort listeners to avoid triggering bench's abort/cycle again - clone.events.abort.length = 0; - clone.abort(); - } - } - - /** - * Determines if more clones should be queued or if cycling should stop. - */ - function evaluate(event) { - var critical, - df, - mean, - moe, - rme, - sd, - sem, - variance, - clone = event.target, - done = bench.aborted, - now = +new Date, - size = sample.push(clone.times.period), - maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, - times = bench.times, - varOf = function(sum, x) { return sum + pow(x - mean, 2); }; - - // exit early for aborted or unclockable tests - if (done || clone.hz == Infinity) { - maxedOut = !(size = sample.length = queue.length = 0); - } - - if (!done) { - // sample mean (estimate of the population mean) - mean = getMean(sample); - // sample variance (estimate of the population variance) - variance = reduce(sample, varOf, 0) / (size - 1) || 0; - // sample standard deviation (estimate of the population standard deviation) - sd = sqrt(variance); - // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean) - sem = sd / sqrt(size); - // degrees of freedom - df = size - 1; - // critical value - critical = tTable[Math.round(df) || 1] || tTable.infinity; - // margin of error - moe = sem * critical; - // relative margin of error - rme = (moe / mean) * 100 || 0; - - extend(bench.stats, { - 'deviation': sd, - 'mean': mean, - 'moe': moe, - 'rme': rme, - 'sem': sem, - 'variance': variance - }); - - // Abort the cycle loop when the minimum sample size has been collected - // and the elapsed time exceeds the maximum time allowed per benchmark. - // We don't count cycle delays toward the max time because delays may be - // increased by browsers that clamp timeouts for inactive tabs. - // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs - if (maxedOut) { - // reset the `initCount` in case the benchmark is rerun - bench.initCount = initCount; - bench.running = false; - done = true; - times.elapsed = (now - times.timeStamp) / 1e3; - } - if (bench.hz != Infinity) { - bench.hz = 1 / mean; - times.cycle = mean * bench.count; - times.period = mean; - } - } - // if time permits, increase sample size to reduce the margin of error - if (queue.length < 2 && !maxedOut) { - enqueue(1); - } - // abort the invoke cycle when done - event.aborted = done; - } - - // init queue and begin - enqueue(minSamples); - invoke(queue, { - 'name': 'run', - 'args': { 'async': async }, - 'queued': true, - 'onCycle': evaluate, - 'onComplete': function() { bench.emit('complete'); } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Cycles a benchmark until a run `count` can be established. - * - * @private - * @param {Object} clone The cloned benchmark instance. - * @param {Object} options The options object. - */ - function cycle(clone, options) { - options || (options = {}); - - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = clone.benchmark; - } - - var clocked, - cycles, - divisor, - event, - minTime, - period, - async = options.async, - bench = clone._original, - count = clone.count, - times = clone.times; - - // continue, if not aborted between cycles - if (clone.running) { - // `minTime` is set to `Benchmark.options.minTime` in `clock()` - cycles = ++clone.cycles; - clocked = deferred ? deferred.elapsed : clock(clone); - minTime = clone.minTime; - - if (cycles > bench.cycles) { - bench.cycles = cycles; - } - if (clone.error) { - event = Event('error'); - event.message = clone.error; - clone.emit(event); - if (!event.cancelled) { - clone.abort(); - } - } - } - - // continue, if not errored - if (clone.running) { - // time taken to complete last test cycle - bench.times.cycle = times.cycle = clocked; - // seconds per operation - period = bench.times.period = times.period = clocked / count; - // ops per second - bench.hz = clone.hz = 1 / period; - // avoid working our way up to this next time - bench.initCount = clone.initCount = count; - // do we need to do another cycle? - clone.running = clocked < minTime; - - if (clone.running) { - // tests may clock at `0` when `initCount` is a small number, - // to avoid that we set its count to something a bit higher - if (!clocked && (divisor = divisors[clone.cycles]) != null) { - count = floor(4e6 / divisor); - } - // calculate how many more iterations it will take to achive the `minTime` - if (count <= clone.count) { - count += Math.ceil((minTime - clocked) / period); - } - clone.running = count != Infinity; - } - } - // should we exit early? - event = Event('cycle'); - clone.emit(event); - if (event.aborted) { - clone.abort(); - } - // figure out what to do next - if (clone.running) { - // start a new cycle - clone.count = count; - if (deferred) { - clone.compiled.call(deferred, timer); - } else if (async) { - delay(clone, function() { cycle(clone, options); }); - } else { - cycle(clone); - } - } - else { - // fix TraceMonkey bug associated with clock fallbacks - // http://bugzil.la/509069 - if (support.browser) { - runScript(uid + '=1;delete ' + uid); - } - // done - clone.emit('complete'); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * Runs the benchmark. - * - * @memberOf Benchmark - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * bench.run(); - * - * // or with options - * bench.run({ 'async': true }); - */ - function run(options) { - var me = this, - event = Event('start'); - - // set `running` to `false` so `reset()` won't call `abort()` - me.running = false; - me.reset(); - me.running = true; - - me.count = me.initCount; - me.times.timeStamp = +new Date; - me.emit(event); - - if (!event.cancelled) { - options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout }; - - // for clones created within `compute()` - if (me._original) { - if (me.defer) { - Deferred(me); - } else { - cycle(me, options); - } - } - // for original benchmarks - else { - compute(me, options); - } - } - return me; - } - - /*--------------------------------------------------------------------------*/ - - // Firefox 1 erroneously defines variable and argument names of functions on - // the function itself as non-configurable properties with `undefined` values. - // The bugginess continues as the `Benchmark` constructor has an argument - // named `options` and Firefox 1 will not assign a value to `Benchmark.options`, - // making it non-writable in the process, unless it is the first property - // assigned by for-in loop of `extend()`. - extend(Benchmark, { - - /** - * The default options copied by benchmark instances. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'options': { - - /** - * A flag to indicate that benchmark cycles will execute asynchronously - * by default. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'async': false, - - /** - * A flag to indicate that the benchmark clock is deferred. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'defer': false, - - /** - * The delay between test cycles (secs). - * @memberOf Benchmark.options - * @type Number - */ - 'delay': 0.005, - - /** - * Displayed by Benchmark#toString when a `name` is not available - * (auto-generated if absent). - * - * @memberOf Benchmark.options - * @type String - */ - 'id': undefined, - - /** - * The default number of times to execute a test on a benchmark's first cycle. - * - * @memberOf Benchmark.options - * @type Number - */ - 'initCount': 1, - - /** - * The maximum time a benchmark is allowed to run before finishing (secs). - * Note: Cycle delays aren't counted toward the maximum time. - * - * @memberOf Benchmark.options - * @type Number - */ - 'maxTime': 5, - - /** - * The minimum sample size required to perform statistical analysis. - * - * @memberOf Benchmark.options - * @type Number - */ - 'minSamples': 5, - - /** - * The time needed to reduce the percent uncertainty of measurement to 1% (secs). - * - * @memberOf Benchmark.options - * @type Number - */ - 'minTime': 0, - - /** - * The name of the benchmark. - * - * @memberOf Benchmark.options - * @type String - */ - 'name': undefined, - - /** - * An event listener called when the benchmark is aborted. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onAbort': undefined, - - /** - * An event listener called when the benchmark completes running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onComplete': undefined, - - /** - * An event listener called after each run cycle. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onCycle': undefined, - - /** - * An event listener called when a test errors. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onError': undefined, - - /** - * An event listener called when the benchmark is reset. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onReset': undefined, - - /** - * An event listener called when the benchmark starts running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onStart': undefined - }, - - /** - * Platform object with properties describing things like browser name, - * version, and operating system. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'platform': req('platform') || window.platform || { - - /** - * The platform description. - * - * @memberOf Benchmark.platform - * @type String - */ - 'description': window.navigator && navigator.userAgent || null, - - /** - * The name of the browser layout engine. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'layout': null, - - /** - * The name of the product hosting the browser. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'product': null, - - /** - * The name of the browser/environment. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'name': null, - - /** - * The name of the product's manufacturer. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'manufacturer': null, - - /** - * The name of the operating system. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'os': null, - - /** - * The alpha/beta release indicator. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'prerelease': null, - - /** - * The browser/environment version. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'version': null, - - /** - * Return platform description when the platform object is coerced to a string. - * - * @memberOf Benchmark.platform - * @type Function - * @returns {String} The platform description. - */ - 'toString': function() { - return this.description || ''; - } - }, - - /** - * The semantic version number. - * - * @static - * @memberOf Benchmark - * @type String - */ - 'version': '1.0.0-pre', - - // an object of environment/feature detection flags - 'support': support, - - // clone objects - 'deepClone': deepClone, - - // iteration utility - 'each': each, - - // augment objects - 'extend': extend, - - // generic Array#filter - 'filter': filter, - - // generic Array#forEach - 'forEach': forEach, - - // generic own property iteration utility - 'forOwn': forOwn, - - // converts a number to a comma-separated string - 'formatNumber': formatNumber, - - // generic Object#hasOwnProperty - // (trigger hasKey's lazy define before assigning it to Benchmark) - 'hasKey': (hasKey(Benchmark, ''), hasKey), - - // generic Array#indexOf - 'indexOf': indexOf, - - // template utility - 'interpolate': interpolate, - - // invokes a method on each item in an array - 'invoke': invoke, - - // generic Array#join for arrays and objects - 'join': join, - - // generic Array#map - 'map': map, - - // retrieves a property value from each item in an array - 'pluck': pluck, - - // generic Array#reduce - 'reduce': reduce - }); - - /*--------------------------------------------------------------------------*/ - - extend(Benchmark.prototype, { - - /** - * The number of times a test was executed. - * - * @memberOf Benchmark - * @type Number - */ - 'count': 0, - - /** - * The number of cycles performed while benchmarking. - * - * @memberOf Benchmark - * @type Number - */ - 'cycles': 0, - - /** - * The number of executions per second. - * - * @memberOf Benchmark - * @type Number - */ - 'hz': 0, - - /** - * The compiled test function. - * - * @memberOf Benchmark - * @type Function|String - */ - 'compiled': undefined, - - /** - * The error object if the test failed. - * - * @memberOf Benchmark - * @type Object - */ - 'error': undefined, - - /** - * The test to benchmark. - * - * @memberOf Benchmark - * @type Function|String - */ - 'fn': undefined, - - /** - * A flag to indicate if the benchmark is aborted. - * - * @memberOf Benchmark - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the benchmark is running. - * - * @memberOf Benchmark - * @type Boolean - */ - 'running': false, - - /** - * Compiled into the test and executed immediately **before** the test loop. - * - * @memberOf Benchmark - * @type Function|String - * @example - * - * // basic usage - * var bench = Benchmark({ - * 'setup': function() { - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * }, - * 'fn': function() { - * element.removeChild(element.lastChild); - * } - * }); - * - * // compiles to something like: - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * var start = new Date; - * while (count--) { - * element.removeChild(element.lastChild); - * } - * var end = new Date - start; - * - * // or using strings - * var bench = Benchmark({ - * 'setup': '\ - * var a = 0;\n\ - * (function() {\n\ - * (function() {\n\ - * (function() {', - * 'fn': 'a += 1;', - * 'teardown': '\ - * }())\n\ - * }())\n\ - * }())' - * }); - * - * // compiles to something like: - * var a = 0; - * (function() { - * (function() { - * (function() { - * var start = new Date; - * while (count--) { - * a += 1; - * } - * var end = new Date - start; - * }()) - * }()) - * }()) - */ - 'setup': noop, - - /** - * Compiled into the test and executed immediately **after** the test loop. - * - * @memberOf Benchmark - * @type Function|String - */ - 'teardown': noop, - - /** - * An object of stats including mean, margin or error, and standard deviation. - * - * @memberOf Benchmark - * @type Object - */ - 'stats': { - - /** - * The margin of error. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'moe': 0, - - /** - * The relative margin of error (expressed as a percentage of the mean). - * - * @memberOf Benchmark#stats - * @type Number - */ - 'rme': 0, - - /** - * The standard error of the mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'sem': 0, - - /** - * The sample standard deviation. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'deviation': 0, - - /** - * The sample arithmetic mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'mean': 0, - - /** - * The array of sampled periods. - * - * @memberOf Benchmark#stats - * @type Array - */ - 'sample': [], - - /** - * The sample variance. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'variance': 0 - }, - - /** - * An object of timing data including cycle, elapsed, period, start, and stop. - * - * @memberOf Benchmark - * @type Object - */ - 'times': { - - /** - * The time taken to complete the last cycle (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'cycle': 0, - - /** - * The time taken to complete the benchmark (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'elapsed': 0, - - /** - * The time taken to execute the test once (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'period': 0, - - /** - * A timestamp of when the benchmark started (ms). - * - * @memberOf Benchmark#times - * @type Number - */ - 'timeStamp': 0 - }, - - // aborts benchmark (does not record times) - 'abort': abort, - - // creates a new benchmark using the same test and options - 'clone': clone, - - // compares benchmark's hertz with another - 'compare': compare, - - // executes listeners - 'emit': emit, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // reset benchmark properties - 'reset': reset, - - // runs the benchmark - 'run': run, - - // pretty print benchmark info - 'toString': toStringBench - }); - - /*--------------------------------------------------------------------------*/ - - extend(Deferred.prototype, { - - /** - * The deferred benchmark instance. - * - * @memberOf Benchmark.Deferred - * @type Object - */ - 'benchmark': null, - - /** - * The number of deferred cycles performed while benchmarking. - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'cycles': 0, - - /** - * The time taken to complete the deferred benchmark (secs). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'elapsed': 0, - - /** - * A timestamp of when the deferred benchmark started (ms). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'timeStamp': 0, - - // cycles/completes the deferred benchmark - 'resolve': resolve - }); - - /*--------------------------------------------------------------------------*/ - - extend(Event.prototype, { - - /** - * A flag to indicate if the emitters listener iteration is aborted. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the default action is cancelled. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'cancelled': false, - - /** - * The object whose listeners are currently being processed. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'currentTarget': undefined, - - /** - * The return value of the last executed listener. - * - * @memberOf Benchmark.Event - * @type Mixed - */ - 'result': undefined, - - /** - * The object to which the event was originally emitted. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'target': undefined, - - /** - * A timestamp of when the event was created (ms). - * - * @memberOf Benchmark.Event - * @type Number - */ - 'timeStamp': 0, - - /** - * The event type. - * - * @memberOf Benchmark.Event - * @type String - */ - 'type': '' - }); - - /*--------------------------------------------------------------------------*/ - - /** - * The default options copied by suite instances. - * - * @static - * @memberOf Benchmark.Suite - * @type Object - */ - Suite.options = { - - /** - * The name of the suite. - * - * @memberOf Benchmark.Suite.options - * @type String - */ - 'name': undefined - }; - - /*--------------------------------------------------------------------------*/ - - extend(Suite.prototype, { - - /** - * The number of benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @type Number - */ - 'length': 0, - - /** - * A flag to indicate if the suite is aborted. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the suite is running. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'running': false, - - /** - * An `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Object} The suite iterated over. - */ - 'forEach': methodize(forEach), - - /** - * An `Array#indexOf` like method. - * - * @memberOf Benchmark.Suite - * @param {Mixed} value The value to search for. - * @returns {Number} The index of the matched value or `-1`. - */ - 'indexOf': methodize(indexOf), - - /** - * Invokes a method on all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - */ - 'invoke': methodize(invoke), - - /** - * Converts the suite of benchmarks to a string. - * - * @memberOf Benchmark.Suite - * @param {String} [separator=','] A string to separate each element of the array. - * @returns {String} The string. - */ - 'join': [].join, - - /** - * An `Array#map` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Array} A new array of values returned by the callback. - */ - 'map': methodize(map), - - /** - * Retrieves the value of a specified property from all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - 'pluck': methodize(pluck), - - /** - * Removes the last benchmark from the suite and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The removed benchmark. - */ - 'pop': [].pop, - - /** - * Appends benchmarks to the suite. - * - * @memberOf Benchmark.Suite - * @returns {Number} The suite's new length. - */ - 'push': [].push, - - /** - * Sorts the benchmarks of the suite. - * - * @memberOf Benchmark.Suite - * @param {Function} [compareFn=null] A function that defines the sort order. - * @returns {Object} The sorted suite. - */ - 'sort': [].sort, - - /** - * An `Array#reduce` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - 'reduce': methodize(reduce), - - // aborts all benchmarks in the suite - 'abort': abortSuite, - - // adds a benchmark to the suite - 'add': add, - - // creates a new suite with cloned benchmarks - 'clone': cloneSuite, - - // executes listeners of a specified type - 'emit': emit, - - // creates a new suite of filtered benchmarks - 'filter': filterSuite, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // resets all benchmarks in the suite - 'reset': resetSuite, - - // runs all benchmarks in the suite - 'run': runSuite, - - // array methods - 'concat': concat, - - 'reverse': reverse, - - 'shift': shift, - - 'slice': slice, - - 'splice': splice, - - 'unshift': unshift - }); - - /*--------------------------------------------------------------------------*/ - - // expose Deferred, Event and Suite - extend(Benchmark, { - 'Deferred': Deferred, - 'Event': Event, - 'Suite': Suite - }); - - // expose Benchmark - if (freeExports) { - // in Node.js or RingoJS v0.8.0+ - if (typeof module == 'object' && module && module.exports == freeExports) { - (module.exports = Benchmark).Benchmark = Benchmark; - } - // in Narwhal or RingoJS v0.7.0- - else { - freeExports.Benchmark = Benchmark; - } - } - // via an AMD loader - else if (freeDefine) { - define('benchmark', function() { - return Benchmark; - }); - } - // in a browser or Rhino - else { - // use square bracket notation so Closure Compiler won't munge `Benchmark` - // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export - window['Benchmark'] = Benchmark; - } - - // trigger clock's lazy define early to avoid a security error - if (support.air) { - clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } }); - } -}(this)); diff --git a/build/perf/perf.css b/build/perf/perf.css deleted file mode 100755 index ddee6ab..0000000 --- a/build/perf/perf.css +++ /dev/null @@ -1,176 +0,0 @@ -/****************************************************************************************** - MASTER RESET OF BROWSER STYLES @http://meyerweb.com/eric/tools/css/reset/index.html -******************************************************************************************/ -/**************************** - Base -*****************************/ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, -p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, -ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, input, textarea, select, option, optgroup, -button, button:active, button:focus, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, time, mark, audio, video { - background:transparent; - border:0; - font-family:inherit; - font-size:100%; - font-style:normal; - font-weight:inherit; - margin:0; - outline:0; - padding:0; - text-align:left; - vertical-align:baseline; -} -div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, -p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, -ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, -dl, dt, dd, ol, ul, li, fieldset, form, label, legend, input, textarea, select, option, optgroup, -button, button:active, button:focus, -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, time, mark, audio, video { - position:relative; -} -table, caption, tbody, tfoot, thead, tr, th, td { - -} -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { - display:block; -} -body { - line-height:1; -} -ol, ul { - list-style:none none; -} -blockquote, q { - quotes:none; -} -blockquote:before, blockquote:after, q:before, q:after { - content:''; - content:none; -} -:focus { - outline:0; -} -ins { - text-decoration:none; -} -del { - text-decoration:line-through; -} -table { - border-collapse:collapse; - border-spacing:0; - empty-cells:show; - width: 100%; -} -iframe { - display: none; -} -thead { - display: table-header-group; -} -tfoot { - display: table-footer-group; -} - - - -body { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; - padding: 8px; -} - -#perf-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 15px 15px 0 0; - -moz-border-radius: 15px 15px 0 0; - -webkit-border-top-right-radius: 15px; - -webkit-border-top-left-radius: 15px; - border-bottom: 5px solid #999999; -} - -#qunit-banner.qunit-pass { background-color: #C6E746; } -#qunit-banner.qunit-fail { background-color: #EE5757; } - -#perf-status { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; -} -.perf-sub-header { - -} -.perf-sub-header th { - text-align: center; - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - -#perf-tests th, #perf-tests td { - padding: 0.5em 0.5em 0.5em 1.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-bottom: 1px solid white; - - font-size: small; -} -#perf-tests .test-name { - color: #366097; - font-weight: bold; - min-width: 120px; - width: 120px; -} -#perf-tests .test-name a { - color: #366097; - font-weight: bold; - text-decoration: none; -} -#perf-tests .test-name a:hover { - text-decoration: underline; -} -#perf-tests .test-body { - -} -#perf-tests .test-body pre { - font-family: consolas, monospace, serif; - font-size: 0.9em; - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; -} -#perf-tests .test-status { - font-weight: bold; - min-width: 200px; - width: 200px; - text-align: right; -} -#perf-tests .test-status small { - font-size: small; - font-weight: normal; -} -#perf-tests .test-error th, #perf-tests .test-error td { - background-color: #ffafaf; -} -#perf-tests .test-error th, #perf-tests .test-error td { - color: #d75f5f; -} -#perf-tests .test-error .test-name, #perf-tests .test-error .test-name a { - color: #af0000; -} \ No newline at end of file diff --git a/build/perf/perf.js b/build/perf/perf.js deleted file mode 100755 index 5e69373..0000000 --- a/build/perf/perf.js +++ /dev/null @@ -1,87 +0,0 @@ -(function(window, tests) { - - function addListener(element, eventName, handler) { - if (typeof element.addEventListener != 'undefined') { - element.addEventListener(eventName, handler, false); - } else if (typeof element.attachEvent != 'undefined') { - element.attachEvent('on' + eventName, handler); - } - return element; - } - - var table = document.getElementById("perf-tests"); - var statusElem = document.getElementById("perf-status"); - - var textProp = document.all ? "innerText" : "textContent"; - - tests.on("add", function(e) { - var test = e.target; - var tr = document.createElement("tr"); - var tdName = document.createElement("th"); - var tdBody = document.createElement("td"); - var tdStatus = document.createElement("td"); - var i = 0; - - var preBody = document.createElement("pre"); - tdBody.appendChild(preBody); - - var aName = document.createElement("a"); - aName.href = "#restart"; - tdName.appendChild(aName); - addListener(aName, "click", function() { - test.abort().reset().run({ - async : true, - queue : true - }); - return false; - }); - - tdName.className = "test-name"; - tdBody.className = "test-body"; - tdStatus.className = "test-status"; - - aName[textProp] = test.name; - preBody[textProp] = test.fn.toString().replace(/\t/g, " ").replace(/^function\s*\(.*\)\s*\{\s*[\n\r]+/, "").replace(/\s*[\n\r]+\s*}\s*$/, "").replace(/^\ /gm, ""); - tdStatus[textProp] = "Ready"; - - tr.appendChild(tdName); - tr.appendChild(tdStatus); - tr.appendChild(tdBody); - table.appendChild(tr); - - // bind events - test.on("start", function(e) { - tr.className = ""; - statusElem[textProp] = "Starting: " + this.name; - tdStatus[textProp] = "Running..."; - i = 0; - }).on("cycle", function(e) { - var size = ++i; - statusElem.innerHTML = this.name + " × " + Benchmark.formatNumber(this.count) + " (" + size + " sample" + (size == 1 ? "" : "s") + ")"; - }).on("error", function(e) { - tr.className = "test-error"; - }).on("reset", function(e) { - tdStatus[textProp] = "Ready"; - }).on("complete", function(e) { - if (this.error) { - tdStatus.innerHTML = this.error.message; - return; - } - tdStatus.title = "Ran " + Benchmark.formatNumber(this.count) + " times in " + this.times.cycle.toFixed(3) + " seconds."; - tdStatus.innerHTML = Benchmark.formatNumber(this.hz.toFixed(this.hz < 100 ? 2 : 0)) + " (±" + this.stats.rme.toFixed(2) + "%)"; - }); - }); - - tests.on("complete", function() { - statusElem[textProp] = "All tests completed!"; - }).on("reset", function() { - statusElem[textProp] = "Initializing..."; - }); - - // wrapper function to add a test group - window.Benchmark.test = function(group, testGroup) { - testGroup(function(name, test) { - tests.add.call(tests, group + "." + name, test); - }); - }; -})(this, ___benchmarks); diff --git a/build/qunit.html b/build/qunit.html deleted file mode 100755 index 80d261f..0000000 --- a/build/qunit.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - -

          -
          -

          -
            - - - - - - - - \ No newline at end of file diff --git a/build/qunit/qunit.css b/build/qunit/qunit.css deleted file mode 100755 index a1dd6a8..0000000 --- a/build/qunit/qunit.css +++ /dev/null @@ -1,236 +0,0 @@ -/** - * QUnit v1.7.0pre - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2012 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. - */ - -/** Font Family and Sizes */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; -} - -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } -#qunit-tests { font-size: smaller; } - - -/** Resets */ - -#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { - margin: 0; - padding: 0; -} - - -/** Header */ - -#qunit-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 15px 15px 0 0; - -moz-border-radius: 15px 15px 0 0; - -webkit-border-top-right-radius: 15px; - -webkit-border-top-left-radius: 15px; -} - -#qunit-header a { - text-decoration: none; - color: #c2ccd1; -} - -#qunit-header a:hover, -#qunit-header a:focus { - color: #fff; -} - -#qunit-header label { - display: inline-block; - padding-left: 0.5em; -} - -#qunit-banner { - height: 5px; -} - -#qunit-testrunner-toolbar { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; -} - -#qunit-userAgent { - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - - -/** Tests: Pass/Fail */ - -#qunit-tests { - list-style-position: inside; -} - -#qunit-tests li { - padding: 0.4em 0.5em 0.4em 2.5em; - border-bottom: 1px solid #fff; - list-style-position: inside; -} - -#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { - display: none; -} - -#qunit-tests li strong { - cursor: pointer; -} - -#qunit-tests li a { - padding: 0.5em; - color: #c2ccd1; - text-decoration: none; -} -#qunit-tests li a:hover, -#qunit-tests li a:focus { - color: #000; -} - -#qunit-tests ol { - margin-top: 0.5em; - padding: 0.5em; - - background-color: #fff; - - border-radius: 15px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - - box-shadow: inset 0px 2px 13px #999; - -moz-box-shadow: inset 0px 2px 13px #999; - -webkit-box-shadow: inset 0px 2px 13px #999; -} - -#qunit-tests table { - border-collapse: collapse; - margin-top: .2em; -} - -#qunit-tests th { - text-align: right; - vertical-align: top; - padding: 0 .5em 0 0; -} - -#qunit-tests td { - vertical-align: top; -} - -#qunit-tests pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; -} - -#qunit-tests del { - background-color: #e0f2be; - color: #374e0c; - text-decoration: none; -} - -#qunit-tests ins { - background-color: #ffcaca; - color: #500; - text-decoration: none; -} - -/*** Test Counts */ - -#qunit-tests b.counts { color: black; } -#qunit-tests b.passed { color: #5E740B; } -#qunit-tests b.failed { color: #710909; } - -#qunit-tests li li { - margin: 0.5em; - padding: 0.4em 0.5em 0.4em 0.5em; - background-color: #fff; - border-bottom: none; - list-style-position: inside; -} - -/*** Passing Styles */ - -#qunit-tests li li.pass { - color: #5E740B; - background-color: #fff; - border-left: 26px solid #C6E746; -} - -#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests .pass .test-name { color: #366097; } - -#qunit-tests .pass .test-actual, -#qunit-tests .pass .test-expected { color: #999999; } - -#qunit-banner.qunit-pass { background-color: #C6E746; } - -/*** Failing Styles */ - -#qunit-tests li li.fail { - color: #710909; - background-color: #fff; - border-left: 26px solid #EE5757; - white-space: pre; -} - -#qunit-tests > li:last-child { - border-radius: 0 0 15px 15px; - -moz-border-radius: 0 0 15px 15px; - -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; -} - -#qunit-tests .fail { color: #000000; background-color: #EE5757; } -#qunit-tests .fail .test-name, -#qunit-tests .fail .module-name { color: #000000; } - -#qunit-tests .fail .test-actual { color: #EE5757; } -#qunit-tests .fail .test-expected { color: green; } - -#qunit-banner.qunit-fail { background-color: #EE5757; } - - -/** Result */ - -#qunit-testresult { - padding: 0.5em 0.5em 0.5em 2.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-bottom: 1px solid white; -} -#qunit-testresult .module-name { - font-weight: bold; -} - -/** Fixture */ - -#qunit-fixture { - position: absolute; - top: -10000px; - left: -10000px; - width: 1000px; - height: 1000px; -} diff --git a/build/qunit/qunit.js b/build/qunit/qunit.js deleted file mode 100755 index 1a11027..0000000 --- a/build/qunit/qunit.js +++ /dev/null @@ -1,1803 +0,0 @@ -/** - * QUnit v1.7.0pre - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2012 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. - */ - -(function( window ) { - -var QUnit, - config, - testId = 0, - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch( e ) { - return false; - } - }()) -}; - -function Test( settings ) { - extend( this, settings ); - this.assertions = []; - this.testNumber = ++Test.count; -} - -Test.count = 0; - -Test.prototype = { - init: function() { - var a, b, li, - tests = id( "qunit-tests" ); - - if ( tests ) { - b = document.createElement( "strong" ); - b.innerHTML = this.name; - - // `a` initialized at top of scope - a = document.createElement( "a" ); - a.innerHTML = "Rerun"; - a.href = QUnit.url({ testNumber: this.testNumber }); - - li = document.createElement( "li" ); - li.appendChild( b ); - li.appendChild( a ); - li.className = "running"; - li.id = this.id = "qunit-test-output" + testId++; - - tests.appendChild( li ); - } - }, - setup: function() { - if ( this.module !== config.previousModule ) { - if ( config.previousModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } else if ( config.autorun ) { - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } - - config.current = this; - - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment ); - - runLoggingCallbacks( "testStart", QUnit, { - name: this.testName, - module: this.module - }); - - // allow utility functions to access the current test environment - // TODO why?? - QUnit.current_testEnvironment = this.testEnvironment; - - if ( !config.pollution ) { - saveGlobal(); - } - if ( config.notrycatch ) { - this.testEnvironment.setup.call( this.testEnvironment ); - return; - } - try { - this.testEnvironment.setup.call( this.testEnvironment ); - } catch( e ) { - QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); - } - }, - run: function() { - config.current = this; - - var running = id( "qunit-testresult" ); - - if ( running ) { - running.innerHTML = "Running:
            " + this.name; - } - - if ( this.async ) { - QUnit.stop(); - } - - if ( config.notrycatch ) { - this.callback.call( this.testEnvironment, QUnit.assert ); - return; - } - - try { - this.callback.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - QUnit.start(); - } - } - }, - teardown: function() { - config.current = this; - if ( config.notrycatch ) { - this.testEnvironment.teardown.call( this.testEnvironment ); - return; - } else { - try { - this.testEnvironment.teardown.call( this.testEnvironment ); - } catch( e ) { - QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); - } - } - checkPollution(); - }, - finish: function() { - config.current = this; - if ( this.expected != null && this.expected != this.assertions.length ) { - QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); - } else if ( this.expected == null && !this.assertions.length ) { - QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); - } - - var assertion, a, b, i, li, ol, - test = this, - good = 0, - bad = 0, - tests = id( "qunit-tests" ); - - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - ol = document.createElement( "ol" ); - - for ( i = 0; i < this.assertions.length; i++ ) { - assertion = this.assertions[i]; - - li = document.createElement( "li" ); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - if ( QUnit.config.reorder && defined.sessionStorage ) { - if ( bad ) { - sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); - } else { - sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); - } - } - - if ( bad === 0 ) { - ol.style.display = "none"; - } - - // `b` initialized at top of scope - b = document.createElement( "strong" ); - b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.nextSibling.nextSibling, - display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; - }); - - addEvent(b, "dblclick", function( e ) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ testNumber: test.testNumber }); - } - }); - - // `li` initialized at top of scope - li = id( this.id ); - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - a = li.firstChild; - li.appendChild( b ); - li.appendChild ( a ); - li.appendChild( ol ); - - } else { - for ( i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - runLoggingCallbacks( "testDone", QUnit, { - name: this.testName, - module: this.module, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length - }); - - QUnit.reset(); - }, - - queue: function() { - var bad, - test = this; - - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - - // `bad` initialized at top of scope - // defer when previous test run passed, if storage is available - bad = QUnit.config.reorder && defined.sessionStorage && - +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); - - if ( bad ) { - run(); - } else { - synchronize( run, true ); - } - } -}; - -// Root QUnit object. -// `QUnit` initialized at top of scope -QUnit = { - - // call on start of module test to prepend name to all tests - module: function( name, testEnvironment ) { - config.currentModule = name; - config.currentModuleTestEnviroment = testEnvironment; - }, - - asyncTest: function( testName, expected, callback ) { - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - QUnit.test( testName, expected, callback, true ); - }, - - test: function( testName, expected, callback, async ) { - var test, - name = "" + escapeInnerText( testName ) + ""; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - if ( config.currentModule ) { - name = "" + config.currentModule + ": " + name; - } - - test = new Test({ - name: name, - testName: testName, - expected: expected, - async: async, - callback: callback, - module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnviroment, - stack: sourceFromStacktrace( 2 ) - }); - - if ( !validTest( test ) ) { - return; - } - - test.queue(); - }, - - // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - expect: function( asserts ) { - config.current.expected = asserts; - }, - - start: function( count ) { - config.semaphore -= count || 1; - // don't start until equal number of stop-calls - if ( config.semaphore > 0 ) { - return; - } - // ignore if start is called more often then stop - if ( config.semaphore < 0 ) { - config.semaphore = 0; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - window.setTimeout(function() { - if ( config.semaphore > 0 ) { - return; - } - if ( config.timeout ) { - clearTimeout( config.timeout ); - } - - config.blocking = false; - process( true ); - }, 13); - } else { - config.blocking = false; - process( true ); - } - }, - - stop: function( count ) { - config.semaphore += count || 1; - config.blocking = true; - - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = window.setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - config.semaphore = 1; - QUnit.start(); - }, config.testTimeout ); - } - } -}; - -// Asssert helpers -// All of these must call either QUnit.push() or manually do: -// - runLoggingCallbacks( "log", .. ); -// - config.current.assertions.push({ .. }); -QUnit.assert = { - /** - * Asserts rough true-ish result. - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function( result, msg ) { - if ( !config.current ) { - throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - result = !!result; - - var source, - details = { - result: result, - message: msg - }; - - msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); - msg = "" + msg + ""; - - if ( !result ) { - source = sourceFromStacktrace( 2 ); - if ( source ) { - details.source = source; - msg += "
            Source:
            " + escapeInnerText( source ) + "
            "; - } - } - runLoggingCallbacks( "log", QUnit, details ); - config.current.assertions.push({ - result: result, - message: msg - }); - }, - - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); - */ - equal: function( actual, expected, message ) { - QUnit.push( expected == actual, actual, expected, message ); - }, - - notEqual: function( actual, expected, message ) { - QUnit.push( expected != actual, actual, expected, message ); - }, - - deepEqual: function( actual, expected, message ) { - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - notDeepEqual: function( actual, expected, message ) { - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - strictEqual: function( actual, expected, message ) { - QUnit.push( expected === actual, actual, expected, message ); - }, - - notStrictEqual: function( actual, expected, message ) { - QUnit.push( expected !== actual, actual, expected, message ); - }, - - raises: function( block, expected, message ) { - var actual, - ok = false; - - if ( typeof expected === "string" ) { - message = expected; - expected = null; - } - - try { - block.call( config.current.testEnvironment ); - } catch (e) { - actual = e; - } - - if ( actual ) { - // we don't want to validate thrown error - if ( !expected ) { - ok = true; - // expected is a regexp - } else if ( QUnit.objectType( expected ) === "regexp" ) { - ok = expected.test( actual ); - // expected is a constructor - } else if ( actual instanceof expected ) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if ( expected.call( {}, actual ) === true ) { - ok = true; - } - } - - QUnit.push( ok, actual, null, message ); - } -}; - -// @deprecated: Kept assertion helpers in root for backwards compatibility -extend( QUnit, QUnit.assert ); - -/** - * @deprecated: Kept for backwards compatibility - * next step: remove entirely - */ -QUnit.equals = function() { - QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); -}; -QUnit.same = function() { - QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); -}; - -// We want access to the constructor's prototype -(function() { - function F() {} - F.prototype = QUnit; - QUnit = new F(); - // Make F QUnit's constructor so that we can add to the prototype later - QUnit.constructor = F; -}()); - -/** - * Config object: Maintain internal state - * Later exposed as QUnit.config - * `config` initialized at top of scope - */ -config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true, - - // when enabled, show only failing tests - // gets persisted through sessionStorage and can be changed in UI via checkbox - hidepassed: false, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - // by default, modify document.title when suite is done - altertitle: true, - - urlConfig: [ "noglobals", "notrycatch" ], - - // logging callback queues - begin: [], - done: [], - log: [], - testStart: [], - testDone: [], - moduleStart: [], - moduleDone: [] -}; - -// Initialize more QUnit.config and QUnit.urlParams -(function() { - var i, - location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}, - current; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - urlParams[ current[ 0 ] ] = current[ 1 ]; - } - } - - QUnit.urlParams = urlParams; - config.filter = urlParams.filter; - config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = location.protocol === "file:"; -}()); - -// Export global variables, unless an 'exports' object exists, -// in that case we assume we're in CommonJS (dealt with on the bottom of the script) -if ( typeof exports === "undefined" ) { - extend( window, QUnit ); - - // Expose QUnit object - window.QUnit = QUnit; -} - -// Extend QUnit object, -// these after set here because they should not be exposed as global functions -extend( QUnit, { - config: config, - - // Initialize the configuration options - init: function() { - extend( config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date(), - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filter: "", - queue: [], - semaphore: 0 - }); - - var tests, banner, result, - qunit = id( "qunit" ); - - if ( qunit ) { - qunit.innerHTML = - "

            " + escapeInnerText( document.title ) + "

            " + - "

            " + - "
            " + - "

            " + - "
              "; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...
               "; - } - }, - - // Resets the test setup. Useful for tests that modify the DOM. - // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. - reset: function() { - var fixture; - - if ( window.jQuery ) { - jQuery( "#qunit-fixture" ).html( config.fixture ); - } else { - fixture = id( "qunit-fixture" ); - if ( fixture ) { - fixture.innerHTML = config.fixture; - } - } - }, - - // Trigger an event on an element. - // @example triggerEvent( document.body, "click" ); - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent( "MouseEvents" ); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - - elem.dispatchEvent( event ); - } else if ( elem.fireEvent ) { - elem.fireEvent( "on" + type ); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) == type; - }, - - objectType: function( obj ) { - if ( typeof obj === "undefined" ) { - return "undefined"; - // consider: typeof null === object - } - if ( obj === null ) { - return "null"; - } - - var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; - - switch ( type ) { - case "Number": - if ( isNaN(obj) ) { - return "nan"; - } - return "number"; - case "String": - case "Boolean": - case "Array": - case "Date": - case "RegExp": - case "Function": - return type.toLowerCase(); - } - if ( typeof obj === "object" ) { - return "object"; - } - return undefined; - }, - - push: function( result, actual, expected, message ) { - if ( !config.current ) { - throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); - } - - var output, source, - details = { - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); - message = "" + message + ""; - output = message; - - if ( !result ) { - expected = escapeInnerText( QUnit.jsDump.parse(expected) ); - actual = escapeInnerText( QUnit.jsDump.parse(actual) ); - output += ""; - - if ( actual != expected ) { - output += ""; - output += ""; - } - - source = sourceFromStacktrace(); - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
              Expected:
              " + expected + "
              Result:
              " + actual + "
              Diff:
              " + QUnit.diff( expected, actual ) + "
              Source:
              " + escapeInnerText( source ) + "
              "; - } - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - pushFailure: function( message, source ) { - var output, - details = { - result: false, - message: message - }; - - message = escapeInnerText(message ) || "error"; - message = "" + message + ""; - output = message; - - if ( source ) { - details.source = source; - output += "
              Source:
              " + escapeInnerText( source ) + "
              "; - } - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: false, - message: output - }); - }, - - url: function( params ) { - params = extend( extend( {}, QUnit.urlParams ), params ); - var key, - querystring = "?"; - - for ( key in params ) { - if ( !hasOwn.call( params, key ) ) { - continue; - } - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; - } - return window.location.pathname + querystring.slice( 0, -1 ); - }, - - extend: extend, - id: id, - addEvent: addEvent - // load, equiv, jsDump, diff: Attached later -}); - -/** - * @deprecated: Created for backwards compatibility with test runner that set the hook function - * into QUnit.{hook}, instead of invoking it and passing the hook function. - * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. - * Doing this allows us to tell if the following methods have been overwritten on the actual - * QUnit object. - */ -extend( QUnit.constructor.prototype, { - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: registerLoggingCallback( "begin" ), - - // done: { failed, passed, total, runtime } - done: registerLoggingCallback( "done" ), - - // log: { result, actual, expected, message } - log: registerLoggingCallback( "log" ), - - // testStart: { name } - testStart: registerLoggingCallback( "testStart" ), - - // testDone: { name, failed, passed, total } - testDone: registerLoggingCallback( "testDone" ), - - // moduleStart: { name } - moduleStart: registerLoggingCallback( "moduleStart" ), - - // moduleDone: { name, failed, passed, total } - moduleDone: registerLoggingCallback( "moduleDone" ) -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -QUnit.load = function() { - runLoggingCallbacks( "begin", QUnit, {} ); - - // Initialize the config, saving the execution queue - var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, - urlConfigHtml = "", - oldconfig = extend( {}, config ); - - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - len = config.urlConfig.length; - - for ( i = 0; i < len; i++ ) { - val = config.urlConfig[i]; - config[val] = QUnit.urlParams[val]; - urlConfigHtml += ""; - } - - // `userAgent` initialized at top of scope - userAgent = id( "qunit-userAgent" ); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - - // `banner` initialized at top of scope - banner = id( "qunit-header" ); - if ( banner ) { - banner.innerHTML = "" + banner.innerHTML + " " + urlConfigHtml; - addEvent( banner, "change", function( event ) { - var params = {}; - params[ event.target.name ] = event.target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); - } - - // `toolbar` initialized at top of scope - toolbar = id( "qunit-testrunner-toolbar" ); - if ( toolbar ) { - // `filter` initialized at top of scope - filter = document.createElement( "input" ); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - - addEvent( filter, "click", function() { - var tmp, - ol = document.getElementById( "qunit-tests" ); - - if ( filter.checked ) { - ol.className = ol.className + " hidepass"; - } else { - tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; - ol.className = tmp.replace( / hidepass /, " " ); - } - if ( defined.sessionStorage ) { - if (filter.checked) { - sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); - } else { - sessionStorage.removeItem( "qunit-filter-passed-tests" ); - } - } - }); - - if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { - filter.checked = true; - // `ol` initialized at top of scope - ol = document.getElementById( "qunit-tests" ); - ol.className = ol.className + " hidepass"; - } - toolbar.appendChild( filter ); - - // `label` initialized at top of scope - label = document.createElement( "label" ); - label.setAttribute( "for", "qunit-filter-pass" ); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - } - - // `main` initialized at top of scope - main = id( "qunit-fixture" ); - if ( main ) { - config.fixture = main.innerHTML; - } - - if ( config.autostart ) { - QUnit.start(); - } -}; - -addEvent( window, "load", QUnit.load ); - -// addEvent(window, "error" ) gives us a useless event object -window.onerror = function( message, file, line ) { - if ( QUnit.config.current ) { - QUnit.pushFailure( message, file + ":" + line ); - } else { - QUnit.test( "global failure", function() { - QUnit.pushFailure( message, file + ":" + line ); - }); - } -}; - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - - var i, key, - banner = id( "qunit-banner" ), - tests = id( "qunit-tests" ), - runtime = +new Date() - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - "Tests completed in ", - runtime, - " milliseconds.
              ", - "", - passed, - " tests of ", - config.stats.all, - " passed, ", - config.stats.bad, - " failed." - ].join( "" ); - - if ( banner ) { - banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( config.altertitle && typeof document !== "undefined" && document.title ) { - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = [ - ( config.stats.bad ? "\u2716" : "\u2714" ), - document.title.replace( /^[\u2714\u2716] /i, "" ) - ].join( " " ); - } - - // clear own sessionStorage items if all tests passed - if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { - // `key` & `i` initialized at top of scope - for ( i = 0; i < sessionStorage.length; i++ ) { - key = sessionStorage.key( i++ ); - if ( key.indexOf( "qunit-test-" ) === 0 ) { - sessionStorage.removeItem( key ); - } - } - } - - runLoggingCallbacks( "done", QUnit, { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - }); -} - -function validTest( test ) { - var include, - filter = (config.filter || "").toLowerCase(), - fullName = (test.module + ": " + test.testName).toLowerCase(); - - if ( config.testNumber ) { - return test.testNumber === config.testNumber; - } - - if ( !filter ) { - return true; - } - - include = filter.charAt( 0 ) !== "!"; - if ( !include ) { - filter = filter.slice( 1 ); - } - - // If the filter matches, we need to honour include - if ( fullName.indexOf( filter ) !== -1 ) { - return include; - } - - // Otherwise, do the opposite - return !include; -} - -// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) -// Later Safari and IE10 are supposed to support error.stack as well -// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack -function extractStacktrace( e, offset ) { - offset = offset || 3; - - var stack; - - if ( e.stacktrace ) { - // Opera - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { - // Firefox, Chrome - stack = e.stack.split( "\n" ); - if (/^error$/i.test( stack[0] ) ) { - stack.shift(); - } - return stack[ offset ]; - } else if ( e.sourceURL ) { - // Safari, PhantomJS - // hopefully one day Safari provides actual stacktraces - // exclude useless self-reference for generated Error objects - if ( /qunit.js$/.test( e.sourceURL ) ) { - return; - } - // for actual exceptions, this is useful - return e.sourceURL + ":" + e.line; - } -} -function sourceFromStacktrace( offset ) { - try { - throw new Error(); - } catch ( e ) { - return extractStacktrace( e, offset ); - } -} - -function escapeInnerText( s ) { - if ( !s ) { - return ""; - } - s = s + ""; - return s.replace( /[\&<>]/g, function( s ) { - switch( s ) { - case "&": return "&"; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); -} - -function synchronize( callback, last ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process( last ); - } -} - -function process( last ) { - function next() { - process( last ); - } - var start = new Date().getTime(); - config.depth = config.depth ? config.depth + 1 : 1; - - while ( config.queue.length && !config.blocking ) { - if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { - config.queue.shift()(); - } else { - window.setTimeout( next, 13 ); - break; - } - } - config.depth--; - if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { - continue; - } - config.pollution.push( key ); - } - } -} - -function checkPollution( name ) { - var newGlobals, - deletedGlobals, - old = config.pollution; - - saveGlobal(); - - newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); - } - - deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var i, j, - result = a.slice(); - - for ( i = 0; i < result.length; i++ ) { - for ( j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice( i, 1 ); - i--; - break; - } - } - } - return result; -} - -function extend( a, b ) { - for ( var prop in b ) { - if ( b[ prop ] === undefined ) { - delete a[ prop ]; - - // Avoid "Member not found" error in IE8 caused by setting window.constructor - } else if ( prop !== "constructor" || a !== window ) { - a[ prop ] = b[ prop ]; - } - } - - return a; -} - -function addEvent( elem, type, fn ) { - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, fn ); - } else { - fn(); - } -} - -function id( name ) { - return !!( typeof document !== "undefined" && document && document.getElementById ) && - document.getElementById( name ); -} - -function registerLoggingCallback( key ) { - return function( callback ) { - config[key].push( callback ); - }; -} - -// Supports deprecated method of completely overwriting logging callbacks -function runLoggingCallbacks( key, scope, args ) { - //debugger; - var i, callbacks; - if ( QUnit.hasOwnProperty( key ) ) { - QUnit[ key ].call(scope, args ); - } else { - callbacks = config[ key ]; - for ( i = 0; i < callbacks.length; i++ ) { - callbacks[ i ].call( scope, args ); - } - } -} - -// Test for equality any JavaScript type. -// Author: Philippe Rathé -QUnit.equiv = (function() { - - // Call the o related callback with the given arguments. - function bindCallbacks( o, callbacks, args ) { - var prop = QUnit.objectType( o ); - if ( prop ) { - if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { - return callbacks[ prop ].apply( callbacks, args ); - } else { - return callbacks[ prop ]; // or undefined - } - } - } - - // the real equiv function - var innerEquiv, - // stack to decide between skip/abort functions - callers = [], - // stack to avoiding loops from circular referencing - parents = [], - - getProto = Object.getPrototypeOf || function ( obj ) { - return obj.__proto__; - }, - callbacks = (function () { - - // for string, boolean, number and null - function useStrictEquality( b, a ) { - if ( b instanceof a.constructor || a instanceof b.constructor ) { - // to catch short annotaion VS 'new' annotation of a - // declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function( b ) { - return isNaN( b ); - }, - - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && - // the regex itself - a.source === b.source && - // and its modifers - a.global === b.global && - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function() { - var caller = callers[callers.length - 1]; - return caller !== Object && typeof caller !== "undefined"; - }, - - "array": function( b, a ) { - var i, j, len, loop; - - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } - - len = a.length; - if ( len !== b.length ) { - // safe and faster - return false; - } - - // track reference to avoid circular references - parents.push( a ); - for ( i = 0; i < len; i++ ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - if ( parents[j] === a[i] ) { - loop = true;// dont rewalk array - } - } - if ( !loop && !innerEquiv(a[i], b[i]) ) { - parents.pop(); - return false; - } - } - parents.pop(); - return true; - }, - - "object": function( b, a ) { - var i, j, loop, - // Default to true - eq = true, - aProperties = [], - bProperties = []; - - // comparing constructors is more strict than using - // instanceof - if ( a.constructor !== b.constructor ) { - // Allow objects with no prototype to be equivalent to - // objects with Object as their constructor. - if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || - ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { - return false; - } - } - - // stack constructor before traversing properties - callers.push( a.constructor ); - // track reference to avoid circular references - parents.push( a ); - - for ( i in a ) { // be strict: don't ensures hasOwnProperty - // and go deep - loop = false; - for ( j = 0; j < parents.length; j++ ) { - if ( parents[j] === a[i] ) { - // don't go down the same path twice - loop = true; - } - } - aProperties.push(i); // collect a's properties - - if (!loop && !innerEquiv( a[i], b[i] ) ) { - eq = false; - break; - } - } - - callers.pop(); // unstack, we are done - parents.pop(); - - for ( i in b ) { - bProperties.push( i ); // collect b's properties - } - - // Ensures identical properties name - return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); - } - }; - }()); - - innerEquiv = function() { // can take multiple arguments - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { - return true; // end transition - } - - return (function( a, b ) { - if ( a === b ) { - return true; // catch the most you can - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType(a) !== QUnit.objectType(b) ) { - return false; // don't lose time with error prone cases - } else { - return bindCallbacks(a, callbacks, [ b, a ]); - } - - // apply transition with (1..n) arguments - }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); - }; - - return innerEquiv; -}()); - -/** - * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | - * http://flesler.blogspot.com Licensed under BSD - * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 - * - * @projectDescription Advanced and extensible data dumping for Javascript. - * @version 1.0.0 - * @author Ariel Flesler - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} - */ -QUnit.jsDump = (function() { - function quote( str ) { - return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; - } - function literal( o ) { - return o + ""; - } - function join( pre, arr, post ) { - var s = jsDump.separator(), - base = jsDump.indent(), - inner = jsDump.indent(1); - if ( arr.join ) { - arr = arr.join( "," + s + inner ); - } - if ( !arr ) { - return pre + post; - } - return [ pre, inner + arr, base + post ].join(s); - } - function array( arr, stack ) { - var i = arr.length, ret = new Array(i); - this.up(); - while ( i-- ) { - ret[i] = this.parse( arr[i] , undefined , stack); - } - this.down(); - return join( "[", ret, "]" ); - } - - var reName = /^function (\w+)/, - jsDump = { - parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance - stack = stack || [ ]; - var inStack, res, - parser = this.parsers[ type || this.typeOf(obj) ]; - - type = typeof parser; - inStack = inArray( obj, stack ); - - if ( inStack != -1 ) { - return "recursion(" + (inStack - stack.length) + ")"; - } - //else - if ( type == "function" ) { - stack.push( obj ); - res = parser.call( this, obj, stack ); - stack.pop(); - return res; - } - // else - return ( type == "string" ) ? parser : this.parsers.error; - }, - typeOf: function( obj ) { - var type; - if ( obj === null ) { - type = "null"; - } else if ( typeof obj === "undefined" ) { - type = "undefined"; - } else if ( QUnit.is( "regexp", obj) ) { - type = "regexp"; - } else if ( QUnit.is( "date", obj) ) { - type = "date"; - } else if ( QUnit.is( "function", obj) ) { - type = "function"; - } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { - type = "window"; - } else if ( obj.nodeType === 9 ) { - type = "document"; - } else if ( obj.nodeType ) { - type = "node"; - } else if ( - // native arrays - toString.call( obj ) === "[object Array]" || - // NodeList objects - ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) - ) { - type = "array"; - } else { - type = typeof obj; - } - return type; - }, - separator: function() { - return this.multiline ? this.HTML ? "
              " : "\n" : this.HTML ? " " : " "; - }, - indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing - if ( !this.multiline ) { - return ""; - } - var chr = this.indentChar; - if ( this.HTML ) { - chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); - } - return new Array( this._depth_ + (extra||0) ).join(chr); - }, - up: function( a ) { - this._depth_ += a || 1; - }, - down: function( a ) { - this._depth_ -= a || 1; - }, - setParser: function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote: quote, - literal: literal, - join: join, - // - _depth_: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers: { - window: "[Window]", - document: "[Document]", - error: "[ERROR]", //when no parser is found, shouldn"t happen - unknown: "[Unknown]", - "null": "null", - "undefined": "undefined", - "function": function( fn ) { - var ret = "function", - name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE - - if ( name ) { - ret += " " + name; - } - ret += "( "; - - ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); - return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); - }, - array: array, - nodelist: array, - "arguments": array, - object: function( map, stack ) { - var ret = [ ], keys, key, val, i; - QUnit.jsDump.up(); - if ( Object.keys ) { - keys = Object.keys( map ); - } else { - keys = []; - for ( key in map ) { - keys.push( key ); - } - } - keys.sort(); - for ( i = 0; i < keys.length; i++ ) { - key = keys[ i ]; - val = map[ key ]; - ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); - } - QUnit.jsDump.down(); - return join( "{", ret, "}" ); - }, - node: function( node ) { - var a, val, - open = QUnit.jsDump.HTML ? "<" : "<", - close = QUnit.jsDump.HTML ? ">" : ">", - tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for ( a in QUnit.jsDump.DOMAttrs ) { - val = node[ QUnit.jsDump.DOMAttrs[a] ]; - if ( val ) { - ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); - } - } - return ret + close + open + "/" + tag + close; - }, - functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function - var args, - l = fn.length; - - if ( !l ) { - return ""; - } - - args = new Array(l); - while ( l-- ) { - args[l] = String.fromCharCode(97+l);//97 is 'a' - } - return " " + args.join( ", " ) + " "; - }, - key: quote, //object calls it internally, the key part of an item in a map - functionCode: "[code]", //function calls it internally, it's the content of the function - attribute: quote, //node calls it internally, it's an html attribute value - string: quote, - date: quote, - regexp: literal, //regex - number: literal, - "boolean": literal - }, - DOMAttrs: { - //attributes to dump from nodes, name=>realName - id: "id", - name: "name", - "class": "className" - }, - HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar: " ",//indentation unit - multiline: true //if true, items in a collection, are separated by a \n, else just a space. - }; - - return jsDump; -}()); - -// from Sizzle.js -function getText( elems ) { - var i, elem, - ret = ""; - - for ( i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -} - -// from jquery.js -function inArray( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; -} - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - function diff( o, n ) { - var i, - ns = {}, - os = {}; - - for ( i = 0; i < n.length; i++ ) { - if ( ns[ n[i] ] == null ) { - ns[ n[i] ] = { - rows: [], - o: null - }; - } - ns[ n[i] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( os[ o[i] ] == null ) { - os[ o[i] ] = { - rows: [], - n: null - }; - } - os[ o[i] ].rows.push( i ); - } - - for ( i in ns ) { - if ( !hasOwn.call( ns, i ) ) { - continue; - } - if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { - n[ ns[i].rows[0] ] = { - text: n[ ns[i].rows[0] ], - row: os[i].rows[0] - }; - o[ os[i].rows[0] ] = { - text: o[ os[i].rows[0] ], - row: ns[i].rows[0] - }; - } - } - - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && - n[ i + 1 ] == o[ n[i].row + 1 ] ) { - - n[ i + 1 ] = { - text: n[ i + 1 ], - row: n[i].row + 1 - }; - o[ n[i].row + 1 ] = { - text: o[ n[i].row + 1 ], - row: i + 1 - }; - } - } - - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && - n[ i - 1 ] == o[ n[i].row - 1 ]) { - - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[i].row - 1 - }; - o[ n[i].row - 1 ] = { - text: o[ n[i].row - 1 ], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); - - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), - oSpace = o.match(/\s+/g), - nSpace = n.match(/\s+/g); - - if ( oSpace == null ) { - oSpace = [ " " ]; - } - else { - oSpace.push( " " ); - } - - if ( nSpace == null ) { - nSpace = [ " " ]; - } - else { - nSpace.push( " " ); - } - - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[i] + oSpace[i] + ""; - } - } - else { - if ( out.n[0].text == null ) { - for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { - str += "" + out.o[n] + oSpace[n] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if (out.n[i].text == null) { - str += "" + out.n[i] + nSpace[i] + ""; - } - else { - // `pre` initialized at top of scope - pre = ""; - - for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { - pre += "" + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -}()); - -// for CommonJS enviroments, export everything -if ( typeof exports !== "undefined" ) { - extend(exports, QUnit); -} - -// get at whatever the global object is, like window in browsers -}( (function() {return this;}.call(window)) )); diff --git a/build/vendor/browserstack/browserstack.js b/build/vendor/browserstack/browserstack.js deleted file mode 100755 index 61212f4..0000000 --- a/build/vendor/browserstack/browserstack.js +++ /dev/null @@ -1,272 +0,0 @@ -var http = require( "http" ), - querystring = require( "querystring" ), - util = require( "util" ), - userAgent = getUA(); - -function getUA() { - var os = require( "os" ), - version = "0.1.0"; - return os.platform() + "/" + os.release() + " " + - "node/" + process.versions.node + " " + - "node-browserstack/" + version; -} - -function extend( a, b ) { - for ( var p in b ) { - a[ p ] = b[ p ]; - } - - return a; -} - -function Client( settings ) { - if ( !settings.username ) { - throw new Error( "Username is required." ); - } - if ( !settings.password ) { - throw new Error( "Password is required." ); - } - - extend( this, settings ); - this.authHeader = "Basic " + - new Buffer( this.username + ":" + this.password ).toString( "base64" ); -} - - - -// public API -extend( Client.prototype, { - getBrowsers: function( fn ) { - this._getBrowsers( function( error, browsers ) { - if ( !error ) { - this.updateLatest( browsers ); - } - - fn( error, browsers ); - }.bind( this ) ); - }, - - createWorker: function( options, fn ) { - if ( options.version === "latest" ) { - return this.getLatest( options, function( error, version ) { - if ( error ) { - return fn( error ); - } - - options = extend( {}, options ); - options.version = version; - this.createWorker( options, fn ); - }.bind( this ) ); - } - - var data = querystring.stringify( options ); - this.request({ - path: this.path( "/worker" ), - method: "POST" - }, data, fn ); - }, - - getWorker: function( id, fn ) { - this.request({ - path: this.path( "/worker/" + id ) - }, fn ); - }, - - terminateWorker: function( id, fn ) { - this.request({ - path: this.path( "/worker/" + id ), - method: "DELETE" - }, fn ); - }, - - getWorkers: function( fn ) { - this.request({ - path: this.path( "/workers" ) - }, fn ); - }, - - getLatest: function( browser, fn ) { - var latest = this.latest, - browserId = this.getBrowserId( browser ); - - if ( typeof browser === "function" ) { - fn = browser; - browser = null; - } - - // there may be a lot of createWorker() calls with "latest" version - // so minimize the number of calls to getBrowsers() - if ( this.latestPending ) { - return setTimeout(function() { - this.getLatest( browser, fn ); - }.bind( this ), 50 ); - } - - // only cache browsers for one day - if ( !latest || this.latestUpdate < (new Date() - 864e5) ) { - this.latestPending = true; - return this.getBrowsers(function( error ) { - this.latestPending = false; - - if ( error ) { - return fn( error ); - } - - this.getLatest( browser, fn ); - }.bind( this ) ); - } - - process.nextTick(function() { - fn( null, browser ? latest[ browserId ] : extend( {}, latest ) ); - }); - } -}); - - - -// internal API -extend( Client.prototype, { - latest: null, - latestUpdate: 0, - latestPending: false, - - path: function( path ) { - return "/" + this.version + path; - }, - - request: function( options, data, fn ) { - if ( typeof data === "function" ) { - fn = data; - data = null; - } - fn = fn || function() {}; - - var req = http.request( extend({ - host: "api.browserstack.com", - port: 80, - method: "GET", - headers: { - authorization: this.authHeader, - "user-agent": userAgent, - "content-length": typeof data === "string" ? data.length : 0 - } - }, options ), function( res ) { - var response = ""; - res.setEncoding( "utf8" ); - res.on( "data", function( chunk ) { - response += chunk; - }); - res.on( "end", function() { - if ( res.statusCode !== 200 ) { - var message; - if ( res.headers[ "content-type" ].indexOf( "json" ) !== -1 ) { - message = JSON.parse( response ).message; - } else { - message = response; - } - if ( !message && res.statusCode === 403 ) { - message = "Forbidden"; - } - fn( new Error( message ) ); - } else { - fn( null, JSON.parse( response ) ); - } - }); - }); - - if ( data ) { - req.write( data ); - } - req.end(); - }, - - updateLatest: function( browsers ) { - var latest = this.latest = {}, - getBrowserId = this.getBrowserId; - - this.latestUpdate = new Date(); - browsers.forEach(function( browser ) { - var version = browser.version, - browserId = getBrowserId( browser ); - - // ignore pre-release versions - if ( /\s/.test( version ) ) { - return; - } - - if ( parseFloat( version ) > - (parseFloat( latest[ browserId ] ) || 0) ) { - latest[ browserId ] = version; - } - }); - } -}); - - - -// Versions - -Client.versions = {}; -Client.latestVersion = 0; -Client.createVersion = function( version, prototype ) { - function Version( settings ) { - Client.call( this, settings ); - } - util.inherits( Version, Client ); - - Version.prototype.version = version; - extend( Version.prototype, prototype ); - - Client.versions[ version ] = Version; - Client.latestVersion = Math.max( Client.latestVersion, version ); -}; - -Client.createVersion( 1, { - _getBrowsers: function( fn ) { - this.request({ - path: this.path( "/browsers" ) - }, fn ); - }, - - getBrowserId: function( browser ) { - return browser.browser; - } -}); - -Client.createVersion( 2, { - _getBrowsers: function( fn ) { - this.request({ - path: this.path( "/browsers" ) - }, function( error, osBrowsers ) { - if ( error ) { - return fn( error ); - } - - fn( null, [].concat.apply( [], - Object.keys( osBrowsers ).map(function( os ) { - return osBrowsers[ os ].map(function( browser ) { - browser.os = os; - return browser; - }); - }) - )); - }); - }, - - getBrowserId: function( browser ) { - return browser.os + ":" + (browser.browser || browser.device); - } -}); - - - -module.exports = { - createClient: function( settings ) { - var Version = Client.versions[ settings.version || Client.latestVersion ]; - if ( !Version ) { - throw new Error( "Invalid version" ); - } - - return new Version( settings ); - } -}; \ No newline at end of file diff --git a/build/vendor/classify/classify-array.min.js b/build/vendor/classify/classify-array.min.js deleted file mode 100755 index a0a29dd..0000000 --- a/build/vendor/classify/classify-array.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Classify JavaScript Array Extension Class v0.1.0 - * http://www.closedinterval.com/ - * - * Copyright 2012, Wei Kin Huang - * Classify-Array is freely distributable under the MIT license. - * - * Date: Fri, 01 Jun 2012 20:17:10 GMT - */;(function(a,b){"use strict";var c=function(a){var b=Array.prototype,c,d,e,f,g;e=b.indexOf?function(a,c){return b.indexOf.call(a,c)}:function(a,b){var c=0,d=a.length;while(c0)this.push(b);return this},range:function(a,b,c){arguments.length<=1&&(b=a||0,a=0),c=c||1;var d=Math.max(Math.ceil((b-a)/c),0),e=0;this.clear();while(e++-1})},asyncEach:function(a,b,c,d){var e,f,g=!1,h=this.toArray(),i=this,j=0,k=function(){e=+(new Date);do if(a.call(c||null,h.shift(),j++,i)===!1){g=!0;break}while(!g&&h.length>0&&+(new Date)-e<50);!g&&h.length>0?f=setTimeout(k,d||25):b&&b.call(c||null,i)};return i.length===0?b&&b.call(c||null,i):f=setTimeout(k,d||25),this},every:b.every||function(a,b){var c=0,d=this.length;while(c=0)b=a.call(null,b,this[d],d,this),d--;return b},serialEach:function(a,b,c){var d=this,e=this.toArray(),f=0,g=function(){if(e.length===0){b&&b.call(c||null,d);return}a.call(c||null,g,e.shift(),f++,d)};return g(),this},threadEach:function(a,b,c){var d=this,e=this.length,f=!1,g=function(){--e===0&&!f&&(f=!0,b&&b.call(c||null,d))};return d.length===0?(b&&b.call(c||null,d),this):this.asyncEach(function(d,e,h){if(a.call(c||null,g,d,e,h)===!1)return f=!0,b&&b.call(c||null,h),!1},null,c,1)},unique:function(a,b){var c=this,d=b?c.map(b):c,f=[];return d.reduce(function(b,d,g){if(a?b[b.length-1]!==d||!b.length:e(b,d)===-1)b.push(d),f.push(c[g]);return b},[]),this.getNewObject(f)}})};if(typeof Classify=="undefined"&&typeof module!="undefined"&&module.exports){module.exports=c;return}c(Classify)})(this); \ No newline at end of file diff --git a/build/vendor/classify/classify.min.js b/build/vendor/classify/classify.min.js deleted file mode 100755 index 8406492..0000000 --- a/build/vendor/classify/classify.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Classify JavaScript Library v0.9.7 - * http://www.closedinterval.com/ - * - * Copyright 2011-2012, Wei Kin Huang - * Classify is freely distributable under the MIT license. - * - * Date: Fri, 01 Jun 2012 20:06:51 GMT - */;(function(a,b){"use strict";var c="prototype",d=!{toString:1}.propertyIsEnumerable("toString"),e=d?"hasOwnProperty,valueOf,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,constructor".split(","):[],f=e.length,g=Object[c],h=g.toString,i=g.hasOwnProperty,j=function(a){return typeof a=="function"},k=function(a){return a&&a[c]&&h.call(a)==="[object Function]"},l=Array.isArray||function(a){return h.call(a)==="[object Array]"},m=function(a){var b=[],c;for(c in a)b.push(c);if(d)for(c=0;c-1&&B[c].splice(d,1)}}),w[a]=null;try{delete w[a]}catch(c){}},H=function(a,b,d,e){if(e===g[d])return;var f=!1;r(y,function(c){if(c.propTest.test(d))return d===c.propPrefix?r(e,function(d,e){c.onPropAdd.call(c,a,b,e,d)}):c.onPropAdd.call(c,a,b,d.replace(c.propTest,""),e),f=!0,!1});if(f)return;var h=b[c][d],i=a[c];i[d]=j(e)&&!e.__isclass_&&j(h)?E(h,e):e,j(e)&&r(a.subclass,function(a){j(a[c][d])&&!a[c][d].__original_&&(a[c][d]=E(i[d],a[c][d]))})},I=function(a,b){var d=!1;r(z,function(c){if(c.propTest.test(b))return c.onPropRemove.call(c,a,b.replace(c.propTest,"")),d=!0,!1});if(d)return;if(!j(a[c][b])){a[c][b]=null;try{delete a[c][b]}catch(e){}return}r(a.subclass,function(a){a[c][b]&&j(a[c][b])&&j(a[c][b].__original_)&&(a[c][b]=a[c][b].__original_)}),a[c][b]=null;try{delete a[c][b]}catch(e){}},J=function(){var a=D,d={},e=[],f=arguments,g=f.length;g===1?d=f[0]:g===2?(!f[0].__isclass_&&!k(f[0])?e=n(f[0]):a=f[0],d=f[1]):(a=f[0],e=n(f[1]),d=f[2]),!a.__isclass_&&!d.init&&(d.init=a);var h=function(){var a,c,d;if(!this||!this.init||!(this instanceof h))return h.invoke.apply(h,arguments);for(c=0,d=A.length;c-1&&!a[c].hasOwnProperty(b)&&a.removeBoundProperty(b)}),I(a,b)},onInit:function(a,b){var d=b.bindings||null;if(d===null||d.length===0)return;r(d,function(d){a[d]=function(){return b[c][d].apply(a,arguments)}})}});var K=J({init:function(a,b,c){if(!a)throw Error("Cannot create Observer without class context.");this.context=a,this.name=b,this.events=[],this.writable=!0,this.delay=0,this._debounce=null,c!==null&&typeof c=="object"?(this.getter=j(c.get)?c.get:null,this.setter=j(c.set)?c.set:null,this.value=c.value,this.writable=typeof c.writable=="boolean"?c.writable:!0,this.delay=typeof c.delay=="number"?c.delay:0):this.value=c},get:function(){return this.getter?this.getter.call(this.context,this.value):this.value},set:function(a){var b=this.value;return this.writable?(this.value=this.setter?this.setter.call(this.context,a,b):a,this.value!==b&&this.emit(),this.context):this.context},emit:function(){var b=this;return this.delay>0?(this._debounce!==null&&a.clearTimeout(this._debounce),this._debounce=a.setTimeout(function(){this._debounce=null,b.triggerEmit()},this.delay)):this.triggerEmit(),this.context},triggerEmit:function(){var a=0,b=this.events.length;for(;a'; - } - - while (stream1.length || stream2.length) { - var current = selectStream().splice(0, 1)[0]; - result += escape(value.substr(processed, current.offset - processed)); - processed = current.offset; - if ( current.event == 'start') { - result += open(current.node); - nodeStack.push(current.node); - } else if (current.event == 'stop') { - var node, i = nodeStack.length; - do { - i--; - node = nodeStack[i]; - result += (''); - } while (node != current.node); - nodeStack.splice(i, 1); - while (i < nodeStack.length) { - result += open(nodeStack[i]); - i++; - } - } - } - return result + escape(value.substr(processed)); - } - - /* Initialization */ - - function compileModes() { - - function compileMode(mode, language, is_default) { - if (mode.compiled) { - return; - } - - var keywords = []; // used later with beginWithKeyword but filled as a side-effect of keywords compilation - if (mode.keywords) { - var compiled_keywords = {}; - - function flatten(className, str) { - var group = str.split(' '); - for (var i = 0; i < group.length; i++) { - var pair = group[i].split('|'); - compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; - keywords.push(pair[0]); - } - } - - mode.lexemsRe = langRe(language, mode.lexems || hljs.IDENT_RE, true); - if (typeof mode.keywords == 'string') { // string - flatten('keyword', mode.keywords) - } else { - for (var className in mode.keywords) { - if (!mode.keywords.hasOwnProperty(className)) { - continue; - } - flatten(className, mode.keywords[className]); - } - } - mode.keywords = compiled_keywords; - } - if (!is_default) { - if (mode.beginWithKeyword) { - mode.begin = '\\b(' + keywords.join('|') + ')\\s'; - } - mode.beginRe = langRe(language, mode.begin ? mode.begin : '\\B|\\b'); - if (!mode.end && !mode.endsWithParent){mode.end = '\\B|\\b';} - if (mode.end){mode.endRe = langRe(language, mode.end);} - } - if (mode.illegal){mode.illegalRe = langRe(language, mode.illegal);} - if (mode.relevance === undefined){mode.relevance = 1;} - if (!mode.contains) { - mode.contains = []; - } - // compiled flag is set before compiling submodes to avoid self-recursion - // (see lisp where quoted_list contains quoted_list) - mode.compiled = true; - for (var i = 0; i < mode.contains.length; i++) { - if (mode.contains[i] == 'self') { - mode.contains[i] = mode; - } - compileMode(mode.contains[i], language, false); - } - if (mode.starts) { - compileMode(mode.starts, language, false); - } - } - - for (var i in languages) { - if (!languages.hasOwnProperty(i)) { - continue; - } - compileMode(languages[i].defaultMode, languages[i], true); - } - } - - /* - Core highlighting function. Accepts a language name and a string with the - code to highlight. Returns an object with the following properties: - - - relevance (int) - - keyword_count (int) - - value (an HTML string with highlighting markup) - - */ - function highlight(language_name, value) { - if (!compileModes.called) { - compileModes(); - compileModes.called = true; - } - - function subMode(lexem, mode) { - for (var i = 0; i < mode.contains.length; i++) { - var match = mode.contains[i].beginRe.exec(lexem); - if (match && match.index == 0) { - return mode.contains[i]; - } - } - } - - function endOfMode(mode_index, lexem) { - if (modes[mode_index].end && modes[mode_index].endRe.test(lexem)) { - return 1; - } - if (modes[mode_index].endsWithParent) { - var level = endOfMode(mode_index - 1, lexem); - return level ? level + 1 : 0; - } - return 0; - } - - function isIllegal(lexem, mode) { - return mode.illegal && mode.illegalRe.test(lexem); - } - - function compileTerminators(mode, language) { - var terminators = []; - - for (var i = 0; i < mode.contains.length; i++) { - terminators.push(mode.contains[i].begin); - } - - var index = modes.length - 1; - do { - if (modes[index].end) { - terminators.push(modes[index].end); - } - index--; - } while (modes[index + 1].endsWithParent); - - if (mode.illegal) { - terminators.push(mode.illegal); - } - - return terminators.length ? langRe(language, terminators.join('|'), true) : null; - } - - function eatModeChunk(value, index) { - var mode = modes[modes.length - 1]; - if (mode.terminators === undefined) { - mode.terminators = compileTerminators(mode, language); - } - var match; - if (mode.terminators) { - mode.terminators.lastIndex = index; - match = mode.terminators.exec(value); - } - return match ? [value.substr(index, match.index - index), match[0], false] : [value.substr(index), '', true]; - } - - function keywordMatch(mode, match) { - var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; - var value = mode.keywords[match_str]; - if (value && value instanceof Array) { - return value; - } - return false; - } - - function processKeywords(buffer, mode) { - buffer = escape(buffer); - if (!mode.keywords) { - return buffer; - } - var result = ''; - var last_index = 0; - mode.lexemsRe.lastIndex = 0; - var match = mode.lexemsRe.exec(buffer); - while (match) { - result += buffer.substr(last_index, match.index - last_index); - var keyword_match = keywordMatch(mode, match); - if (keyword_match) { - keyword_count += keyword_match[1]; - result += '' + match[0] + ''; - } else { - result += match[0]; - } - last_index = mode.lexemsRe.lastIndex; - match = mode.lexemsRe.exec(buffer); - } - return result + buffer.substr(last_index, buffer.length - last_index); - } - - function processSubLanguage(buffer, mode) { - var result; - if (mode.subLanguage == '') { - result = highlightAuto(buffer); - } else { - result = highlight(mode.subLanguage, buffer); - } - // Counting embedded language score towards the host language may be disabled - // with zeroing the containing mode relevance. Usecase in point is Markdown that - // allows XML everywhere and makes every XML snippet to have a much larger Markdown - // score. - if (mode.relevance > 0) { - keyword_count += result.keyword_count; - relevance += result.relevance; - } - return '' + result.value + ''; - } - - function processBuffer(buffer, mode) { - if (mode.subLanguage && languages[mode.subLanguage] || mode.subLanguage == '') { - return processSubLanguage(buffer, mode); - } else { - return processKeywords(buffer, mode); - } - } - - function startNewMode(mode, lexem) { - var markup = mode.className?'':''; - if (mode.returnBegin) { - result += markup; - mode.buffer = ''; - } else if (mode.excludeBegin) { - result += escape(lexem) + markup; - mode.buffer = ''; - } else { - result += markup; - mode.buffer = lexem; - } - modes.push(mode); - relevance += mode.relevance; - } - - function processModeInfo(buffer, lexem, end) { - var current_mode = modes[modes.length - 1]; - if (end) { - result += processBuffer(current_mode.buffer + buffer, current_mode); - return false; - } - - var new_mode = subMode(lexem, current_mode); - if (new_mode) { - result += processBuffer(current_mode.buffer + buffer, current_mode); - startNewMode(new_mode, lexem); - return new_mode.returnBegin; - } - - var end_level = endOfMode(modes.length - 1, lexem); - if (end_level) { - var markup = current_mode.className?'':''; - if (current_mode.returnEnd) { - result += processBuffer(current_mode.buffer + buffer, current_mode) + markup; - } else if (current_mode.excludeEnd) { - result += processBuffer(current_mode.buffer + buffer, current_mode) + markup + escape(lexem); - } else { - result += processBuffer(current_mode.buffer + buffer + lexem, current_mode) + markup; - } - while (end_level > 1) { - markup = modes[modes.length - 2].className?'':''; - result += markup; - end_level--; - modes.length--; - } - var last_ended_mode = modes[modes.length - 1]; - modes.length--; - modes[modes.length - 1].buffer = ''; - if (last_ended_mode.starts) { - startNewMode(last_ended_mode.starts, ''); - } - return current_mode.returnEnd; - } - - if (isIllegal(lexem, current_mode)) { - throw 'Illegal'; - } - } - - var language = languages[language_name]; - var modes = [language.defaultMode]; - var relevance = 0; - var keyword_count = 0; - var result = ''; - try { - var mode_info, index = 0; - language.defaultMode.buffer = ''; - do { - mode_info = eatModeChunk(value, index); - var return_lexem = processModeInfo(mode_info[0], mode_info[1], mode_info[2]); - index += mode_info[0].length; - if (!return_lexem) { - index += mode_info[1].length; - } - } while (!mode_info[2]); - return { - relevance: relevance, - keyword_count: keyword_count, - value: result, - language: language_name - }; - } catch (e) { - if (e == 'Illegal') { - return { - relevance: 0, - keyword_count: 0, - value: escape(value) - }; - } else { - throw e; - } - } - } - - /* - Highlighting with language detection. Accepts a string with the code to - highlight. Returns an object with the following properties: - - - language (detected language) - - relevance (int) - - keyword_count (int) - - value (an HTML string with highlighting markup) - - second_best (object with the same structure for second-best heuristically - detected language, may be absent) - - */ - function highlightAuto(text) { - var result = { - keyword_count: 0, - relevance: 0, - value: escape(text) - }; - var second_best = result; - for (var key in languages) { - if (!languages.hasOwnProperty(key)) { - continue; - } - var current = highlight(key, text); - current.language = key; - if (current.keyword_count + current.relevance > second_best.keyword_count + second_best.relevance) { - second_best = current; - } - if (current.keyword_count + current.relevance > result.keyword_count + result.relevance) { - second_best = result; - result = current; - } - } - if (second_best.language) { - result.second_best = second_best; - } - return result; - } - - /* - Post-processing of the highlighted markup: - - - replace TABs with something more useful - - replace real line-breaks with '
              ' for non-pre containers - - */ - function fixMarkup(value, tabReplace, useBR) { - if (tabReplace) { - value = value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1, offset, s) { - return p1.replace(/\t/g, tabReplace); - }); - } - if (useBR) { - value = value.replace(/\n/g, '
              '); - } - return value; - } - - /* - Applies highlighting to a DOM node containing code. Accepts a DOM node and - two optional parameters for fixMarkup. - */ - function highlightBlock(block, tabReplace, useBR) { - var text = blockText(block, useBR); - var language = blockLanguage(block); - var result, pre; - if (language == 'no-highlight') { - return; - } - if (language) { - result = highlight(language, text); - } else { - result = highlightAuto(text); - language = result.language; - } - var original = nodeStream(block); - if (original.length) { - pre = document.createElement('pre'); - pre.innerHTML = result.value; - result.value = mergeStreams(original, nodeStream(pre), text); - } - result.value = fixMarkup(result.value, tabReplace, useBR); - - var class_name = block.className; - if (!class_name.match('(\\s|^)(language-)?' + language + '(\\s|$)')) { - class_name = class_name ? (class_name + ' ' + language) : language; - } - if (/MSIE [678]/.test(navigator.userAgent) && block.tagName == 'CODE' && block.parentNode.tagName == 'PRE') { - // This is for backwards compatibility only. IE needs this strange - // hack becasue it cannot just cleanly replace block contents. - pre = block.parentNode; - var container = document.createElement('div'); - container.innerHTML = '
              ' + result.value + '
              '; - block = container.firstChild.firstChild; - container.firstChild.className = pre.className; - pre.parentNode.replaceChild(container.firstChild, pre); - } else { - block.innerHTML = result.value; - } - block.className = class_name; - block.result = { - language: language, - kw: result.keyword_count, - re: result.relevance - }; - if (result.second_best) { - block.second_best = { - language: result.second_best.language, - kw: result.second_best.keyword_count, - re: result.second_best.relevance - }; - } - } - - /* - Applies highlighting to all
              ..
              blocks on a page. - */ - function initHighlighting() { - if (initHighlighting.called) { - return; - } - initHighlighting.called = true; - var pres = document.getElementsByTagName('pre'); - for (var i = 0; i < pres.length; i++) { - var code = findCode(pres[i]); - if (code){highlightBlock(code, hljs.tabReplace);} - } - } - - /* - Attaches highlighting to the page load event. - */ - function initHighlightingOnLoad() { - if (window.addEventListener) { - window.addEventListener('DOMContentLoaded', initHighlighting, false); - window.addEventListener('load', initHighlighting, false); - } else if (window.attachEvent){window.attachEvent('onload', initHighlighting);} else {window.onload = initHighlighting;} - } - - var languages = {}; // a shortcut to avoid writing "this." everywhere - - /* Interface definition */ - - this.LANGUAGES = languages; - this.highlight = highlight; - this.highlightAuto = highlightAuto; - this.fixMarkup = fixMarkup; - this.highlightBlock = highlightBlock; - this.initHighlighting = initHighlighting; - this.initHighlightingOnLoad = initHighlightingOnLoad; - - // Common regexps - this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*'; - this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*'; - this.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; - this.C_NUMBER_RE = '\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float - this.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... - this.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; - - // Common modes - this.BACKSLASH_ESCAPE = { - begin: '\\\\.', relevance: 0 - }; - this.APOS_STRING_MODE = { - className: 'string', - begin: '\'', end: '\'', - illegal: '\\n', - contains: [this.BACKSLASH_ESCAPE], - relevance: 0 - }; - this.QUOTE_STRING_MODE = { - className: 'string', - begin: '"', end: '"', - illegal: '\\n', - contains: [this.BACKSLASH_ESCAPE], - relevance: 0 - }; - this.C_LINE_COMMENT_MODE = { - className: 'comment', - begin: '//', end: '$' - }; - this.C_BLOCK_COMMENT_MODE = { - className: 'comment', - begin: '/\\*', end: '\\*/' - }; - this.HASH_COMMENT_MODE = { - className: 'comment', - begin: '#', end: '$' - }; - this.NUMBER_MODE = { - className: 'number', - begin: this.NUMBER_RE, - relevance: 0 - }; - this.C_NUMBER_MODE = { - className: 'number', - begin: this.C_NUMBER_RE, - relevance: 0 - }; - this.BINARY_NUMBER_MODE = { - className: 'number', - begin: this.BINARY_NUMBER_RE, - relevance: 0 - }; - - // Utility functions - this.inherit = function(parent, obj) { - var result = {} - for (var key in parent) - result[key] = parent[key]; - if (obj){for (var key in obj) - result[key] = obj[key];} - return result; - } -}(); diff --git a/build/vendor/jshint/jshint.js b/build/vendor/jshint/jshint.js deleted file mode 100755 index 5b1cc1f..0000000 --- a/build/vendor/jshint/jshint.js +++ /dev/null @@ -1,4551 +0,0 @@ -/*! - * JSHint, by JSHint Community. - * - * Licensed under the same slightly modified MIT license that JSLint is. - * It stops evil-doers everywhere. - * - * JSHint is a derivative work of JSLint: - * - * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * JSHint was forked from 2010-12-16 edition of JSLint. - * - */ - -/* - JSHINT is a global function. It takes two parameters. - - var myResult = JSHINT(source, option); - - The first parameter is either a string or an array of strings. If it is a - string, it will be split on '\n' or '\r'. If it is an array of strings, it - is assumed that each string represents one line. The source can be a - JavaScript text or a JSON text. - - The second parameter is an optional object of options which control the - operation of JSHINT. Most of the options are booleans: They are all - optional and have a default value of false. One of the options, predef, - can be an array of names, which will be used to declare global variables, - or an object whose keys are used as global names, with a boolean value - that determines if they are assignable. - - If it checks out, JSHINT returns true. Otherwise, it returns false. - - If false, you can inspect JSHINT.errors to find out the problems. - JSHINT.errors is an array of objects containing these members: - - { - line : The line (relative to 0) at which the lint was found - character : The character (relative to 0) at which the lint was found - reason : The problem - evidence : The text line in which the problem occurred - raw : The raw message before the details were inserted - a : The first detail - b : The second detail - c : The third detail - d : The fourth detail - } - - If a fatal error was found, a null will be the last element of the - JSHINT.errors array. - - You can request a Function Report, which shows all of the functions - and the parameters and vars that they use. This can be used to find - implied global variables and other problems. The report is in HTML and - can be inserted in an HTML . - - var myReport = JSHINT.report(limited); - - If limited is true, then the report will be limited to only errors. - - You can request a data structure which contains JSHint's results. - - var myData = JSHINT.data(); - - It returns a structure with this form: - - { - errors: [ - { - line: NUMBER, - character: NUMBER, - reason: STRING, - evidence: STRING - } - ], - functions: [ - name: STRING, - line: NUMBER, - last: NUMBER, - param: [ - STRING - ], - closure: [ - STRING - ], - var: [ - STRING - ], - exception: [ - STRING - ], - outer: [ - STRING - ], - unused: [ - STRING - ], - global: [ - STRING - ], - label: [ - STRING - ] - ], - globals: [ - STRING - ], - member: { - STRING: NUMBER - }, - unused: [ - { - name: STRING, - line: NUMBER - } - ], - implieds: [ - { - name: STRING, - line: NUMBER - } - ], - urls: [ - STRING - ], - json: BOOLEAN - } - - Empty arrays will not be included. - -*/ - -/*jshint - evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true, - undef: true, maxlen: 100, indent:4 -*/ - -/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)", - "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)", - "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)", - "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==", - "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax, - __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio, - Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas, - CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date, - Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag, - E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event, - Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form, - FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey, - HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement, - HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement, - HTMLDivElement, HTMLDListElement, HTMLFieldSetElement, - HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement, - HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement, - HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement, - HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement, - HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement, - HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement, - HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement, - HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement, - HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement, - HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement, - HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement, - Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array, - Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E, - MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort, - MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option, - Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, - RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, - SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion, - ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller, - Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables, - SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template, - Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL, - VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer, - XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, - "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob, - b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, call, callee, - caller, camelcase, cases, charAt, charCodeAt, character, clearInterval, clearTimeout, - close, closed, closure, comment, condition, confirm, console, constructor, - content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI, - decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document, - dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent, - entityify, eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil, - ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, - forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions, - g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict, - hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include, - indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray, - isDigit, isFinite, isNaN, iterator, java, join, jshint, - JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma, - latedef, lbp, led, left, length, line, load, loadClass, localStorage, location, - log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy, - moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen, - nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus, - onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param, - parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt, - proto, prototype, prototypejs, provides, push, quit, quotmark, range, raw, reach, reason, regexp, - readFile, readUrl, regexdash, removeEventListener, replace, report, require, - reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right, - runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, - send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice, - smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow, - supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, - type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis, - value, valueOf, var, vars, version, WebSocket, withstmt, white, window, windows, Worker, wsh*/ - -/*global exports: false */ - -// We build the application inside a function so that we produce only a single -// global variable. That function will be invoked immediately, and its return -// value is the JSHINT function itself. - -var JSHINT = (function () { - "use strict"; - - var anonname, // The guessed name for anonymous functions. - -// These are operators that should not be used with the ! operator. - - bang = { - '<' : true, - '<=' : true, - '==' : true, - '===': true, - '!==': true, - '!=' : true, - '>' : true, - '>=' : true, - '+' : true, - '-' : true, - '*' : true, - '/' : true, - '%' : true - }, - - // These are the JSHint boolean options. - boolOptions = { - asi : true, // if automatic semicolon insertion should be tolerated - bitwise : true, // if bitwise operators should not be allowed - boss : true, // if advanced usage of assignments should be allowed - browser : true, // if the standard browser globals should be predefined - camelcase : true, // if identifiers should be required in camel case - couch : true, // if CouchDB globals should be predefined - curly : true, // if curly braces around all blocks should be required - debug : true, // if debugger statements should be allowed - devel : true, // if logging globals should be predefined (console, - // alert, etc.) - dojo : true, // if Dojo Toolkit globals should be predefined - eqeqeq : true, // if === should be required - eqnull : true, // if == null comparisons should be tolerated - es5 : true, // if ES5 syntax should be allowed - esnext : true, // if es.next specific syntax should be allowed - evil : true, // if eval should be allowed - expr : true, // if ExpressionStatement should be allowed as Programs - forin : true, // if for in statements must filter - funcscope : true, // if only function scope should be used for scope tests - globalstrict: true, // if global "use strict"; should be allowed (also - // enables 'strict') - immed : true, // if immediate invocations must be wrapped in parens - iterator : true, // if the `__iterator__` property should be allowed - jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing - // statements inside of a one-line blocks. - latedef : true, // if the use before definition should not be tolerated - laxbreak : true, // if line breaks should not be checked - laxcomma : true, // if line breaks should not be checked around commas - loopfunc : true, // if functions should be allowed to be defined within - // loops - mootools : true, // if MooTools globals should be predefined - multistr : true, // allow multiline strings - newcap : true, // if constructor names must be capitalized - noarg : true, // if arguments.caller and arguments.callee should be - // disallowed - node : true, // if the Node.js environment globals should be - // predefined - noempty : true, // if empty blocks should be disallowed - nonew : true, // if using `new` for side-effects should be disallowed - nonstandard : true, // if non-standard (but widely adopted) globals should - // be predefined - nomen : true, // if names should be checked - onevar : true, // if only one var statement per function should be - // allowed - onecase : true, // if one case switch statements should be allowed - passfail : true, // if the scan should stop on first error - plusplus : true, // if increment/decrement should not be allowed - proto : true, // if the `__proto__` property should be allowed - prototypejs : true, // if Prototype and Scriptaculous globals should be - // predefined - regexdash : true, // if unescaped first/last dash (-) inside brackets - // should be tolerated - regexp : true, // if the . should not be allowed in regexp literals - rhino : true, // if the Rhino environment globals should be predefined - undef : true, // if variables should be declared before used - scripturl : true, // if script-targeted URLs should be tolerated - shadow : true, // if variable shadowing should be tolerated - smarttabs : true, // if smarttabs should be tolerated - // (http://www.emacswiki.org/emacs/SmartTabs) - strict : true, // require the "use strict"; pragma - sub : true, // if all forms of subscript notation are tolerated - supernew : true, // if `new function () { ... };` and `new Object;` - // should be tolerated - trailing : true, // if trailing whitespace rules apply - validthis : true, // if 'this' inside a non-constructor function is valid. - // This is a function scoped option only. - withstmt : true, // if with statements should be allowed - white : true, // if strict whitespace rules apply - wsh : true // if the Windows Scripting Host environment globals - // should be predefined - }, - - // These are the JSHint options that can take any value - // (we use this object to detect invalid options) - valOptions = { - maxlen: false, - indent: false, - maxerr: false, - predef: false, - quotmark: false //'single'|'double'|true - }, - - // These are JSHint boolean options which are shared with JSLint - // where the definition in JSHint is opposite JSLint - invertedOptions = { - bitwise : true, - forin : true, - newcap : true, - nomen : true, - plusplus : true, - regexp : true, - undef : true, - white : true, - - // Inverted and renamed, use JSHint name here - eqeqeq : true, - onevar : true - }, - - // These are JSHint boolean options which are shared with JSLint - // where the name has been changed but the effect is unchanged - renamedOptions = { - eqeq : "eqeqeq", - vars : "onevar", - windows : "wsh" - }, - - - // browser contains a set of global names which are commonly provided by a - // web browser environment. - browser = { - ArrayBuffer : false, - ArrayBufferView : false, - Audio : false, - addEventListener : false, - applicationCache : false, - atob : false, - blur : false, - btoa : false, - clearInterval : false, - clearTimeout : false, - close : false, - closed : false, - DataView : false, - DOMParser : false, - defaultStatus : false, - document : false, - event : false, - FileReader : false, - Float32Array : false, - Float64Array : false, - FormData : false, - focus : false, - frames : false, - getComputedStyle : false, - HTMLElement : false, - HTMLAnchorElement : false, - HTMLBaseElement : false, - HTMLBlockquoteElement : false, - HTMLBodyElement : false, - HTMLBRElement : false, - HTMLButtonElement : false, - HTMLCanvasElement : false, - HTMLDirectoryElement : false, - HTMLDivElement : false, - HTMLDListElement : false, - HTMLFieldSetElement : false, - HTMLFontElement : false, - HTMLFormElement : false, - HTMLFrameElement : false, - HTMLFrameSetElement : false, - HTMLHeadElement : false, - HTMLHeadingElement : false, - HTMLHRElement : false, - HTMLHtmlElement : false, - HTMLIFrameElement : false, - HTMLImageElement : false, - HTMLInputElement : false, - HTMLIsIndexElement : false, - HTMLLabelElement : false, - HTMLLayerElement : false, - HTMLLegendElement : false, - HTMLLIElement : false, - HTMLLinkElement : false, - HTMLMapElement : false, - HTMLMenuElement : false, - HTMLMetaElement : false, - HTMLModElement : false, - HTMLObjectElement : false, - HTMLOListElement : false, - HTMLOptGroupElement : false, - HTMLOptionElement : false, - HTMLParagraphElement : false, - HTMLParamElement : false, - HTMLPreElement : false, - HTMLQuoteElement : false, - HTMLScriptElement : false, - HTMLSelectElement : false, - HTMLStyleElement : false, - HTMLTableCaptionElement : false, - HTMLTableCellElement : false, - HTMLTableColElement : false, - HTMLTableElement : false, - HTMLTableRowElement : false, - HTMLTableSectionElement : false, - HTMLTextAreaElement : false, - HTMLTitleElement : false, - HTMLUListElement : false, - HTMLVideoElement : false, - history : false, - Int16Array : false, - Int32Array : false, - Int8Array : false, - Image : false, - length : false, - localStorage : false, - location : false, - MessageChannel : false, - MessageEvent : false, - MessagePort : false, - moveBy : false, - moveTo : false, - name : false, - Node : false, - NodeFilter : false, - navigator : false, - onbeforeunload : true, - onblur : true, - onerror : true, - onfocus : true, - onload : true, - onresize : true, - onunload : true, - open : false, - openDatabase : false, - opener : false, - Option : false, - parent : false, - print : false, - removeEventListener : false, - resizeBy : false, - resizeTo : false, - screen : false, - scroll : false, - scrollBy : false, - scrollTo : false, - sessionStorage : false, - setInterval : false, - setTimeout : false, - SharedWorker : false, - status : false, - top : false, - Uint16Array : false, - Uint32Array : false, - Uint8Array : false, - WebSocket : false, - window : false, - Worker : false, - XMLHttpRequest : false, - XMLSerializer : false, - XPathEvaluator : false, - XPathException : false, - XPathExpression : false, - XPathNamespace : false, - XPathNSResolver : false, - XPathResult : false - }, - - couch = { - "require" : false, - respond : false, - getRow : false, - emit : false, - send : false, - start : false, - sum : false, - log : false, - exports : false, - module : false, - provides : false - }, - - devel = { - alert : false, - confirm : false, - console : false, - Debug : false, - opera : false, - prompt : false - }, - - dojo = { - dojo : false, - dijit : false, - dojox : false, - define : false, - "require" : false - }, - - escapes = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '/' : '\\/', - '\\': '\\\\' - }, - - funct, // The current function - - functionicity = [ - 'closure', 'exception', 'global', 'label', - 'outer', 'unused', 'var' - ], - - functions, // All of the functions - - global, // The global scope - implied, // Implied globals - inblock, - indent, - jsonmode, - - jquery = { - '$' : false, - jQuery : false - }, - - lines, - lookahead, - member, - membersOnly, - - mootools = { - '$' : false, - '$$' : false, - Assets : false, - Browser : false, - Chain : false, - Class : false, - Color : false, - Cookie : false, - Core : false, - Document : false, - DomReady : false, - DOMReady : false, - Drag : false, - Element : false, - Elements : false, - Event : false, - Events : false, - Fx : false, - Group : false, - Hash : false, - HtmlTable : false, - Iframe : false, - IframeShim : false, - InputValidator : false, - instanceOf : false, - Keyboard : false, - Locale : false, - Mask : false, - MooTools : false, - Native : false, - Options : false, - OverText : false, - Request : false, - Scroller : false, - Slick : false, - Slider : false, - Sortables : false, - Spinner : false, - Swiff : false, - Tips : false, - Type : false, - typeOf : false, - URI : false, - Window : false - }, - - nexttoken, - - node = { - __filename : false, - __dirname : false, - Buffer : false, - console : false, - exports : false, - GLOBAL : false, - global : false, - module : false, - process : false, - require : false, - setTimeout : false, - clearTimeout : false, - setInterval : false, - clearInterval : false - }, - - noreach, - option, - predefined, // Global variables defined by option - prereg, - prevtoken, - - prototypejs = { - '$' : false, - '$$' : false, - '$A' : false, - '$F' : false, - '$H' : false, - '$R' : false, - '$break' : false, - '$continue' : false, - '$w' : false, - Abstract : false, - Ajax : false, - Class : false, - Enumerable : false, - Element : false, - Event : false, - Field : false, - Form : false, - Hash : false, - Insertion : false, - ObjectRange : false, - PeriodicalExecuter: false, - Position : false, - Prototype : false, - Selector : false, - Template : false, - Toggle : false, - Try : false, - Autocompleter : false, - Builder : false, - Control : false, - Draggable : false, - Draggables : false, - Droppables : false, - Effect : false, - Sortable : false, - SortableObserver : false, - Sound : false, - Scriptaculous : false - }, - - quotmark, - - rhino = { - defineClass : false, - deserialize : false, - gc : false, - help : false, - importPackage: false, - "java" : false, - load : false, - loadClass : false, - print : false, - quit : false, - readFile : false, - readUrl : false, - runCommand : false, - seal : false, - serialize : false, - spawn : false, - sync : false, - toint32 : false, - version : false - }, - - scope, // The current scope - stack, - - // standard contains the global names that are provided by the - // ECMAScript standard. - standard = { - Array : false, - Boolean : false, - Date : false, - decodeURI : false, - decodeURIComponent : false, - encodeURI : false, - encodeURIComponent : false, - Error : false, - 'eval' : false, - EvalError : false, - Function : false, - hasOwnProperty : false, - isFinite : false, - isNaN : false, - JSON : false, - Math : false, - Number : false, - Object : false, - parseInt : false, - parseFloat : false, - RangeError : false, - ReferenceError : false, - RegExp : false, - String : false, - SyntaxError : false, - TypeError : false, - URIError : false - }, - - // widely adopted global names that are not part of ECMAScript standard - nonstandard = { - escape : false, - unescape : false - }, - - standard_member = { - E : true, - LN2 : true, - LN10 : true, - LOG2E : true, - LOG10E : true, - MAX_VALUE : true, - MIN_VALUE : true, - NEGATIVE_INFINITY : true, - PI : true, - POSITIVE_INFINITY : true, - SQRT1_2 : true, - SQRT2 : true - }, - - directive, - syntax = {}, - tab, - token, - urls, - useESNextSyntax, - warnings, - - wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : true - }; - - // Regular expressions. Some of these are stupidly long. - var ax, cx, tx, nx, nxg, lx, ix, jx, ft; - (function () { - /*jshint maxlen:300 */ - - // unsafe comment or string - ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i; - - // unsafe characters that are silently deleted by one or more browsers - cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - - // token - tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/; - - // characters in strings that need escapement - nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - - // star slash - lx = /\*\/|\/\*/; - - // identifier - ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; - - // javascript url - jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - - // catches /* falls through */ comments - ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/; - }()); - - function F() {} // Used by Object.create - - function is_own(object, name) { - -// The object.hasOwnProperty method fails when the property under consideration -// is named 'hasOwnProperty'. So we have to use this more convoluted form. - - return Object.prototype.hasOwnProperty.call(object, name); - } - - function checkOption(name, t) { - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - warning("Bad option: '" + name + "'.", t); - } - } - -// Provide critical ES5 functions to ES3. - - if (typeof Array.isArray !== 'function') { - Array.isArray = function (o) { - return Object.prototype.toString.apply(o) === '[object Array]'; - }; - } - - if (typeof Object.create !== 'function') { - Object.create = function (o) { - F.prototype = o; - return new F(); - }; - } - - if (typeof Object.keys !== 'function') { - Object.keys = function (o) { - var a = [], k; - for (k in o) { - if (is_own(o, k)) { - a.push(k); - } - } - return a; - }; - } - -// Non standard methods - - if (typeof String.prototype.entityify !== 'function') { - String.prototype.entityify = function () { - return this - .replace(/&/g, '&') - .replace(//g, '>'); - }; - } - - if (typeof String.prototype.isAlpha !== 'function') { - String.prototype.isAlpha = function () { - return (this >= 'a' && this <= 'z\uffff') || - (this >= 'A' && this <= 'Z\uffff'); - }; - } - - if (typeof String.prototype.isDigit !== 'function') { - String.prototype.isDigit = function () { - return (this >= '0' && this <= '9'); - }; - } - - if (typeof String.prototype.supplant !== 'function') { - String.prototype.supplant = function (o) { - return this.replace(/\{([^{}]*)\}/g, function (a, b) { - var r = o[b]; - return typeof r === 'string' || typeof r === 'number' ? r : a; - }); - }; - } - - if (typeof String.prototype.name !== 'function') { - String.prototype.name = function () { - -// If the string looks like an identifier, then we can return it as is. -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can simply slap some quotes around it. -// Otherwise we must also replace the offending characters with safe -// sequences. - - if (ix.test(this)) { - return this; - } - if (nx.test(this)) { - return '"' + this.replace(nxg, function (a) { - var c = escapes[a]; - if (c) { - return c; - } - return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4); - }) + '"'; - } - return '"' + this + '"'; - }; - } - - - function combine(t, o) { - var n; - for (n in o) { - if (is_own(o, n)) { - t[n] = o[n]; - } - } - } - - function assume() { - if (option.couch) { - combine(predefined, couch); - } - - if (option.rhino) { - combine(predefined, rhino); - } - - if (option.prototypejs) { - combine(predefined, prototypejs); - } - - if (option.node) { - combine(predefined, node); - option.globalstrict = true; - } - - if (option.devel) { - combine(predefined, devel); - } - - if (option.dojo) { - combine(predefined, dojo); - } - - if (option.browser) { - combine(predefined, browser); - } - - if (option.nonstandard) { - combine(predefined, nonstandard); - } - - if (option.jquery) { - combine(predefined, jquery); - } - - if (option.mootools) { - combine(predefined, mootools); - } - - if (option.wsh) { - combine(predefined, wsh); - } - - if (option.esnext) { - useESNextSyntax(); - } - - if (option.globalstrict && option.strict !== false) { - option.strict = true; - } - } - - - // Produce an error warning. - function quit(message, line, chr) { - var percentage = Math.floor((line / lines.length) * 100); - - throw { - name: 'JSHintError', - line: line, - character: chr, - message: message + " (" + percentage + "% scanned).", - raw: message - }; - } - - function isundef(scope, m, t, a) { - return JSHINT.undefs.push([scope, m, t, a]); - } - - function warning(m, t, a, b, c, d) { - var ch, l, w; - t = t || nexttoken; - if (t.id === '(end)') { // `~ - t = token; - } - l = t.line || 0; - ch = t.from || 0; - w = { - id: '(error)', - raw: m, - evidence: lines[l - 1] || '', - line: l, - character: ch, - a: a, - b: b, - c: c, - d: d - }; - w.reason = m.supplant(w); - JSHINT.errors.push(w); - if (option.passfail) { - quit('Stopping. ', l, ch); - } - warnings += 1; - if (warnings >= option.maxerr) { - quit("Too many errors.", l, ch); - } - return w; - } - - function warningAt(m, l, ch, a, b, c, d) { - return warning(m, { - line: l, - from: ch - }, a, b, c, d); - } - - function error(m, t, a, b, c, d) { - var w = warning(m, t, a, b, c, d); - } - - function errorAt(m, l, ch, a, b, c, d) { - return error(m, { - line: l, - from: ch - }, a, b, c, d); - } - - - -// lexical analysis and token construction - - var lex = (function lex() { - var character, from, line, s; - -// Private lex methods - - function nextLine() { - var at, - tw; // trailing whitespace check - - if (line >= lines.length) - return false; - - character = 1; - s = lines[line]; - line += 1; - - // If smarttabs option is used check for spaces followed by tabs only. - // Otherwise check for any occurence of mixed tabs and spaces. - // Tabs and one space followed by block comment is allowed. - if (option.smarttabs) - at = s.search(/ \t/); - else - at = s.search(/ \t|\t [^\*]/); - - if (at >= 0) - warningAt("Mixed spaces and tabs.", line, at + 1); - - s = s.replace(/\t/g, tab); - at = s.search(cx); - - if (at >= 0) - warningAt("Unsafe character.", line, at); - - if (option.maxlen && option.maxlen < s.length) - warningAt("Line too long.", line, s.length); - - // Check for trailing whitespaces - tw = option.trailing && s.match(/^(.*?)\s+$/); - if (tw && !/^\s+$/.test(s)) { - warningAt("Trailing whitespace.", line, tw[1].length + 1); - } - return true; - } - -// Produce a token object. The token inherits from a syntax symbol. - - function it(type, value) { - var i, t; - if (type === '(color)' || type === '(range)') { - t = {type: type}; - } else if (type === '(punctuator)' || - (type === '(identifier)' && is_own(syntax, value))) { - t = syntax[value] || syntax['(error)']; - } else { - t = syntax[type]; - } - t = Object.create(t); - if (type === '(string)' || type === '(range)') { - if (!option.scripturl && jx.test(value)) { - warningAt("Script URL.", line, from); - } - } - if (type === '(identifier)') { - t.identifier = true; - if (value === '__proto__' && !option.proto) { - warningAt("The '{a}' property is deprecated.", - line, from, value); - } else if (value === '__iterator__' && !option.iterator) { - warningAt("'{a}' is only available in JavaScript 1.7.", - line, from, value); - } else if (option.nomen && (value.charAt(0) === '_' || - value.charAt(value.length - 1) === '_')) { - if (!option.node || token.id === '.' || - (value !== '__dirname' && value !== '__filename')) { - warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value); - } - } else if (option.camelcase && value.indexOf('_') > -1 && - !value.match(/^[A-Z0-9_]*$/)) { - warningAt("Identifier '{a}' is not in camel case.", - line, from, value); - } - } - t.value = value; - t.line = line; - t.character = character; - t.from = from; - i = t.id; - if (i !== '(endline)') { - prereg = i && - (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) || - i === 'return' || - i === 'case'); - } - return t; - } - - // Public lex methods - return { - init: function (source) { - if (typeof source === 'string') { - lines = source - .replace(/\r\n/g, '\n') - .replace(/\r/g, '\n') - .split('\n'); - } else { - lines = source; - } - - // If the first line is a shebang (#!), make it a blank and move on. - // Shebangs are used by Node scripts. - if (lines[0] && lines[0].substr(0, 2) === '#!') - lines[0] = ''; - - line = 0; - nextLine(); - from = 1; - }, - - range: function (begin, end) { - var c, value = ''; - from = character; - if (s.charAt(0) !== begin) { - errorAt("Expected '{a}' and instead saw '{b}'.", - line, character, begin, s.charAt(0)); - } - for (;;) { - s = s.slice(1); - character += 1; - c = s.charAt(0); - switch (c) { - case '': - errorAt("Missing '{a}'.", line, character, c); - break; - case end: - s = s.slice(1); - character += 1; - return it('(range)', value); - case '\\': - warningAt("Unexpected '{a}'.", line, character, c); - } - value += c; - } - - }, - - - // token -- this is called by advance to get the next token - token: function () { - var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n; - - function match(x) { - var r = x.exec(s), r1; - if (r) { - l = r[0].length; - r1 = r[1]; - c = r1.charAt(0); - s = s.substr(l); - from = character + l - r1.length; - character += l; - return r1; - } - } - - function string(x) { - var c, j, r = '', allowNewLine = false; - - if (jsonmode && x !== '"') { - warningAt("Strings must use doublequote.", - line, character); - } - - if (option.quotmark) { - if (option.quotmark === 'single' && x !== "'") { - warningAt("Strings must use singlequote.", - line, character); - } else if (option.quotmark === 'double' && x !== '"') { - warningAt("Strings must use doublequote.", - line, character); - } else if (option.quotmark === true) { - quotmark = quotmark || x; - if (quotmark !== x) { - warningAt("Mixed double and single quotes.", - line, character); - } - } - } - - function esc(n) { - var i = parseInt(s.substr(j + 1, n), 16); - j += n; - if (i >= 32 && i <= 126 && - i !== 34 && i !== 92 && i !== 39) { - warningAt("Unnecessary escapement.", line, character); - } - character += n; - c = String.fromCharCode(i); - } - j = 0; -unclosedString: for (;;) { - while (j >= s.length) { - j = 0; - - var cl = line, cf = from; - if (!nextLine()) { - errorAt("Unclosed string.", cl, cf); - break unclosedString; - } - - if (allowNewLine) { - allowNewLine = false; - } else { - warningAt("Unclosed string.", cl, cf); - } - } - c = s.charAt(j); - if (c === x) { - character += 1; - s = s.substr(j + 1); - return it('(string)', r, x); - } - if (c < ' ') { - if (c === '\n' || c === '\r') { - break; - } - warningAt("Control character in string: {a}.", - line, character + j, s.slice(0, j)); - } else if (c === '\\') { - j += 1; - character += 1; - c = s.charAt(j); - n = s.charAt(j + 1); - switch (c) { - case '\\': - case '"': - case '/': - break; - case '\'': - if (jsonmode) { - warningAt("Avoid \\'.", line, character); - } - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case '0': - c = '\0'; - // Octal literals fail in strict mode - // check if the number is between 00 and 07 - // where 'n' is the token next to 'c' - if (n >= 0 && n <= 7 && directive["use strict"]) { - warningAt( - "Octal literals are not allowed in strict mode.", - line, character); - } - break; - case 'u': - esc(4); - break; - case 'v': - if (jsonmode) { - warningAt("Avoid \\v.", line, character); - } - c = '\v'; - break; - case 'x': - if (jsonmode) { - warningAt("Avoid \\x-.", line, character); - } - esc(2); - break; - case '': - // last character is escape character - // always allow new line if escaped, but show - // warning if option is not set - allowNewLine = true; - if (option.multistr) { - if (jsonmode) { - warningAt("Avoid EOL escapement.", line, character); - } - c = ''; - character -= 1; - break; - } - warningAt("Bad escapement of EOL. Use option multistr if needed.", - line, character); - break; - default: - warningAt("Bad escapement.", line, character); - } - } - r += c; - character += 1; - j += 1; - } - } - - for (;;) { - if (!s) { - return it(nextLine() ? '(endline)' : '(end)', ''); - } - t = match(tx); - if (!t) { - t = ''; - c = ''; - while (s && s < '!') { - s = s.substr(1); - } - if (s) { - errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1)); - s = ''; - } - } else { - - // identifier - - if (c.isAlpha() || c === '_' || c === '$') { - return it('(identifier)', t); - } - - // number - - if (c.isDigit()) { - if (!isFinite(Number(t))) { - warningAt("Bad number '{a}'.", - line, character, t); - } - if (s.substr(0, 1).isAlpha()) { - warningAt("Missing space after '{a}'.", - line, character, t); - } - if (c === '0') { - d = t.substr(1, 1); - if (d.isDigit()) { - if (token.id !== '.') { - warningAt("Don't use extra leading zeros '{a}'.", - line, character, t); - } - } else if (jsonmode && (d === 'x' || d === 'X')) { - warningAt("Avoid 0x-. '{a}'.", - line, character, t); - } - } - if (t.substr(t.length - 1) === '.') { - warningAt( -"A trailing decimal point can be confused with a dot '{a}'.", line, character, t); - } - return it('(number)', t); - } - switch (t) { - - // string - - case '"': - case "'": - return string(t); - - // // comment - - case '//': - s = ''; - token.comment = true; - break; - - // /* comment - - case '/*': - for (;;) { - i = s.search(lx); - if (i >= 0) { - break; - } - if (!nextLine()) { - errorAt("Unclosed comment.", line, character); - } - } - character += i + 2; - if (s.substr(i, 1) === '/') { - errorAt("Nested comment.", line, character); - } - s = s.substr(i + 2); - token.comment = true; - break; - - // /*members /*jshint /*global - - case '/*members': - case '/*member': - case '/*jshint': - case '/*jslint': - case '/*global': - case '*/': - return { - value: t, - type: 'special', - line: line, - character: character, - from: from - }; - - case '': - break; - // / - case '/': - if (token.id === '/=') { - errorAt("A regular expression literal can be confused with '/='.", - line, from); - } - if (prereg) { - depth = 0; - captures = 0; - l = 0; - for (;;) { - b = true; - c = s.charAt(l); - l += 1; - switch (c) { - case '': - errorAt("Unclosed regular expression.", line, from); - return quit('Stopping.', line, from); - case '/': - if (depth > 0) { - warningAt("{a} unterminated regular expression " + - "group(s).", line, from + l, depth); - } - c = s.substr(0, l - 1); - q = { - g: true, - i: true, - m: true - }; - while (q[s.charAt(l)] === true) { - q[s.charAt(l)] = false; - l += 1; - } - character += l; - s = s.substr(l); - q = s.charAt(0); - if (q === '/' || q === '*') { - errorAt("Confusing regular expression.", - line, from); - } - return it('(regexp)', c); - case '\\': - c = s.charAt(l); - if (c < ' ') { - warningAt( -"Unexpected control character in regular expression.", line, from + l); - } else if (c === '<') { - warningAt( -"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); - } - l += 1; - break; - case '(': - depth += 1; - b = false; - if (s.charAt(l) === '?') { - l += 1; - switch (s.charAt(l)) { - case ':': - case '=': - case '!': - l += 1; - break; - default: - warningAt( -"Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l)); - } - } else { - captures += 1; - } - break; - case '|': - b = false; - break; - case ')': - if (depth === 0) { - warningAt("Unescaped '{a}'.", - line, from + l, ')'); - } else { - depth -= 1; - } - break; - case ' ': - q = 1; - while (s.charAt(l) === ' ') { - l += 1; - q += 1; - } - if (q > 1) { - warningAt( -"Spaces are hard to count. Use {{a}}.", line, from + l, q); - } - break; - case '[': - c = s.charAt(l); - if (c === '^') { - l += 1; - if (option.regexp) { - warningAt("Insecure '{a}'.", - line, from + l, c); - } else if (s.charAt(l) === ']') { - errorAt("Unescaped '{a}'.", - line, from + l, '^'); - } - } - if (c === ']') { - warningAt("Empty class.", line, - from + l - 1); - } - isLiteral = false; - isInRange = false; -klass: do { - c = s.charAt(l); - l += 1; - switch (c) { - case '[': - case '^': - warningAt("Unescaped '{a}'.", - line, from + l, c); - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case '-': - if (isLiteral && !isInRange) { - isLiteral = false; - isInRange = true; - } else if (isInRange) { - isInRange = false; - } else if (s.charAt(l) === ']') { - isInRange = true; - } else { - if (option.regexdash !== (l === 2 || (l === 3 && - s.charAt(1) === '^'))) { - warningAt("Unescaped '{a}'.", - line, from + l - 1, '-'); - } - isLiteral = true; - } - break; - case ']': - if (isInRange && !option.regexdash) { - warningAt("Unescaped '{a}'.", - line, from + l - 1, '-'); - } - break klass; - case '\\': - c = s.charAt(l); - if (c < ' ') { - warningAt( -"Unexpected control character in regular expression.", line, from + l); - } else if (c === '<') { - warningAt( -"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); - } - l += 1; - - // \w, \s and \d are never part of a character range - if (/[wsd]/i.test(c)) { - if (isInRange) { - warningAt("Unescaped '{a}'.", - line, from + l, '-'); - isInRange = false; - } - isLiteral = false; - } else if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case '/': - warningAt("Unescaped '{a}'.", - line, from + l - 1, '/'); - - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case '<': - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - default: - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - } - } while (c); - break; - case '.': - if (option.regexp) { - warningAt("Insecure '{a}'.", line, - from + l, c); - } - break; - case ']': - case '?': - case '{': - case '}': - case '+': - case '*': - warningAt("Unescaped '{a}'.", line, - from + l, c); - } - if (b) { - switch (s.charAt(l)) { - case '?': - case '+': - case '*': - l += 1; - if (s.charAt(l) === '?') { - l += 1; - } - break; - case '{': - l += 1; - c = s.charAt(l); - if (c < '0' || c > '9') { - warningAt( -"Expected a number and instead saw '{a}'.", line, from + l, c); - } - l += 1; - low = +c; - for (;;) { - c = s.charAt(l); - if (c < '0' || c > '9') { - break; - } - l += 1; - low = +c + (low * 10); - } - high = low; - if (c === ',') { - l += 1; - high = Infinity; - c = s.charAt(l); - if (c >= '0' && c <= '9') { - l += 1; - high = +c; - for (;;) { - c = s.charAt(l); - if (c < '0' || c > '9') { - break; - } - l += 1; - high = +c + (high * 10); - } - } - } - if (s.charAt(l) !== '}') { - warningAt( -"Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c); - } else { - l += 1; - } - if (s.charAt(l) === '?') { - l += 1; - } - if (low > high) { - warningAt( -"'{a}' should not be greater than '{b}'.", line, from + l, low, high); - } - } - } - } - c = s.substr(0, l - 1); - character += l; - s = s.substr(l); - return it('(regexp)', c); - } - return it('(punctuator)', t); - - // punctuator - - case '#': - return it('(punctuator)', t); - default: - return it('(punctuator)', t); - } - } - } - } - }; - }()); - - - function addlabel(t, type) { - - if (t === 'hasOwnProperty') { - warning("'hasOwnProperty' is a really bad name."); - } - -// Define t in the current function in the current scope. - if (is_own(funct, t) && !funct['(global)']) { - if (funct[t] === true) { - if (option.latedef) - warning("'{a}' was used before it was defined.", nexttoken, t); - } else { - if (!option.shadow && type !== "exception") - warning("'{a}' is already defined.", nexttoken, t); - } - } - - funct[t] = type; - if (funct['(global)']) { - global[t] = funct; - if (is_own(implied, t)) { - if (option.latedef) - warning("'{a}' was used before it was defined.", nexttoken, t); - delete implied[t]; - } - } else { - scope[t] = funct; - } - } - - - function doOption() { - var b, obj, filter, o = nexttoken.value, t, tn, v; - - switch (o) { - case '*/': - error("Unbegun comment."); - break; - case '/*members': - case '/*member': - o = '/*members'; - if (!membersOnly) { - membersOnly = {}; - } - obj = membersOnly; - break; - case '/*jshint': - case '/*jslint': - obj = option; - filter = boolOptions; - break; - case '/*global': - obj = predefined; - break; - default: - error("What?"); - } - - t = lex.token(); -loop: for (;;) { - for (;;) { - if (t.type === 'special' && t.value === '*/') { - break loop; - } - if (t.id !== '(endline)' && t.id !== ',') { - break; - } - t = lex.token(); - } - if (t.type !== '(string)' && t.type !== '(identifier)' && - o !== '/*members') { - error("Bad option.", t); - } - - v = lex.token(); - if (v.id === ':') { - v = lex.token(); - - if (obj === membersOnly) { - error("Expected '{a}' and instead saw '{b}'.", - t, '*/', ':'); - } - - if (o === '/*jshint') { - checkOption(t.value, t); - } - - if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) { - b = +v.value; - if (typeof b !== 'number' || !isFinite(b) || b <= 0 || - Math.floor(b) !== b) { - error("Expected a small integer and instead saw '{a}'.", - v, v.value); - } - obj.white = true; - obj.indent = b; - } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) { - b = +v.value; - if (typeof b !== 'number' || !isFinite(b) || b <= 0 || - Math.floor(b) !== b) { - error("Expected a small integer and instead saw '{a}'.", - v, v.value); - } - obj.maxerr = b; - } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) { - b = +v.value; - if (typeof b !== 'number' || !isFinite(b) || b <= 0 || - Math.floor(b) !== b) { - error("Expected a small integer and instead saw '{a}'.", - v, v.value); - } - obj.maxlen = b; - } else if (t.value === 'validthis') { - if (funct['(global)']) { - error("Option 'validthis' can't be used in a global scope."); - } else { - if (v.value === 'true' || v.value === 'false') - obj[t.value] = v.value === 'true'; - else - error("Bad option value.", v); - } - } else if (v.value === 'true' || v.value === 'false') { - if (o === '/*jslint') { - tn = renamedOptions[t.value] || t.value; - obj[tn] = v.value === 'true'; - if (invertedOptions[tn] !== undefined) { - obj[tn] = !obj[tn]; - } - } else { - obj[t.value] = v.value === 'true'; - } - } else { - error("Bad option value.", v); - } - t = lex.token(); - } else { - if (o === '/*jshint' || o === '/*jslint') { - error("Missing option value.", t); - } - obj[t.value] = false; - t = v; - } - } - if (filter) { - assume(); - } - } - - -// We need a peek function. If it has an argument, it peeks that much farther -// ahead. It is used to distinguish -// for ( var i in ... -// from -// for ( var i = ... - - function peek(p) { - var i = p || 0, j = 0, t; - - while (j <= i) { - t = lookahead[j]; - if (!t) { - t = lookahead[j] = lex.token(); - } - j += 1; - } - return t; - } - - - -// Produce the next token. It looks for programming errors. - - function advance(id, t) { - switch (token.id) { - case '(number)': - if (nexttoken.id === '.') { - warning("A dot following a number can be confused with a decimal point.", token); - } - break; - case '-': - if (nexttoken.id === '-' || nexttoken.id === '--') { - warning("Confusing minusses."); - } - break; - case '+': - if (nexttoken.id === '+' || nexttoken.id === '++') { - warning("Confusing plusses."); - } - break; - } - - if (token.type === '(string)' || token.identifier) { - anonname = token.value; - } - - if (id && nexttoken.id !== id) { - if (t) { - if (nexttoken.id === '(end)') { - warning("Unmatched '{a}'.", t, t.id); - } else { - warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", - nexttoken, id, t.id, t.line, nexttoken.value); - } - } else if (nexttoken.type !== '(identifier)' || - nexttoken.value !== id) { - warning("Expected '{a}' and instead saw '{b}'.", - nexttoken, id, nexttoken.value); - } - } - - prevtoken = token; - token = nexttoken; - for (;;) { - nexttoken = lookahead.shift() || lex.token(); - if (nexttoken.id === '(end)' || nexttoken.id === '(error)') { - return; - } - if (nexttoken.type === 'special') { - doOption(); - } else { - if (nexttoken.id !== '(endline)') { - break; - } - } - } - } - - -// This is the heart of JSHINT, the Pratt parser. In addition to parsing, it -// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is -// like .nud except that it is only used on the first token of a statement. -// Having .fud makes it much easier to define statement-oriented languages like -// JavaScript. I retained Pratt's nomenclature. - -// .nud Null denotation -// .fud First null denotation -// .led Left denotation -// lbp Left binding power -// rbp Right binding power - -// They are elements of the parsing method called Top Down Operator Precedence. - - function expression(rbp, initial) { - var left, isArray = false, isObject = false; - - if (nexttoken.id === '(end)') - error("Unexpected early end of program.", token); - - advance(); - if (initial) { - anonname = 'anonymous'; - funct['(verb)'] = token.value; - } - if (initial === true && token.fud) { - left = token.fud(); - } else { - if (token.nud) { - left = token.nud(); - } else { - if (nexttoken.type === '(number)' && token.id === '.') { - warning("A leading decimal point can be confused with a dot: '.{a}'.", - token, nexttoken.value); - advance(); - return token; - } else { - error("Expected an identifier and instead saw '{a}'.", - token, token.id); - } - } - while (rbp < nexttoken.lbp) { - isArray = token.value === 'Array'; - isObject = token.value === 'Object'; - - // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() - // Line breaks in IfStatement heads exist to satisfy the checkJSHint - // "Line too long." error. - if (left && (left.value || (left.first && left.first.value))) { - // If the left.value is not "new", or the left.first.value is a "." - // then safely assume that this is not "new Array()" and possibly - // not "new Object()"... - if (left.value !== 'new' || - (left.first && left.first.value && left.first.value === '.')) { - isArray = false; - // ...In the case of Object, if the left.value and token.value - // are not equal, then safely assume that this not "new Object()" - if (left.value !== token.value) { - isObject = false; - } - } - } - - advance(); - if (isArray && token.id === '(' && nexttoken.id === ')') - warning("Use the array literal notation [].", token); - if (isObject && token.id === '(' && nexttoken.id === ')') - warning("Use the object literal notation {}.", token); - if (token.led) { - left = token.led(left); - } else { - error("Expected an operator and instead saw '{a}'.", - token, token.id); - } - } - } - return left; - } - - -// Functions for conformance of style. - - function adjacent(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white) { - if (left.character !== right.from && left.line === right.line) { - left.from += (left.character - left.from); - warning("Unexpected space after '{a}'.", left, left.value); - } - } - } - - function nobreak(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white && (left.character !== right.from || left.line !== right.line)) { - warning("Unexpected space before '{a}'.", right, right.value); - } - } - - function nospace(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white && !left.comment) { - if (left.line === right.line) { - adjacent(left, right); - } - } - } - - function nonadjacent(left, right) { - if (option.white) { - left = left || token; - right = right || nexttoken; - if (left.line === right.line && left.character === right.from) { - left.from += (left.character - left.from); - warning("Missing space after '{a}'.", - left, left.value); - } - } - } - - function nobreaknonadjacent(left, right) { - left = left || token; - right = right || nexttoken; - if (!option.laxbreak && left.line !== right.line) { - warning("Bad line breaking before '{a}'.", right, right.id); - } else if (option.white) { - left = left || token; - right = right || nexttoken; - if (left.character === right.from) { - left.from += (left.character - left.from); - warning("Missing space after '{a}'.", - left, left.value); - } - } - } - - function indentation(bias) { - var i; - if (option.white && nexttoken.id !== '(end)') { - i = indent + (bias || 0); - if (nexttoken.from !== i) { - warning( -"Expected '{a}' to have an indentation at {b} instead at {c}.", - nexttoken, nexttoken.value, i, nexttoken.from); - } - } - } - - function nolinebreak(t) { - t = t || token; - if (t.line !== nexttoken.line) { - warning("Line breaking error '{a}'.", t, t.value); - } - } - - - function comma() { - if (token.line !== nexttoken.line) { - if (!option.laxcomma) { - if (comma.first) { - warning("Comma warnings can be turned off with 'laxcomma'"); - comma.first = false; - } - warning("Bad line breaking before '{a}'.", token, nexttoken.id); - } - } else if (!token.comment && token.character !== nexttoken.from && option.white) { - token.from += (token.character - token.from); - warning("Unexpected space after '{a}'.", token, token.value); - } - advance(','); - nonadjacent(token, nexttoken); - } - - -// Functional constructors for making the symbols that will be inherited by -// tokens. - - function symbol(s, p) { - var x = syntax[s]; - if (!x || typeof x !== 'object') { - syntax[s] = x = { - id: s, - lbp: p, - value: s - }; - } - return x; - } - - - function delim(s) { - return symbol(s, 0); - } - - - function stmt(s, f) { - var x = delim(s); - x.identifier = x.reserved = true; - x.fud = f; - return x; - } - - - function blockstmt(s, f) { - var x = stmt(s, f); - x.block = true; - return x; - } - - - function reserveName(x) { - var c = x.id.charAt(0); - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - x.identifier = x.reserved = true; - } - return x; - } - - - function prefix(s, f) { - var x = symbol(s, 150); - reserveName(x); - x.nud = (typeof f === 'function') ? f : function () { - this.right = expression(150); - this.arity = 'unary'; - if (this.id === '++' || this.id === '--') { - if (option.plusplus) { - warning("Unexpected use of '{a}'.", this, this.id); - } else if ((!this.right.identifier || this.right.reserved) && - this.right.id !== '.' && this.right.id !== '[') { - warning("Bad operand.", this); - } - } - return this; - }; - return x; - } - - - function type(s, f) { - var x = delim(s); - x.type = s; - x.nud = f; - return x; - } - - - function reserve(s, f) { - var x = type(s, f); - x.identifier = x.reserved = true; - return x; - } - - - function reservevar(s, v) { - return reserve(s, function () { - if (typeof v === 'function') { - v(this); - } - return this; - }); - } - - - function infix(s, f, p, w) { - var x = symbol(s, p); - reserveName(x); - x.led = function (left) { - if (!w) { - nobreaknonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); - } - if (s === "in" && left.id === "!") { - warning("Confusing use of '{a}'.", left, '!'); - } - if (typeof f === 'function') { - return f(left, this); - } else { - this.left = left; - this.right = expression(p); - return this; - } - }; - return x; - } - - - function relation(s, f) { - var x = symbol(s, 100); - x.led = function (left) { - nobreaknonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); - var right = expression(100); - if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) { - warning("Use the isNaN function to compare with NaN.", this); - } else if (f) { - f.apply(this, [left, right]); - } - if (left.id === '!') { - warning("Confusing use of '{a}'.", left, '!'); - } - if (right.id === '!') { - warning("Confusing use of '{a}'.", right, '!'); - } - this.left = left; - this.right = right; - return this; - }; - return x; - } - - - function isPoorRelation(node) { - return node && - ((node.type === '(number)' && +node.value === 0) || - (node.type === '(string)' && node.value === '') || - (node.type === 'null' && !option.eqnull) || - node.type === 'true' || - node.type === 'false' || - node.type === 'undefined'); - } - - - function assignop(s, f) { - symbol(s, 20).exps = true; - return infix(s, function (left, that) { - var l; - that.left = left; - if (predefined[left.value] === false && - scope[left.value]['(global)'] === true) { - warning("Read only.", left); - } else if (left['function']) { - warning("'{a}' is a function.", left, left.value); - } - if (left) { - if (option.esnext && funct[left.value] === 'const') { - warning("Attempting to override '{a}' which is a constant", left, left.value); - } - if (left.id === '.' || left.id === '[') { - if (!left.left || left.left.value === 'arguments') { - warning('Bad assignment.', that); - } - that.right = expression(19); - return that; - } else if (left.identifier && !left.reserved) { - if (funct[left.value] === 'exception') { - warning("Do not assign to the exception parameter.", left); - } - that.right = expression(19); - return that; - } - if (left === syntax['function']) { - warning( -"Expected an identifier in an assignment and instead saw a function invocation.", - token); - } - } - error("Bad assignment.", that); - }, 20); - } - - - function bitwise(s, f, p) { - var x = symbol(s, p); - reserveName(x); - x.led = (typeof f === 'function') ? f : function (left) { - if (option.bitwise) { - warning("Unexpected use of '{a}'.", this, this.id); - } - this.left = left; - this.right = expression(p); - return this; - }; - return x; - } - - - function bitwiseassignop(s) { - symbol(s, 20).exps = true; - return infix(s, function (left, that) { - if (option.bitwise) { - warning("Unexpected use of '{a}'.", that, that.id); - } - nonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); - if (left) { - if (left.id === '.' || left.id === '[' || - (left.identifier && !left.reserved)) { - expression(19); - return that; - } - if (left === syntax['function']) { - warning( -"Expected an identifier in an assignment, and instead saw a function invocation.", - token); - } - return that; - } - error("Bad assignment.", that); - }, 20); - } - - - function suffix(s, f) { - var x = symbol(s, 150); - x.led = function (left) { - if (option.plusplus) { - warning("Unexpected use of '{a}'.", this, this.id); - } else if ((!left.identifier || left.reserved) && - left.id !== '.' && left.id !== '[') { - warning("Bad operand.", this); - } - this.left = left; - return this; - }; - return x; - } - - - // fnparam means that this identifier is being defined as a function - // argument (see identifier()) - function optionalidentifier(fnparam) { - if (nexttoken.identifier) { - advance(); - if (token.reserved && !option.es5) { - // `undefined` as a function param is a common pattern to protect - // against the case when somebody does `undefined = true` and - // help with minification. More info: https://gist.github.com/315916 - if (!fnparam || token.value !== 'undefined') { - warning("Expected an identifier and instead saw '{a}' (a reserved word).", - token, token.id); - } - } - return token.value; - } - } - - // fnparam means that this identifier is being defined as a function - // argument - function identifier(fnparam) { - var i = optionalidentifier(fnparam); - if (i) { - return i; - } - if (token.id === 'function' && nexttoken.id === '(') { - warning("Missing name in function declaration."); - } else { - error("Expected an identifier and instead saw '{a}'.", - nexttoken, nexttoken.value); - } - } - - - function reachable(s) { - var i = 0, t; - if (nexttoken.id !== ';' || noreach) { - return; - } - for (;;) { - t = peek(i); - if (t.reach) { - return; - } - if (t.id !== '(endline)') { - if (t.id === 'function') { - if (!option.latedef) { - break; - } - warning( -"Inner functions should be listed at the top of the outer function.", t); - break; - } - warning("Unreachable '{a}' after '{b}'.", t, t.value, s); - break; - } - i += 1; - } - } - - - function statement(noindent) { - var i = indent, r, s = scope, t = nexttoken; - - if (t.id === ";") { - advance(";"); - return; - } - -// Is this a labelled statement? - - if (t.identifier && !t.reserved && peek().id === ':') { - advance(); - advance(':'); - scope = Object.create(s); - addlabel(t.value, 'label'); - if (!nexttoken.labelled) { - warning("Label '{a}' on {b} statement.", - nexttoken, t.value, nexttoken.value); - } - if (jx.test(t.value + ':')) { - warning("Label '{a}' looks like a javascript url.", - t, t.value); - } - nexttoken.label = t.value; - t = nexttoken; - } - -// Parse the statement. - - if (!noindent) { - indentation(); - } - r = expression(0, true); - - // Look for the final semicolon. - if (!t.block) { - if (!option.expr && (!r || !r.exps)) { - warning("Expected an assignment or function call and instead saw an expression.", - token); - } else if (option.nonew && r.id === '(' && r.left.id === 'new') { - warning("Do not use 'new' for side effects."); - } - - if (nexttoken.id === ',') { - return comma(); - } - - if (nexttoken.id !== ';') { - if (!option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if (!option.lastsemic || nexttoken.id !== '}' || - nexttoken.line !== token.line) { - warningAt("Missing semicolon.", token.line, token.character); - } - } - } else { - adjacent(token, nexttoken); - advance(';'); - nonadjacent(token, nexttoken); - } - } - -// Restore the indentation. - - indent = i; - scope = s; - return r; - } - - - function statements(startLine) { - var a = [], f, p; - - while (!nexttoken.reach && nexttoken.id !== '(end)') { - if (nexttoken.id === ';') { - p = peek(); - if (!p || p.id !== "(") { - warning("Unnecessary semicolon."); - } - advance(';'); - } else { - a.push(statement(startLine === nexttoken.line)); - } - } - return a; - } - - - /* - * read all directives - * recognizes a simple form of asi, but always - * warns, if it is used - */ - function directives() { - var i, p, pn; - - for (;;) { - if (nexttoken.id === "(string)") { - p = peek(0); - if (p.id === "(endline)") { - i = 1; - do { - pn = peek(i); - i = i + 1; - } while (pn.id === "(endline)"); - - if (pn.id !== ";") { - if (pn.id !== "(string)" && pn.id !== "(number)" && - pn.id !== "(regexp)" && pn.identifier !== true && - pn.id !== "}") { - break; - } - warning("Missing semicolon.", nexttoken); - } else { - p = pn; - } - } else if (p.id === "}") { - // directive with no other statements, warn about missing semicolon - warning("Missing semicolon.", p); - } else if (p.id !== ";") { - break; - } - - indentation(); - advance(); - if (directive[token.value]) { - warning("Unnecessary directive \"{a}\".", token, token.value); - } - - if (token.value === "use strict") { - option.newcap = true; - option.undef = true; - } - - // there's no directive negation, so always set to true - directive[token.value] = true; - - if (p.id === ";") { - advance(";"); - } - continue; - } - break; - } - } - - - /* - * Parses a single block. A block is a sequence of statements wrapped in - * braces. - * - * ordinary - true for everything but function bodies and try blocks. - * stmt - true if block can be a single statement (e.g. in if/for/while). - * isfunc - true if block is a function body - */ - function block(ordinary, stmt, isfunc) { - var a, - b = inblock, - old_indent = indent, - m, - s = scope, - t, - line, - d; - - inblock = ordinary; - if (!ordinary || !option.funcscope) scope = Object.create(scope); - nonadjacent(token, nexttoken); - t = nexttoken; - - if (nexttoken.id === '{') { - advance('{'); - line = token.line; - if (nexttoken.id !== '}') { - indent += option.indent; - while (!ordinary && nexttoken.from > indent) { - indent += option.indent; - } - - if (isfunc) { - m = {}; - for (d in directive) { - if (is_own(directive, d)) { - m[d] = directive[d]; - } - } - directives(); - - if (option.strict && funct['(context)']['(global)']) { - if (!m["use strict"] && !directive["use strict"]) { - warning("Missing \"use strict\" statement."); - } - } - } - - a = statements(line); - - if (isfunc) { - directive = m; - } - - indent -= option.indent; - if (line !== nexttoken.line) { - indentation(); - } - } else if (line !== nexttoken.line) { - indentation(); - } - advance('}', t); - indent = old_indent; - } else if (!ordinary) { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, '{', nexttoken.value); - } else { - if (!stmt || option.curly) - warning("Expected '{a}' and instead saw '{b}'.", - nexttoken, '{', nexttoken.value); - - noreach = true; - indent += option.indent; - // test indentation only if statement is in new line - a = [statement(nexttoken.line === token.line)]; - indent -= option.indent; - noreach = false; - } - funct['(verb)'] = null; - if (!ordinary || !option.funcscope) scope = s; - inblock = b; - if (ordinary && option.noempty && (!a || a.length === 0)) { - warning("Empty block."); - } - return a; - } - - - function countMember(m) { - if (membersOnly && typeof membersOnly[m] !== 'boolean') { - warning("Unexpected /*member '{a}'.", token, m); - } - if (typeof member[m] === 'number') { - member[m] += 1; - } else { - member[m] = 1; - } - } - - - function note_implied(token) { - var name = token.value, line = token.line, a = implied[name]; - if (typeof a === 'function') { - a = false; - } - - if (!a) { - a = [line]; - implied[name] = a; - } else if (a[a.length - 1] !== line) { - a.push(line); - } - } - - - // Build the syntax table by declaring the syntactic elements of the language. - - type('(number)', function () { - return this; - }); - - type('(string)', function () { - return this; - }); - - syntax['(identifier)'] = { - type: '(identifier)', - lbp: 0, - identifier: true, - nud: function () { - var v = this.value, - s = scope[v], - f; - - if (typeof s === 'function') { - // Protection against accidental inheritance. - s = undefined; - } else if (typeof s === 'boolean') { - f = funct; - funct = functions[0]; - addlabel(v, 'var'); - s = funct; - funct = f; - } - - // The name is in scope and defined in the current function. - if (funct === s) { - // Change 'unused' to 'var', and reject labels. - switch (funct[v]) { - case 'unused': - funct[v] = 'var'; - break; - case 'unction': - funct[v] = 'function'; - this['function'] = true; - break; - case 'function': - this['function'] = true; - break; - case 'label': - warning("'{a}' is a statement label.", token, v); - break; - } - } else if (funct['(global)']) { - // The name is not defined in the function. If we are in the global - // scope, then we have an undefined variable. - // - // Operators typeof and delete do not raise runtime errors even if - // the base object of a reference is null so no need to display warning - // if we're inside of typeof or delete. - - if (option.undef && typeof predefined[v] !== 'boolean') { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === 'typeof' || anonname === 'delete') || - (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) { - - isundef(funct, "'{a}' is not defined.", token, v); - } - } - note_implied(token); - } else { - // If the name is already defined in the current - // function, but not as outer, then there is a scope error. - - switch (funct[v]) { - case 'closure': - case 'function': - case 'var': - case 'unused': - warning("'{a}' used out of scope.", token, v); - break; - case 'label': - warning("'{a}' is a statement label.", token, v); - break; - case 'outer': - case 'global': - break; - default: - // If the name is defined in an outer function, make an outer entry, - // and if it was unused, make it var. - if (s === true) { - funct[v] = true; - } else if (s === null) { - warning("'{a}' is not allowed.", token, v); - note_implied(token); - } else if (typeof s !== 'object') { - // Operators typeof and delete do not raise runtime errors even - // if the base object of a reference is null so no need to - // display warning if we're inside of typeof or delete. - if (option.undef) { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === 'typeof' || anonname === 'delete') || - (nexttoken && - (nexttoken.value === '.' || nexttoken.value === '['))) { - - isundef(funct, "'{a}' is not defined.", token, v); - } - } - funct[v] = true; - note_implied(token); - } else { - switch (s[v]) { - case 'function': - case 'unction': - this['function'] = true; - s[v] = 'closure'; - funct[v] = s['(global)'] ? 'global' : 'outer'; - break; - case 'var': - case 'unused': - s[v] = 'closure'; - funct[v] = s['(global)'] ? 'global' : 'outer'; - break; - case 'closure': - case 'parameter': - funct[v] = s['(global)'] ? 'global' : 'outer'; - break; - case 'label': - warning("'{a}' is a statement label.", token, v); - } - } - } - } - return this; - }, - led: function () { - error("Expected an operator and instead saw '{a}'.", - nexttoken, nexttoken.value); - } - }; - - type('(regexp)', function () { - return this; - }); - - -// ECMAScript parser - - delim('(endline)'); - delim('(begin)'); - delim('(end)').reach = true; - delim(''); - delim('(error)').reach = true; - delim('}').reach = true; - delim(')'); - delim(']'); - delim('"').reach = true; - delim("'").reach = true; - delim(';'); - delim(':').reach = true; - delim(','); - delim('#'); - delim('@'); - reserve('else'); - reserve('case').reach = true; - reserve('catch'); - reserve('default').reach = true; - reserve('finally'); - reservevar('arguments', function (x) { - if (directive['use strict'] && funct['(global)']) { - warning("Strict violation.", x); - } - }); - reservevar('eval'); - reservevar('false'); - reservevar('Infinity'); - reservevar('NaN'); - reservevar('null'); - reservevar('this', function (x) { - if (directive['use strict'] && !option.validthis && ((funct['(statement)'] && - funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) { - warning("Possible strict violation.", x); - } - }); - reservevar('true'); - reservevar('undefined'); - assignop('=', 'assign', 20); - assignop('+=', 'assignadd', 20); - assignop('-=', 'assignsub', 20); - assignop('*=', 'assignmult', 20); - assignop('/=', 'assigndiv', 20).nud = function () { - error("A regular expression literal can be confused with '/='."); - }; - assignop('%=', 'assignmod', 20); - bitwiseassignop('&=', 'assignbitand', 20); - bitwiseassignop('|=', 'assignbitor', 20); - bitwiseassignop('^=', 'assignbitxor', 20); - bitwiseassignop('<<=', 'assignshiftleft', 20); - bitwiseassignop('>>=', 'assignshiftright', 20); - bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20); - infix('?', function (left, that) { - that.left = left; - that.right = expression(10); - advance(':'); - that['else'] = expression(10); - return that; - }, 30); - - infix('||', 'or', 40); - infix('&&', 'and', 50); - bitwise('|', 'bitor', 70); - bitwise('^', 'bitxor', 80); - bitwise('&', 'bitand', 90); - relation('==', function (left, right) { - var eqnull = option.eqnull && (left.value === 'null' || right.value === 'null'); - - if (!eqnull && option.eqeqeq) - warning("Expected '{a}' and instead saw '{b}'.", this, '===', '=='); - else if (isPoorRelation(left)) - warning("Use '{a}' to compare with '{b}'.", this, '===', left.value); - else if (isPoorRelation(right)) - warning("Use '{a}' to compare with '{b}'.", this, '===', right.value); - - return this; - }); - relation('==='); - relation('!=', function (left, right) { - var eqnull = option.eqnull && - (left.value === 'null' || right.value === 'null'); - - if (!eqnull && option.eqeqeq) { - warning("Expected '{a}' and instead saw '{b}'.", - this, '!==', '!='); - } else if (isPoorRelation(left)) { - warning("Use '{a}' to compare with '{b}'.", - this, '!==', left.value); - } else if (isPoorRelation(right)) { - warning("Use '{a}' to compare with '{b}'.", - this, '!==', right.value); - } - return this; - }); - relation('!=='); - relation('<'); - relation('>'); - relation('<='); - relation('>='); - bitwise('<<', 'shiftleft', 120); - bitwise('>>', 'shiftright', 120); - bitwise('>>>', 'shiftrightunsigned', 120); - infix('in', 'in', 120); - infix('instanceof', 'instanceof', 120); - infix('+', function (left, that) { - var right = expression(130); - if (left && right && left.id === '(string)' && right.id === '(string)') { - left.value += right.value; - left.character = right.character; - if (!option.scripturl && jx.test(left.value)) { - warning("JavaScript URL.", left); - } - return left; - } - that.left = left; - that.right = right; - return that; - }, 130); - prefix('+', 'num'); - prefix('+++', function () { - warning("Confusing pluses."); - this.right = expression(150); - this.arity = 'unary'; - return this; - }); - infix('+++', function (left) { - warning("Confusing pluses."); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix('-', 'sub', 130); - prefix('-', 'neg'); - prefix('---', function () { - warning("Confusing minuses."); - this.right = expression(150); - this.arity = 'unary'; - return this; - }); - infix('---', function (left) { - warning("Confusing minuses."); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix('*', 'mult', 140); - infix('/', 'div', 140); - infix('%', 'mod', 140); - - suffix('++', 'postinc'); - prefix('++', 'preinc'); - syntax['++'].exps = true; - - suffix('--', 'postdec'); - prefix('--', 'predec'); - syntax['--'].exps = true; - prefix('delete', function () { - var p = expression(0); - if (!p || (p.id !== '.' && p.id !== '[')) { - warning("Variables should not be deleted."); - } - this.first = p; - return this; - }).exps = true; - - prefix('~', function () { - if (option.bitwise) { - warning("Unexpected '{a}'.", this, '~'); - } - expression(150); - return this; - }); - - prefix('!', function () { - this.right = expression(150); - this.arity = 'unary'; - if (bang[this.right.id] === true) { - warning("Confusing use of '{a}'.", this, '!'); - } - return this; - }); - prefix('typeof', 'typeof'); - prefix('new', function () { - var c = expression(155), i; - if (c && c.id !== 'function') { - if (c.identifier) { - c['new'] = true; - switch (c.value) { - case 'Number': - case 'String': - case 'Boolean': - case 'Math': - case 'JSON': - warning("Do not use {a} as a constructor.", token, c.value); - break; - case 'Function': - if (!option.evil) { - warning("The Function constructor is eval."); - } - break; - case 'Date': - case 'RegExp': - break; - default: - if (c.id !== 'function') { - i = c.value.substr(0, 1); - if (option.newcap && (i < 'A' || i > 'Z')) { - warning("A constructor name should start with an uppercase letter.", - token); - } - } - } - } else { - if (c.id !== '.' && c.id !== '[' && c.id !== '(') { - warning("Bad constructor.", token); - } - } - } else { - if (!option.supernew) - warning("Weird construction. Delete 'new'.", this); - } - adjacent(token, nexttoken); - if (nexttoken.id !== '(' && !option.supernew) { - warning("Missing '()' invoking a constructor."); - } - this.first = c; - return this; - }); - syntax['new'].exps = true; - - prefix('void').exps = true; - - infix('.', function (left, that) { - adjacent(prevtoken, token); - nobreak(); - var m = identifier(); - if (typeof m === 'string') { - countMember(m); - } - that.left = left; - that.right = m; - if (left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) { - if (option.noarg) - warning("Avoid arguments.{a}.", left, m); - else if (directive['use strict']) - error('Strict violation.'); - } else if (!option.evil && left && left.value === 'document' && - (m === 'write' || m === 'writeln')) { - warning("document.write can be a form of eval.", left); - } - if (!option.evil && (m === 'eval' || m === 'execScript')) { - warning('eval is evil.'); - } - return that; - }, 160, true); - - infix('(', function (left, that) { - if (prevtoken.id !== '}' && prevtoken.id !== ')') { - nobreak(prevtoken, token); - } - nospace(); - if (option.immed && !left.immed && left.id === 'function') { - warning("Wrap an immediate function invocation in parentheses " + - "to assist the reader in understanding that the expression " + - "is the result of a function, and not the function itself."); - } - var n = 0, - p = []; - if (left) { - if (left.type === '(identifier)') { - if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { - if (left.value !== 'Number' && left.value !== 'String' && - left.value !== 'Boolean' && - left.value !== 'Date') { - if (left.value === 'Math') { - warning("Math is not a function.", left); - } else if (option.newcap) { - warning( -"Missing 'new' prefix when invoking a constructor.", left); - } - } - } - } - } - if (nexttoken.id !== ')') { - for (;;) { - p[p.length] = expression(10); - n += 1; - if (nexttoken.id !== ',') { - break; - } - comma(); - } - } - advance(')'); - nospace(prevtoken, token); - if (typeof left === 'object') { - if (left.value === 'parseInt' && n === 1) { - warning("Missing radix parameter.", left); - } - if (!option.evil) { - if (left.value === 'eval' || left.value === 'Function' || - left.value === 'execScript') { - warning("eval is evil.", left); - } else if (p[0] && p[0].id === '(string)' && - (left.value === 'setTimeout' || - left.value === 'setInterval')) { - warning( - "Implied eval is evil. Pass a function instead of a string.", left); - } - } - if (!left.identifier && left.id !== '.' && left.id !== '[' && - left.id !== '(' && left.id !== '&&' && left.id !== '||' && - left.id !== '?') { - warning("Bad invocation.", left); - } - } - that.left = left; - return that; - }, 155, true).exps = true; - - prefix('(', function () { - nospace(); - if (nexttoken.id === 'function') { - nexttoken.immed = true; - } - var v = expression(0); - advance(')', this); - nospace(prevtoken, token); - if (option.immed && v.id === 'function') { - if (nexttoken.id === '(' || - (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) { - warning( -"Move the invocation into the parens that contain the function.", nexttoken); - } else { - warning( -"Do not wrap function literals in parens unless they are to be immediately invoked.", - this); - } - } - return v; - }); - - infix('[', function (left, that) { - nobreak(prevtoken, token); - nospace(); - var e = expression(0), s; - if (e && e.type === '(string)') { - if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) { - warning("eval is evil.", that); - } - countMember(e.value); - if (!option.sub && ix.test(e.value)) { - s = syntax[e.value]; - if (!s || !s.reserved) { - warning("['{a}'] is better written in dot notation.", - e, e.value); - } - } - } - advance(']', that); - nospace(prevtoken, token); - that.left = left; - that.right = e; - return that; - }, 160, true); - - prefix('[', function () { - var b = token.line !== nexttoken.line; - this.first = []; - if (b) { - indent += option.indent; - if (nexttoken.from === indent + option.indent) { - indent += option.indent; - } - } - while (nexttoken.id !== '(end)') { - while (nexttoken.id === ',') { - warning("Extra comma."); - advance(','); - } - if (nexttoken.id === ']') { - break; - } - if (b && token.line !== nexttoken.line) { - indentation(); - } - this.first.push(expression(10)); - if (nexttoken.id === ',') { - comma(); - if (nexttoken.id === ']' && !option.es5) { - warning("Extra comma.", token); - break; - } - } else { - break; - } - } - if (b) { - indent -= option.indent; - indentation(); - } - advance(']', this); - return this; - }, 160); - - - function property_name() { - var id = optionalidentifier(true); - if (!id) { - if (nexttoken.id === '(string)') { - id = nexttoken.value; - advance(); - } else if (nexttoken.id === '(number)') { - id = nexttoken.value.toString(); - advance(); - } - } - return id; - } - - - function functionparams() { - var i, t = nexttoken, p = []; - advance('('); - nospace(); - if (nexttoken.id === ')') { - advance(')'); - return; - } - for (;;) { - i = identifier(true); - p.push(i); - addlabel(i, 'parameter'); - if (nexttoken.id === ',') { - comma(); - } else { - advance(')', t); - nospace(prevtoken, token); - return p; - } - } - } - - - function doFunction(i, statement) { - var f, - oldOption = option, - oldScope = scope; - - option = Object.create(option); - scope = Object.create(scope); - - funct = { - '(name)' : i || '"' + anonname + '"', - '(line)' : nexttoken.line, - '(context)' : funct, - '(breakage)' : 0, - '(loopage)' : 0, - '(scope)' : scope, - '(statement)': statement - }; - f = funct; - token.funct = funct; - functions.push(funct); - if (i) { - addlabel(i, 'function'); - } - funct['(params)'] = functionparams(); - - block(false, false, true); - scope = oldScope; - option = oldOption; - funct['(last)'] = token.line; - funct = funct['(context)']; - return f; - } - - - (function (x) { - x.nud = function () { - var b, f, i, j, p, t; - var props = {}; // All properties, including accessors - - function saveProperty(name, token) { - if (props[name] && is_own(props, name)) - warning("Duplicate member '{a}'.", nexttoken, i); - else - props[name] = {}; - - props[name].basic = true; - props[name].basicToken = token; - } - - function saveSetter(name, token) { - if (props[name] && is_own(props, name)) { - if (props[name].basic || props[name].setter) - warning("Duplicate member '{a}'.", nexttoken, i); - } else { - props[name] = {}; - } - - props[name].setter = true; - props[name].setterToken = token; - } - - function saveGetter(name) { - if (props[name] && is_own(props, name)) { - if (props[name].basic || props[name].getter) - warning("Duplicate member '{a}'.", nexttoken, i); - } else { - props[name] = {}; - } - - props[name].getter = true; - props[name].getterToken = token; - } - - b = token.line !== nexttoken.line; - if (b) { - indent += option.indent; - if (nexttoken.from === indent + option.indent) { - indent += option.indent; - } - } - for (;;) { - if (nexttoken.id === '}') { - break; - } - if (b) { - indentation(); - } - if (nexttoken.value === 'get' && peek().id !== ':') { - advance('get'); - if (!option.es5) { - error("get/set are ES5 features."); - } - i = property_name(); - if (!i) { - error("Missing property name."); - } - saveGetter(i); - t = nexttoken; - adjacent(token, nexttoken); - f = doFunction(); - p = f['(params)']; - if (p) { - warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i); - } - adjacent(token, nexttoken); - } else if (nexttoken.value === 'set' && peek().id !== ':') { - advance('set'); - if (!option.es5) { - error("get/set are ES5 features."); - } - i = property_name(); - if (!i) { - error("Missing property name."); - } - saveSetter(i, nexttoken); - t = nexttoken; - adjacent(token, nexttoken); - f = doFunction(); - p = f['(params)']; - if (!p || p.length !== 1) { - warning("Expected a single parameter in set {a} function.", t, i); - } - } else { - i = property_name(); - saveProperty(i, nexttoken); - if (typeof i !== 'string') { - break; - } - advance(':'); - nonadjacent(token, nexttoken); - expression(10); - } - - countMember(i); - if (nexttoken.id === ',') { - comma(); - if (nexttoken.id === ',') { - warning("Extra comma.", token); - } else if (nexttoken.id === '}' && !option.es5) { - warning("Extra comma.", token); - } - } else { - break; - } - } - if (b) { - indent -= option.indent; - indentation(); - } - advance('}', this); - - // Check for lonely setters if in the ES5 mode. - if (option.es5) { - for (var name in props) { - if (is_own(props, name) && props[name].setter && !props[name].getter) { - warning("Setter is defined without getter.", props[name].setterToken); - } - } - } - return this; - }; - x.fud = function () { - error("Expected to see a statement and instead saw a block.", token); - }; - }(delim('{'))); - -// This Function is called when esnext option is set to true -// it adds the `const` statement to JSHINT - - useESNextSyntax = function () { - var conststatement = stmt('const', function (prefix) { - var id, name, value; - - this.first = []; - for (;;) { - nonadjacent(token, nexttoken); - id = identifier(); - if (funct[id] === "const") { - warning("const '" + id + "' has already been declared"); - } - if (funct['(global)'] && predefined[id] === false) { - warning("Redefinition of '{a}'.", token, id); - } - addlabel(id, 'const'); - if (prefix) { - break; - } - name = token; - this.first.push(token); - - if (nexttoken.id !== "=") { - warning("const " + - "'{a}' is initialized to 'undefined'.", token, id); - } - - if (nexttoken.id === '=') { - nonadjacent(token, nexttoken); - advance('='); - nonadjacent(token, nexttoken); - if (nexttoken.id === 'undefined') { - warning("It is not necessary to initialize " + - "'{a}' to 'undefined'.", token, id); - } - if (peek(0).id === '=' && nexttoken.identifier) { - error("Constant {a} was not declared correctly.", - nexttoken, nexttoken.value); - } - value = expression(0); - name.first = value; - } - - if (nexttoken.id !== ',') { - break; - } - comma(); - } - return this; - }); - conststatement.exps = true; - }; - - var varstatement = stmt('var', function (prefix) { - // JavaScript does not have block scope. It only has function scope. So, - // declaring a variable in a block can have unexpected consequences. - var id, name, value; - - if (funct['(onevar)'] && option.onevar) { - warning("Too many var statements."); - } else if (!funct['(global)']) { - funct['(onevar)'] = true; - } - this.first = []; - for (;;) { - nonadjacent(token, nexttoken); - id = identifier(); - if (option.esnext && funct[id] === "const") { - warning("const '" + id + "' has already been declared"); - } - if (funct['(global)'] && predefined[id] === false) { - warning("Redefinition of '{a}'.", token, id); - } - addlabel(id, 'unused'); - if (prefix) { - break; - } - name = token; - this.first.push(token); - if (nexttoken.id === '=') { - nonadjacent(token, nexttoken); - advance('='); - nonadjacent(token, nexttoken); - if (nexttoken.id === 'undefined') { - warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id); - } - if (peek(0).id === '=' && nexttoken.identifier) { - error("Variable {a} was not declared correctly.", - nexttoken, nexttoken.value); - } - value = expression(0); - name.first = value; - } - if (nexttoken.id !== ',') { - break; - } - comma(); - } - return this; - }); - varstatement.exps = true; - - blockstmt('function', function () { - if (inblock) { - warning("Function declarations should not be placed in blocks. " + - "Use a function expression or move the statement to the top of " + - "the outer function.", token); - - } - var i = identifier(); - if (option.esnext && funct[i] === "const") { - warning("const '" + i + "' has already been declared"); - } - adjacent(token, nexttoken); - addlabel(i, 'unction'); - doFunction(i, true); - if (nexttoken.id === '(' && nexttoken.line === token.line) { - error( -"Function declarations are not invocable. Wrap the whole function invocation in parens."); - } - return this; - }); - - prefix('function', function () { - var i = optionalidentifier(); - if (i) { - adjacent(token, nexttoken); - } else { - nonadjacent(token, nexttoken); - } - doFunction(i); - if (!option.loopfunc && funct['(loopage)']) { - warning("Don't make functions within a loop."); - } - return this; - }); - - blockstmt('if', function () { - var t = nexttoken; - advance('('); - nonadjacent(this, t); - nospace(); - expression(20); - if (nexttoken.id === '=') { - if (!option.boss) - warning("Expected a conditional expression and instead saw an assignment."); - advance('='); - expression(20); - } - advance(')', t); - nospace(prevtoken, token); - block(true, true); - if (nexttoken.id === 'else') { - nonadjacent(token, nexttoken); - advance('else'); - if (nexttoken.id === 'if' || nexttoken.id === 'switch') { - statement(true); - } else { - block(true, true); - } - } - return this; - }); - - blockstmt('try', function () { - var b, e, s; - - block(false); - if (nexttoken.id === 'catch') { - advance('catch'); - nonadjacent(token, nexttoken); - advance('('); - s = scope; - scope = Object.create(s); - e = nexttoken.value; - if (nexttoken.type !== '(identifier)') { - warning("Expected an identifier and instead saw '{a}'.", - nexttoken, e); - } else { - addlabel(e, 'exception'); - } - advance(); - advance(')'); - block(false); - b = true; - scope = s; - } - if (nexttoken.id === 'finally') { - advance('finally'); - block(false); - return; - } else if (!b) { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, 'catch', nexttoken.value); - } - return this; - }); - - blockstmt('while', function () { - var t = nexttoken; - funct['(breakage)'] += 1; - funct['(loopage)'] += 1; - advance('('); - nonadjacent(this, t); - nospace(); - expression(20); - if (nexttoken.id === '=') { - if (!option.boss) - warning("Expected a conditional expression and instead saw an assignment."); - advance('='); - expression(20); - } - advance(')', t); - nospace(prevtoken, token); - block(true, true); - funct['(breakage)'] -= 1; - funct['(loopage)'] -= 1; - return this; - }).labelled = true; - - blockstmt('with', function () { - var t = nexttoken; - if (directive['use strict']) { - error("'with' is not allowed in strict mode.", token); - } else if (!option.withstmt) { - warning("Don't use 'with'.", token); - } - - advance('('); - nonadjacent(this, t); - nospace(); - expression(0); - advance(')', t); - nospace(prevtoken, token); - block(true, true); - - return this; - }); - - blockstmt('switch', function () { - var t = nexttoken, - g = false; - funct['(breakage)'] += 1; - advance('('); - nonadjacent(this, t); - nospace(); - this.condition = expression(20); - advance(')', t); - nospace(prevtoken, token); - nonadjacent(token, nexttoken); - t = nexttoken; - advance('{'); - nonadjacent(token, nexttoken); - indent += option.indent; - this.cases = []; - for (;;) { - switch (nexttoken.id) { - case 'case': - switch (funct['(verb)']) { - case 'break': - case 'case': - case 'continue': - case 'return': - case 'switch': - case 'throw': - break; - default: - // You can tell JSHint that you don't use break intentionally by - // adding a comment /* falls through */ on a line just before - // the next `case`. - if (!ft.test(lines[nexttoken.line - 2])) { - warning( - "Expected a 'break' statement before 'case'.", - token); - } - } - indentation(-option.indent); - advance('case'); - this.cases.push(expression(20)); - g = true; - advance(':'); - funct['(verb)'] = 'case'; - break; - case 'default': - switch (funct['(verb)']) { - case 'break': - case 'continue': - case 'return': - case 'throw': - break; - default: - if (!ft.test(lines[nexttoken.line - 2])) { - warning( - "Expected a 'break' statement before 'default'.", - token); - } - } - indentation(-option.indent); - advance('default'); - g = true; - advance(':'); - break; - case '}': - indent -= option.indent; - indentation(); - advance('}', t); - if (this.cases.length === 1 || this.condition.id === 'true' || - this.condition.id === 'false') { - if (!option.onecase) - warning("This 'switch' should be an 'if'.", this); - } - funct['(breakage)'] -= 1; - funct['(verb)'] = undefined; - return; - case '(end)': - error("Missing '{a}'.", nexttoken, '}'); - return; - default: - if (g) { - switch (token.id) { - case ',': - error("Each value should have its own case label."); - return; - case ':': - g = false; - statements(); - break; - default: - error("Missing ':' on a case clause.", token); - return; - } - } else { - if (token.id === ':') { - advance(':'); - error("Unexpected '{a}'.", token, ':'); - statements(); - } else { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, 'case', nexttoken.value); - return; - } - } - } - } - }).labelled = true; - - stmt('debugger', function () { - if (!option.debug) { - warning("All 'debugger' statements should be removed."); - } - return this; - }).exps = true; - - (function () { - var x = stmt('do', function () { - funct['(breakage)'] += 1; - funct['(loopage)'] += 1; - this.first = block(true); - advance('while'); - var t = nexttoken; - nonadjacent(token, t); - advance('('); - nospace(); - expression(20); - if (nexttoken.id === '=') { - if (!option.boss) - warning("Expected a conditional expression and instead saw an assignment."); - advance('='); - expression(20); - } - advance(')', t); - nospace(prevtoken, token); - funct['(breakage)'] -= 1; - funct['(loopage)'] -= 1; - return this; - }); - x.labelled = true; - x.exps = true; - }()); - - blockstmt('for', function () { - var s, t = nexttoken; - funct['(breakage)'] += 1; - funct['(loopage)'] += 1; - advance('('); - nonadjacent(this, t); - nospace(); - if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') { - if (nexttoken.id === 'var') { - advance('var'); - varstatement.fud.call(varstatement, true); - } else { - switch (funct[nexttoken.value]) { - case 'unused': - funct[nexttoken.value] = 'var'; - break; - case 'var': - break; - default: - warning("Bad for in variable '{a}'.", - nexttoken, nexttoken.value); - } - advance(); - } - advance('in'); - expression(20); - advance(')', t); - s = block(true, true); - if (option.forin && s && (s.length > 1 || typeof s[0] !== 'object' || - s[0].value !== 'if')) { - warning("The body of a for in should be wrapped in an if statement to filter " + - "unwanted properties from the prototype.", this); - } - funct['(breakage)'] -= 1; - funct['(loopage)'] -= 1; - return this; - } else { - if (nexttoken.id !== ';') { - if (nexttoken.id === 'var') { - advance('var'); - varstatement.fud.call(varstatement); - } else { - for (;;) { - expression(0, 'for'); - if (nexttoken.id !== ',') { - break; - } - comma(); - } - } - } - nolinebreak(token); - advance(';'); - if (nexttoken.id !== ';') { - expression(20); - if (nexttoken.id === '=') { - if (!option.boss) - warning("Expected a conditional expression and instead saw an assignment."); - advance('='); - expression(20); - } - } - nolinebreak(token); - advance(';'); - if (nexttoken.id === ';') { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, ')', ';'); - } - if (nexttoken.id !== ')') { - for (;;) { - expression(0, 'for'); - if (nexttoken.id !== ',') { - break; - } - comma(); - } - } - advance(')', t); - nospace(prevtoken, token); - block(true, true); - funct['(breakage)'] -= 1; - funct['(loopage)'] -= 1; - return this; - } - }).labelled = true; - - - stmt('break', function () { - var v = nexttoken.value; - - if (funct['(breakage)'] === 0) - warning("Unexpected '{a}'.", nexttoken, this.value); - - if (!option.asi) - nolinebreak(this); - - if (nexttoken.id !== ';') { - if (token.line === nexttoken.line) { - if (funct[v] !== 'label') { - warning("'{a}' is not a statement label.", nexttoken, v); - } else if (scope[v] !== funct) { - warning("'{a}' is out of scope.", nexttoken, v); - } - this.first = nexttoken; - advance(); - } - } - reachable('break'); - return this; - }).exps = true; - - - stmt('continue', function () { - var v = nexttoken.value; - - if (funct['(breakage)'] === 0) - warning("Unexpected '{a}'.", nexttoken, this.value); - - if (!option.asi) - nolinebreak(this); - - if (nexttoken.id !== ';') { - if (token.line === nexttoken.line) { - if (funct[v] !== 'label') { - warning("'{a}' is not a statement label.", nexttoken, v); - } else if (scope[v] !== funct) { - warning("'{a}' is out of scope.", nexttoken, v); - } - this.first = nexttoken; - advance(); - } - } else if (!funct['(loopage)']) { - warning("Unexpected '{a}'.", nexttoken, this.value); - } - reachable('continue'); - return this; - }).exps = true; - - - stmt('return', function () { - if (this.line === nexttoken.line) { - if (nexttoken.id === '(regexp)') - warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator."); - - if (nexttoken.id !== ';' && !nexttoken.reach) { - nonadjacent(token, nexttoken); - if (peek().value === "=" && !option.boss) { - warningAt("Did you mean to return a conditional instead of an assignment?", - token.line, token.character + 1); - } - this.first = expression(0); - } - } else if (!option.asi) { - nolinebreak(this); // always warn (Line breaking error) - } - reachable('return'); - return this; - }).exps = true; - - - stmt('throw', function () { - nolinebreak(this); - nonadjacent(token, nexttoken); - this.first = expression(20); - reachable('throw'); - return this; - }).exps = true; - -// Superfluous reserved words - - reserve('class'); - reserve('const'); - reserve('enum'); - reserve('export'); - reserve('extends'); - reserve('import'); - reserve('super'); - - reserve('let'); - reserve('yield'); - reserve('implements'); - reserve('interface'); - reserve('package'); - reserve('private'); - reserve('protected'); - reserve('public'); - reserve('static'); - - -// Parse JSON - - function jsonValue() { - - function jsonObject() { - var o = {}, t = nexttoken; - advance('{'); - if (nexttoken.id !== '}') { - for (;;) { - if (nexttoken.id === '(end)') { - error("Missing '}' to match '{' from line {a}.", - nexttoken, t.line); - } else if (nexttoken.id === '}') { - warning("Unexpected comma.", token); - break; - } else if (nexttoken.id === ',') { - error("Unexpected comma.", nexttoken); - } else if (nexttoken.id !== '(string)') { - warning("Expected a string and instead saw {a}.", - nexttoken, nexttoken.value); - } - if (o[nexttoken.value] === true) { - warning("Duplicate key '{a}'.", - nexttoken, nexttoken.value); - } else if ((nexttoken.value === '__proto__' && - !option.proto) || (nexttoken.value === '__iterator__' && - !option.iterator)) { - warning("The '{a}' key may produce unexpected results.", - nexttoken, nexttoken.value); - } else { - o[nexttoken.value] = true; - } - advance(); - advance(':'); - jsonValue(); - if (nexttoken.id !== ',') { - break; - } - advance(','); - } - } - advance('}'); - } - - function jsonArray() { - var t = nexttoken; - advance('['); - if (nexttoken.id !== ']') { - for (;;) { - if (nexttoken.id === '(end)') { - error("Missing ']' to match '[' from line {a}.", - nexttoken, t.line); - } else if (nexttoken.id === ']') { - warning("Unexpected comma.", token); - break; - } else if (nexttoken.id === ',') { - error("Unexpected comma.", nexttoken); - } - jsonValue(); - if (nexttoken.id !== ',') { - break; - } - advance(','); - } - } - advance(']'); - } - - switch (nexttoken.id) { - case '{': - jsonObject(); - break; - case '[': - jsonArray(); - break; - case 'true': - case 'false': - case 'null': - case '(number)': - case '(string)': - advance(); - break; - case '-': - advance('-'); - if (token.character !== nexttoken.from) { - warning("Unexpected space after '-'.", token); - } - adjacent(token, nexttoken); - advance('(number)'); - break; - default: - error("Expected a JSON value.", nexttoken); - } - } - - -// The actual JSHINT function itself. - - var itself = function (s, o, g) { - var a, i, k, x, - optionKeys, - newOptionObj = {}; - - JSHINT.errors = []; - JSHINT.undefs = []; - predefined = Object.create(standard); - combine(predefined, g || {}); - if (o) { - a = o.predef; - if (a) { - if (Array.isArray(a)) { - for (i = 0; i < a.length; i += 1) { - predefined[a[i]] = true; - } - } else if (typeof a === 'object') { - k = Object.keys(a); - for (i = 0; i < k.length; i += 1) { - predefined[k[i]] = !!a[k[i]]; - } - } - } - optionKeys = Object.keys(o); - for (x = 0; x < optionKeys.length; x++) { - newOptionObj[optionKeys[x]] = o[optionKeys[x]]; - } - } - - option = newOptionObj; - - option.indent = option.indent || 4; - option.maxerr = option.maxerr || 50; - - tab = ''; - for (i = 0; i < option.indent; i += 1) { - tab += ' '; - } - indent = 1; - global = Object.create(predefined); - scope = global; - funct = { - '(global)': true, - '(name)': '(global)', - '(scope)': scope, - '(breakage)': 0, - '(loopage)': 0 - }; - functions = [funct]; - urls = []; - stack = null; - member = {}; - membersOnly = null; - implied = {}; - inblock = false; - lookahead = []; - jsonmode = false; - warnings = 0; - lex.init(s); - prereg = true; - directive = {}; - - prevtoken = token = nexttoken = syntax['(begin)']; - - // Check options - for (var name in o) { - if (is_own(o, name)) { - checkOption(name, token); - } - } - - assume(); - - // combine the passed globals after we've assumed all our options - combine(predefined, g || {}); - - //reset values - comma.first = true; - quotmark = undefined; - - try { - advance(); - switch (nexttoken.id) { - case '{': - case '[': - option.laxbreak = true; - jsonmode = true; - jsonValue(); - break; - default: - directives(); - if (directive["use strict"] && !option.globalstrict) { - warning("Use the function form of \"use strict\".", prevtoken); - } - - statements(); - } - advance((nexttoken && nexttoken.value !== '.') ? '(end)' : undefined); - - var markDefined = function (name, context) { - do { - if (typeof context[name] === 'string') { - // JSHINT marks unused variables as 'unused' and - // unused function declaration as 'unction'. This - // code changes such instances back 'var' and - // 'closure' so that the code in JSHINT.data() - // doesn't think they're unused. - - if (context[name] === 'unused') - context[name] = 'var'; - else if (context[name] === 'unction') - context[name] = 'closure'; - - return true; - } - - context = context['(context)']; - } while (context); - - return false; - }; - - var clearImplied = function (name, line) { - if (!implied[name]) - return; - - var newImplied = []; - for (var i = 0; i < implied[name].length; i += 1) { - if (implied[name][i] !== line) - newImplied.push(implied[name][i]); - } - - if (newImplied.length === 0) - delete implied[name]; - else - implied[name] = newImplied; - }; - - // Check queued 'x is not defined' instances to see if they're still undefined. - for (i = 0; i < JSHINT.undefs.length; i += 1) { - k = JSHINT.undefs[i].slice(0); - - if (markDefined(k[2].value, k[0])) { - clearImplied(k[2].value, k[2].line); - } else { - warning.apply(warning, k.slice(1)); - } - } - } catch (e) { - if (e) { - var nt = nexttoken || {}; - JSHINT.errors.push({ - raw : e.raw, - reason : e.message, - line : e.line || nt.line, - character : e.character || nt.from - }, null); - } - } - - return JSHINT.errors.length === 0; - }; - - // Data summary. - itself.data = function () { - - var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j, - members = [], n, unused = [], v; - if (itself.errors.length) { - data.errors = itself.errors; - } - - if (jsonmode) { - data.json = true; - } - - for (n in implied) { - if (is_own(implied, n)) { - implieds.push({ - name: n, - line: implied[n] - }); - } - } - if (implieds.length > 0) { - data.implieds = implieds; - } - - if (urls.length > 0) { - data.urls = urls; - } - - globals = Object.keys(scope); - if (globals.length > 0) { - data.globals = globals; - } - for (i = 1; i < functions.length; i += 1) { - f = functions[i]; - fu = {}; - for (j = 0; j < functionicity.length; j += 1) { - fu[functionicity[j]] = []; - } - for (n in f) { - if (is_own(f, n) && n.charAt(0) !== '(') { - v = f[n]; - if (v === 'unction') { - v = 'unused'; - } - if (Array.isArray(fu[v])) { - fu[v].push(n); - if (v === 'unused') { - unused.push({ - name: n, - line: f['(line)'], - 'function': f['(name)'] - }); - } - } - } - } - for (j = 0; j < functionicity.length; j += 1) { - if (fu[functionicity[j]].length === 0) { - delete fu[functionicity[j]]; - } - } - fu.name = f['(name)']; - fu.param = f['(params)']; - fu.line = f['(line)']; - fu.last = f['(last)']; - data.functions.push(fu); - } - - if (unused.length > 0) { - data.unused = unused; - } - - members = []; - for (n in member) { - if (typeof member[n] === 'number') { - data.member = member; - break; - } - } - - return data; - }; - - itself.report = function (option) { - var data = itself.data(); - - var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s; - - function detail(h, array) { - var b, i, singularity; - if (array) { - o.push('
              ' + h + ' '); - array = array.sort(); - for (i = 0; i < array.length; i += 1) { - if (array[i] !== singularity) { - singularity = array[i]; - o.push((b ? ', ' : '') + singularity); - b = true; - } - } - o.push('
              '); - } - } - - - if (data.errors || data.implieds || data.unused) { - err = true; - o.push('
              Error:'); - if (data.errors) { - for (i = 0; i < data.errors.length; i += 1) { - c = data.errors[i]; - if (c) { - e = c.evidence || ''; - o.push('

              Problem' + (isFinite(c.line) ? ' at line ' + - c.line + ' character ' + c.character : '') + - ': ' + c.reason.entityify() + - '

              ' + - (e && (e.length > 80 ? e.slice(0, 77) + '...' : - e).entityify()) + '

              '); - } - } - } - - if (data.implieds) { - s = []; - for (i = 0; i < data.implieds.length; i += 1) { - s[i] = '' + data.implieds[i].name + ' ' + - data.implieds[i].line + ''; - } - o.push('

              Implied global: ' + s.join(', ') + '

              '); - } - - if (data.unused) { - s = []; - for (i = 0; i < data.unused.length; i += 1) { - s[i] = '' + data.unused[i].name + ' ' + - data.unused[i].line + ' ' + - data.unused[i]['function'] + ''; - } - o.push('

              Unused variable: ' + s.join(', ') + '

              '); - } - if (data.json) { - o.push('

              JSON: bad.

              '); - } - o.push('
              '); - } - - if (!option) { - - o.push('
              '); - - if (data.urls) { - detail("URLs
              ", data.urls, '
              '); - } - - if (data.json && !err) { - o.push('

              JSON: good.

              '); - } else if (data.globals) { - o.push('
              Global ' + - data.globals.sort().join(', ') + '
              '); - } else { - o.push('
              No new global variables introduced.
              '); - } - - for (i = 0; i < data.functions.length; i += 1) { - f = data.functions[i]; - - o.push('
              ' + f.line + '-' + - f.last + ' ' + (f.name || '') + '(' + - (f.param ? f.param.join(', ') : '') + ')
              '); - detail('Unused', f.unused); - detail('Closure', f.closure); - detail('Variable', f['var']); - detail('Exception', f.exception); - detail('Outer', f.outer); - detail('Global', f.global); - detail('Label', f.label); - } - - if (data.member) { - a = Object.keys(data.member); - if (a.length) { - a = a.sort(); - m = '
              /*members ';
              -                    l = 10;
              -                    for (i = 0; i < a.length; i += 1) {
              -                        k = a[i];
              -                        n = k.name();
              -                        if (l + n.length > 72) {
              -                            o.push(m + '
              '); - m = ' '; - l = 1; - } - l += n.length + 2; - if (data.member[k] === 1) { - n = '' + n + ''; - } - if (i < a.length - 1) { - n += ', '; - } - m += n; - } - o.push(m + '
              */
              '); - } - o.push('
              '); - } - } - return o.join(''); - }; - - itself.jshint = itself; - - return itself; -}()); - -// Make JSHINT a Node module, if possible. -if (typeof exports === 'object' && exports) - exports.JSHINT = JSHINT; diff --git a/build/vendor/uglify/consolidator.js b/build/vendor/uglify/consolidator.js deleted file mode 100755 index caaed94..0000000 --- a/build/vendor/uglify/consolidator.js +++ /dev/null @@ -1,1220 +0,0 @@ -/** - * @preserve Copyright 2012 Robert Gust-Bardon . - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/** - * @fileoverview Enhances UglifyJS with consolidation of null, Boolean, and String values. - *

              Also known as aliasing, this feature has been deprecated in the Closure Compiler since its - * initial release, where it is unavailable from the CLI. The Closure Compiler allows one to log and - * influence this process. In contrast, this implementation does not introduce - * any variable declarations in global code and derives String values from - * identifier names used as property accessors.

              - *

              Consolidating literals may worsen the data compression ratio when an encoding - * transformation is applied. For instance, jQuery 1.7.1 takes 248235 bytes. - * Building it with - * UglifyJS v1.2.5 results in 93647 bytes (37.73% of the original) which are - * then compressed to 33154 bytes (13.36% of the original) using gzip(1). Building it with the same - * version of UglifyJS 1.2.5 patched with the implementation of consolidation - * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison - * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes - * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned - * 33154 bytes).

              - *

              Written in the strict variant - * of ECMA-262 5.1 Edition. Encoded in UTF-8. Follows Revision 2.28 of the Google JavaScript Style Guide (except for the - * discouraged use of the {@code function} tag and the {@code namespace} tag). - * 100% typed for the Closure Compiler Version 1741.

              - *

              Should you find this software useful, please consider a donation.

              - * @author follow.me@RGustBardon (Robert Gust-Bardon) - * @supported Tested with: - * - */ - -/*global console:false, exports:true, module:false, require:false */ -/*jshint sub:true */ -/** - * Consolidates null, Boolean, and String values found inside an AST. - * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object - * representing an AST. - * @return {!TSyntacticCodeUnit} An array-like object representing an AST with its null, Boolean, and - * String values consolidated. - */ -// TODO(user) Consolidation of mathematical values found in numeric literals. -// TODO(user) Unconsolidation. -// TODO(user) Consolidation of ECMA-262 6th Edition programs. -// TODO(user) Rewrite in ECMA-262 6th Edition. -exports['ast_consolidate'] = function(oAbstractSyntaxTree) { - 'use strict'; - /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true, - latedef:true, newcap:true, noarge:true, noempty:true, nonew:true, - onevar:true, plusplus:true, regexp:true, undef:true, strict:true, - sub:false, trailing:true */ - - var _, - /** - * A record consisting of data about one or more source elements. - * @constructor - * @nosideeffects - */ - TSourceElementsData = function() { - /** - * The category of the elements. - * @type {number} - * @see ESourceElementCategories - */ - this.nCategory = ESourceElementCategories.N_OTHER; - /** - * The number of occurrences (within the elements) of each primitive - * value that could be consolidated. - * @type {!Array.>} - */ - this.aCount = []; - this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {}; - this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {}; - this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] = - {}; - /** - * Identifier names found within the elements. - * @type {!Array.} - */ - this.aIdentifiers = []; - /** - * Prefixed representation Strings of each primitive value that could be - * consolidated within the elements. - * @type {!Array.} - */ - this.aPrimitiveValues = []; - }, - /** - * A record consisting of data about a primitive value that could be - * consolidated. - * @constructor - * @nosideeffects - */ - TPrimitiveValue = function() { - /** - * The difference in the number of terminal symbols between the original - * source text and the one with the primitive value consolidated. If the - * difference is positive, the primitive value is considered worthwhile. - * @type {number} - */ - this.nSaving = 0; - /** - * An identifier name of the variable that will be declared and assigned - * the primitive value if the primitive value is consolidated. - * @type {string} - */ - this.sName = ''; - }, - /** - * A record consisting of data on what to consolidate within the range of - * source elements that is currently being considered. - * @constructor - * @nosideeffects - */ - TSolution = function() { - /** - * An object whose keys are prefixed representation Strings of each - * primitive value that could be consolidated within the elements and - * whose values are corresponding data about those primitive values. - * @type {!Object.} - * @see TPrimitiveValue - */ - this.oPrimitiveValues = {}; - /** - * The difference in the number of terminal symbols between the original - * source text and the one with all the worthwhile primitive values - * consolidated. - * @type {number} - * @see TPrimitiveValue#nSaving - */ - this.nSavings = 0; - }, - /** - * The processor of ASTs found - * in UglifyJS. - * @namespace - * @type {!TProcessor} - */ - oProcessor = (/** @type {!TProcessor} */ require('./process')), - /** - * A record consisting of a number of constants that represent the - * difference in the number of terminal symbols between a source text with - * a modified syntactic code unit and the original one. - * @namespace - * @type {!Object.} - */ - oWeights = { - /** - * The difference in the number of punctuators required by the bracket - * notation and the dot notation. - *

              '[]'.length - '.'.length

              - * @const - * @type {number} - */ - N_PROPERTY_ACCESSOR: 1, - /** - * The number of punctuators required by a variable declaration with an - * initialiser. - *

              ':'.length + ';'.length

              - * @const - * @type {number} - */ - N_VARIABLE_DECLARATION: 2, - /** - * The number of terminal symbols required to introduce a variable - * statement (excluding its variable declaration list). - *

              'var '.length

              - * @const - * @type {number} - */ - N_VARIABLE_STATEMENT_AFFIXATION: 4, - /** - * The number of terminal symbols needed to enclose source elements - * within a function call with no argument values to a function with an - * empty parameter list. - *

              '(function(){}());'.length

              - * @const - * @type {number} - */ - N_CLOSURE: 17 - }, - /** - * Categories of primary expressions from which primitive values that - * could be consolidated are derivable. - * @namespace - * @enum {number} - */ - EPrimaryExpressionCategories = { - /** - * Identifier names used as property accessors. - * @type {number} - */ - N_IDENTIFIER_NAMES: 0, - /** - * String literals. - * @type {number} - */ - N_STRING_LITERALS: 1, - /** - * Null and Boolean literals. - * @type {number} - */ - N_NULL_AND_BOOLEAN_LITERALS: 2 - }, - /** - * Prefixes of primitive values that could be consolidated. - * The String values of the prefixes must have same number of characters. - * The prefixes must not be used in any properties defined in any version - * of ECMA-262. - * @namespace - * @enum {string} - */ - EValuePrefixes = { - /** - * Identifies String values. - * @type {string} - */ - S_STRING: '#S', - /** - * Identifies null and Boolean values. - * @type {string} - */ - S_SYMBOLIC: '#O' - }, - /** - * Categories of source elements in terms of their appropriateness of - * having their primitive values consolidated. - * @namespace - * @enum {number} - */ - ESourceElementCategories = { - /** - * Identifies a source element that includes the {@code with} statement. - * @type {number} - */ - N_WITH: 0, - /** - * Identifies a source element that includes the {@code eval} identifier name. - * @type {number} - */ - N_EVAL: 1, - /** - * Identifies a source element that must be excluded from the process - * unless its whole scope is examined. - * @type {number} - */ - N_EXCLUDABLE: 2, - /** - * Identifies source elements not posing any problems. - * @type {number} - */ - N_OTHER: 3 - }, - /** - * The list of literals (other than the String ones) whose primitive - * values can be consolidated. - * @const - * @type {!Array.} - */ - A_OTHER_SUBSTITUTABLE_LITERALS = [ - 'null', // The null literal. - 'false', // The Boolean literal {@code false}. - 'true' // The Boolean literal {@code true}. - ]; - - (/** - * Consolidates all worthwhile primitive values in a syntactic code unit. - * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object - * representing the branch of the abstract syntax tree representing the - * syntactic code unit along with its scope. - * @see TPrimitiveValue#nSaving - */ - function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) { - var _, - /** - * Indicates whether the syntactic code unit represents global code. - * @type {boolean} - */ - bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0], - /** - * Indicates whether the whole scope is being examined. - * @type {boolean} - */ - bIsWhollyExaminable = !bIsGlobal, - /** - * An array-like object representing source elements that constitute a - * syntactic code unit. - * @type {!TSyntacticCodeUnit} - */ - oSourceElements, - /** - * A record consisting of data about the source element that is - * currently being examined. - * @type {!TSourceElementsData} - */ - oSourceElementData, - /** - * The scope of the syntactic code unit. - * @type {!TScope} - */ - oScope, - /** - * An instance of an object that allows the traversal of an AST. - * @type {!TWalker} - */ - oWalker, - /** - * An object encompassing collections of functions used during the - * traversal of an AST. - * @namespace - * @type {!Object.>} - */ - oWalkers = { - /** - * A collection of functions used during the surveyance of source - * elements. - * @namespace - * @type {!Object.} - */ - oSurveySourceElement: { - /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys. - /** - * Classifies the source element as excludable if it does not - * contain a {@code with} statement or the {@code eval} identifier - * name. Adds the identifier of the function and its formal - * parameters to the list of identifier names found. - * @param {string} sIdentifier The identifier of the function. - * @param {!Array.} aFormalParameterList Formal parameters. - * @param {!TSyntacticCodeUnit} oFunctionBody Function code. - */ - 'defun': function( - sIdentifier, - aFormalParameterList, - oFunctionBody) { - fClassifyAsExcludable(); - fAddIdentifier(sIdentifier); - aFormalParameterList.forEach(fAddIdentifier); - }, - /** - * Increments the count of the number of occurrences of the String - * value that is equivalent to the sequence of terminal symbols - * that constitute the encountered identifier name. - * @param {!TSyntacticCodeUnit} oExpression The nonterminal - * MemberExpression. - * @param {string} sIdentifierName The identifier name used as the - * property accessor. - * @return {!Array} The encountered branch of an AST with its nonterminal - * MemberExpression traversed. - */ - 'dot': function(oExpression, sIdentifierName) { - fCountPrimaryExpression( - EPrimaryExpressionCategories.N_IDENTIFIER_NAMES, - EValuePrefixes.S_STRING + sIdentifierName); - return ['dot', oWalker.walk(oExpression), sIdentifierName]; - }, - /** - * Adds the optional identifier of the function and its formal - * parameters to the list of identifier names found. - * @param {?string} sIdentifier The optional identifier of the - * function. - * @param {!Array.} aFormalParameterList Formal parameters. - * @param {!TSyntacticCodeUnit} oFunctionBody Function code. - */ - 'function': function( - sIdentifier, - aFormalParameterList, - oFunctionBody) { - if ('string' === typeof sIdentifier) { - fAddIdentifier(sIdentifier); - } - aFormalParameterList.forEach(fAddIdentifier); - }, - /** - * Either increments the count of the number of occurrences of the - * encountered null or Boolean value or classifies a source element - * as containing the {@code eval} identifier name. - * @param {string} sIdentifier The identifier encountered. - */ - 'name': function(sIdentifier) { - if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) { - fCountPrimaryExpression( - EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS, - EValuePrefixes.S_SYMBOLIC + sIdentifier); - } else { - if ('eval' === sIdentifier) { - oSourceElementData.nCategory = - ESourceElementCategories.N_EVAL; - } - fAddIdentifier(sIdentifier); - } - }, - /** - * Classifies the source element as excludable if it does not - * contain a {@code with} statement or the {@code eval} identifier - * name. - * @param {TSyntacticCodeUnit} oExpression The expression whose - * value is to be returned. - */ - 'return': function(oExpression) { - fClassifyAsExcludable(); - }, - /** - * Increments the count of the number of occurrences of the - * encountered String value. - * @param {string} sStringValue The String value of the string - * literal encountered. - */ - 'string': function(sStringValue) { - if (sStringValue.length > 0) { - fCountPrimaryExpression( - EPrimaryExpressionCategories.N_STRING_LITERALS, - EValuePrefixes.S_STRING + sStringValue); - } - }, - /** - * Adds the identifier reserved for an exception to the list of - * identifier names found. - * @param {!TSyntacticCodeUnit} oTry A block of code in which an - * exception can occur. - * @param {Array} aCatch The identifier reserved for an exception - * and a block of code to handle the exception. - * @param {TSyntacticCodeUnit} oFinally An optional block of code - * to be evaluated regardless of whether an exception occurs. - */ - 'try': function(oTry, aCatch, oFinally) { - if (Array.isArray(aCatch)) { - fAddIdentifier(aCatch[0]); - } - }, - /** - * Classifies the source element as excludable if it does not - * contain a {@code with} statement or the {@code eval} identifier - * name. Adds the identifier of each declared variable to the list - * of identifier names found. - * @param {!Array.} aVariableDeclarationList Variable - * declarations. - */ - 'var': function(aVariableDeclarationList) { - fClassifyAsExcludable(); - aVariableDeclarationList.forEach(fAddVariable); - }, - /** - * Classifies a source element as containing the {@code with} - * statement. - * @param {!TSyntacticCodeUnit} oExpression An expression whose - * value is to be converted to a value of type Object and - * become the binding object of a new object environment - * record of a new lexical environment in which the statement - * is to be executed. - * @param {!TSyntacticCodeUnit} oStatement The statement to be - * executed in the augmented lexical environment. - * @return {!Array} An empty array to stop the traversal. - */ - 'with': function(oExpression, oStatement) { - oSourceElementData.nCategory = ESourceElementCategories.N_WITH; - return []; - } - /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys. - }, - /** - * A collection of functions used while looking for nested functions. - * @namespace - * @type {!Object.} - */ - oExamineFunctions: { - /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys. - /** - * Orders an examination of a nested function declaration. - * @this {!TSyntacticCodeUnit} An array-like object representing - * the branch of an AST representing the syntactic code unit along with - * its scope. - * @return {!Array} An empty array to stop the traversal. - */ - 'defun': function() { - fExamineSyntacticCodeUnit(this); - return []; - }, - /** - * Orders an examination of a nested function expression. - * @this {!TSyntacticCodeUnit} An array-like object representing - * the branch of an AST representing the syntactic code unit along with - * its scope. - * @return {!Array} An empty array to stop the traversal. - */ - 'function': function() { - fExamineSyntacticCodeUnit(this); - return []; - } - /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys. - } - }, - /** - * Records containing data about source elements. - * @type {Array.} - */ - aSourceElementsData = [], - /** - * The index (in the source text order) of the source element - * immediately following a Directive Prologue. - * @type {number} - */ - nAfterDirectivePrologue = 0, - /** - * The index (in the source text order) of the source element that is - * currently being considered. - * @type {number} - */ - nPosition, - /** - * The index (in the source text order) of the source element that is - * the last element of the range of source elements that is currently - * being considered. - * @type {(undefined|number)} - */ - nTo, - /** - * Initiates the traversal of a source element. - * @param {!TWalker} oWalker An instance of an object that allows the - * traversal of an abstract syntax tree. - * @param {!TSyntacticCodeUnit} oSourceElement A source element from - * which the traversal should commence. - * @return {function(): !TSyntacticCodeUnit} A function that is able to - * initiate the traversal from a given source element. - */ - cContext = function(oWalker, oSourceElement) { - /** - * @return {!TSyntacticCodeUnit} A function that is able to - * initiate the traversal from a given source element. - */ - var fLambda = function() { - return oWalker.walk(oSourceElement); - }; - - return fLambda; - }, - /** - * Classifies the source element as excludable if it does not - * contain a {@code with} statement or the {@code eval} identifier - * name. - */ - fClassifyAsExcludable = function() { - if (oSourceElementData.nCategory === - ESourceElementCategories.N_OTHER) { - oSourceElementData.nCategory = - ESourceElementCategories.N_EXCLUDABLE; - } - }, - /** - * Adds an identifier to the list of identifier names found. - * @param {string} sIdentifier The identifier to be added. - */ - fAddIdentifier = function(sIdentifier) { - if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) { - oSourceElementData.aIdentifiers.push(sIdentifier); - } - }, - /** - * Adds the identifier of a variable to the list of identifier names - * found. - * @param {!Array} aVariableDeclaration A variable declaration. - */ - fAddVariable = function(aVariableDeclaration) { - fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]); - }, - /** - * Increments the count of the number of occurrences of the prefixed - * String representation attributed to the primary expression. - * @param {number} nCategory The category of the primary expression. - * @param {string} sName The prefixed String representation attributed - * to the primary expression. - */ - fCountPrimaryExpression = function(nCategory, sName) { - if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) { - oSourceElementData.aCount[nCategory][sName] = 0; - if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) { - oSourceElementData.aPrimitiveValues.push(sName); - } - } - oSourceElementData.aCount[nCategory][sName] += 1; - }, - /** - * Consolidates all worthwhile primitive values in a range of source - * elements. - * @param {number} nFrom The index (in the source text order) of the - * source element that is the first element of the range. - * @param {number} nTo The index (in the source text order) of the - * source element that is the last element of the range. - * @param {boolean} bEnclose Indicates whether the range should be - * enclosed within a function call with no argument values to a - * function with an empty parameter list if any primitive values - * are consolidated. - * @see TPrimitiveValue#nSaving - */ - fExamineSourceElements = function(nFrom, nTo, bEnclose) { - var _, - /** - * The index of the last mangled name. - * @type {number} - */ - nIndex = oScope.cname, - /** - * The index of the source element that is currently being - * considered. - * @type {number} - */ - nPosition, - /** - * A collection of functions used during the consolidation of - * primitive values and identifier names used as property - * accessors. - * @namespace - * @type {!Object.} - */ - oWalkersTransformers = { - /** - * If the String value that is equivalent to the sequence of - * terminal symbols that constitute the encountered identifier - * name is worthwhile, a syntactic conversion from the dot - * notation to the bracket notation ensues with that sequence - * being substituted by an identifier name to which the value - * is assigned. - * Applies to property accessors that use the dot notation. - * @param {!TSyntacticCodeUnit} oExpression The nonterminal - * MemberExpression. - * @param {string} sIdentifierName The identifier name used as - * the property accessor. - * @return {!Array} A syntactic code unit that is equivalent to - * the one encountered. - * @see TPrimitiveValue#nSaving - */ - 'dot': function(oExpression, sIdentifierName) { - /** - * The prefixed String value that is equivalent to the - * sequence of terminal symbols that constitute the - * encountered identifier name. - * @type {string} - */ - var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName; - - return oSolutionBest.oPrimitiveValues.hasOwnProperty( - sPrefixed) && - oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? - ['sub', - oWalker.walk(oExpression), - ['name', - oSolutionBest.oPrimitiveValues[sPrefixed].sName]] : - ['dot', oWalker.walk(oExpression), sIdentifierName]; - }, - /** - * If the encountered identifier is a null or Boolean literal - * and its value is worthwhile, the identifier is substituted - * by an identifier name to which that value is assigned. - * Applies to identifier names. - * @param {string} sIdentifier The identifier encountered. - * @return {!Array} A syntactic code unit that is equivalent to - * the one encountered. - * @see TPrimitiveValue#nSaving - */ - 'name': function(sIdentifier) { - /** - * The prefixed representation String of the identifier. - * @type {string} - */ - var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier; - - return [ - 'name', - oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) && - oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? - oSolutionBest.oPrimitiveValues[sPrefixed].sName : - sIdentifier - ]; - }, - /** - * If the encountered String value is worthwhile, it is - * substituted by an identifier name to which that value is - * assigned. - * Applies to String values. - * @param {string} sStringValue The String value of the string - * literal encountered. - * @return {!Array} A syntactic code unit that is equivalent to - * the one encountered. - * @see TPrimitiveValue#nSaving - */ - 'string': function(sStringValue) { - /** - * The prefixed representation String of the primitive value - * of the literal. - * @type {string} - */ - var sPrefixed = - EValuePrefixes.S_STRING + sStringValue; - - return oSolutionBest.oPrimitiveValues.hasOwnProperty( - sPrefixed) && - oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ? - ['name', - oSolutionBest.oPrimitiveValues[sPrefixed].sName] : - ['string', sStringValue]; - } - }, - /** - * Such data on what to consolidate within the range of source - * elements that is currently being considered that lead to the - * greatest known reduction of the number of the terminal symbols - * in comparison to the original source text. - * @type {!TSolution} - */ - oSolutionBest = new TSolution(), - /** - * Data representing an ongoing attempt to find a better - * reduction of the number of the terminal symbols in comparison - * to the original source text than the best one that is - * currently known. - * @type {!TSolution} - * @see oSolutionBest - */ - oSolutionCandidate = new TSolution(), - /** - * A record consisting of data about the range of source elements - * that is currently being examined. - * @type {!TSourceElementsData} - */ - oSourceElementsData = new TSourceElementsData(), - /** - * Variable declarations for each primitive value that is to be - * consolidated within the elements. - * @type {!Array.} - */ - aVariableDeclarations = [], - /** - * Augments a list with a prefixed representation String. - * @param {!Array.} aList A list that is to be augmented. - * @return {function(string)} A function that augments a list - * with a prefixed representation String. - */ - cAugmentList = function(aList) { - /** - * @param {string} sPrefixed Prefixed representation String of - * a primitive value that could be consolidated within the - * elements. - */ - var fLambda = function(sPrefixed) { - if (-1 === aList.indexOf(sPrefixed)) { - aList.push(sPrefixed); - } - }; - - return fLambda; - }, - /** - * Adds the number of occurrences of a primitive value of a given - * category that could be consolidated in the source element with - * a given index to the count of occurrences of that primitive - * value within the range of source elements that is currently - * being considered. - * @param {number} nPosition The index (in the source text order) - * of a source element. - * @param {number} nCategory The category of the primary - * expression from which the primitive value is derived. - * @return {function(string)} A function that performs the - * addition. - * @see cAddOccurrencesInCategory - */ - cAddOccurrences = function(nPosition, nCategory) { - /** - * @param {string} sPrefixed The prefixed representation String - * of a primitive value. - */ - var fLambda = function(sPrefixed) { - if (!oSourceElementsData.aCount[nCategory].hasOwnProperty( - sPrefixed)) { - oSourceElementsData.aCount[nCategory][sPrefixed] = 0; - } - oSourceElementsData.aCount[nCategory][sPrefixed] += - aSourceElementsData[nPosition].aCount[nCategory][ - sPrefixed]; - }; - - return fLambda; - }, - /** - * Adds the number of occurrences of each primitive value of a - * given category that could be consolidated in the source - * element with a given index to the count of occurrences of that - * primitive values within the range of source elements that is - * currently being considered. - * @param {number} nPosition The index (in the source text order) - * of a source element. - * @return {function(number)} A function that performs the - * addition. - * @see fAddOccurrences - */ - cAddOccurrencesInCategory = function(nPosition) { - /** - * @param {number} nCategory The category of the primary - * expression from which the primitive value is derived. - */ - var fLambda = function(nCategory) { - Object.keys( - aSourceElementsData[nPosition].aCount[nCategory] - ).forEach(cAddOccurrences(nPosition, nCategory)); - }; - - return fLambda; - }, - /** - * Adds the number of occurrences of each primitive value that - * could be consolidated in the source element with a given index - * to the count of occurrences of that primitive values within - * the range of source elements that is currently being - * considered. - * @param {number} nPosition The index (in the source text order) - * of a source element. - */ - fAddOccurrences = function(nPosition) { - Object.keys(aSourceElementsData[nPosition].aCount).forEach( - cAddOccurrencesInCategory(nPosition)); - }, - /** - * Creates a variable declaration for a primitive value if that - * primitive value is to be consolidated within the elements. - * @param {string} sPrefixed Prefixed representation String of a - * primitive value that could be consolidated within the - * elements. - * @see aVariableDeclarations - */ - cAugmentVariableDeclarations = function(sPrefixed) { - if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) { - aVariableDeclarations.push([ - oSolutionBest.oPrimitiveValues[sPrefixed].sName, - [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ? - 'name' : 'string', - sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)] - ]); - } - }, - /** - * Sorts primitive values with regard to the difference in the - * number of terminal symbols between the original source text - * and the one with those primitive values consolidated. - * @param {string} sPrefixed0 The prefixed representation String - * of the first of the two primitive values that are being - * compared. - * @param {string} sPrefixed1 The prefixed representation String - * of the second of the two primitive values that are being - * compared. - * @return {number} - *
              - *
              -1
              - *
              if the first primitive value must be placed before - * the other one,
              - *
              0
              - *
              if the first primitive value may be placed before - * the other one,
              - *
              1
              - *
              if the first primitive value must not be placed - * before the other one.
              - *
              - * @see TSolution.oPrimitiveValues - */ - cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) { - /** - * The difference between: - *
                - *
              1. the difference in the number of terminal symbols - * between the original source text and the one with the - * first primitive value consolidated, and
              2. - *
              3. the difference in the number of terminal symbols - * between the original source text and the one with the - * second primitive value consolidated.
              4. - *
              - * @type {number} - */ - var nDifference = - oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving - - oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving; - - return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0; - }, - /** - * Assigns an identifier name to a primitive value and calculates - * whether instances of that primitive value are worth - * consolidating. - * @param {string} sPrefixed The prefixed representation String - * of a primitive value that is being evaluated. - */ - fEvaluatePrimitiveValue = function(sPrefixed) { - var _, - /** - * The index of the last mangled name. - * @type {number} - */ - nIndex, - /** - * The representation String of the primitive value that is - * being evaluated. - * @type {string} - */ - sName = - sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length), - /** - * The number of source characters taken up by the - * representation String of the primitive value that is - * being evaluated. - * @type {number} - */ - nLengthOriginal = sName.length, - /** - * The number of source characters taken up by the - * identifier name that could substitute the primitive - * value that is being evaluated. - * substituted. - * @type {number} - */ - nLengthSubstitution, - /** - * The number of source characters taken up by by the - * representation String of the primitive value that is - * being evaluated when it is represented by a string - * literal. - * @type {number} - */ - nLengthString = oProcessor.make_string(sName).length; - - oSolutionCandidate.oPrimitiveValues[sPrefixed] = - new TPrimitiveValue(); - do { // Find an identifier unused in this or any nested scope. - nIndex = oScope.cname; - oSolutionCandidate.oPrimitiveValues[sPrefixed].sName = - oScope.next_mangled(); - } while (-1 !== oSourceElementsData.aIdentifiers.indexOf( - oSolutionCandidate.oPrimitiveValues[sPrefixed].sName)); - nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[ - sPrefixed].sName.length; - if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) { - // foo:null, or foo:null; - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -= - nLengthSubstitution + nLengthOriginal + - oWeights.N_VARIABLE_DECLARATION; - // null vs foo - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += - oSourceElementsData.aCount[ - EPrimaryExpressionCategories. - N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] * - (nLengthOriginal - nLengthSubstitution); - } else { - // foo:'fromCharCode'; - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -= - nLengthSubstitution + nLengthString + - oWeights.N_VARIABLE_DECLARATION; - // .fromCharCode vs [foo] - if (oSourceElementsData.aCount[ - EPrimaryExpressionCategories.N_IDENTIFIER_NAMES - ].hasOwnProperty(sPrefixed)) { - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += - oSourceElementsData.aCount[ - EPrimaryExpressionCategories.N_IDENTIFIER_NAMES - ][sPrefixed] * - (nLengthOriginal - nLengthSubstitution - - oWeights.N_PROPERTY_ACCESSOR); - } - // 'fromCharCode' vs foo - if (oSourceElementsData.aCount[ - EPrimaryExpressionCategories.N_STRING_LITERALS - ].hasOwnProperty(sPrefixed)) { - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving += - oSourceElementsData.aCount[ - EPrimaryExpressionCategories.N_STRING_LITERALS - ][sPrefixed] * - (nLengthString - nLengthSubstitution); - } - } - if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving > - 0) { - oSolutionCandidate.nSavings += - oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving; - } else { - oScope.cname = nIndex; // Free the identifier name. - } - }, - /** - * Adds a variable declaration to an existing variable statement. - * @param {!Array} aVariableDeclaration A variable declaration - * with an initialiser. - */ - cAddVariableDeclaration = function(aVariableDeclaration) { - (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift( - aVariableDeclaration); - }; - - if (nFrom > nTo) { - return; - } - // If the range is a closure, reuse the closure. - if (nFrom === nTo && - 'stat' === oSourceElements[nFrom][0] && - 'call' === oSourceElements[nFrom][1][0] && - 'function' === oSourceElements[nFrom][1][1][0]) { - fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]); - return; - } - // Create a list of all derived primitive values within the range. - for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { - aSourceElementsData[nPosition].aPrimitiveValues.forEach( - cAugmentList(oSourceElementsData.aPrimitiveValues)); - } - if (0 === oSourceElementsData.aPrimitiveValues.length) { - return; - } - for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { - // Add the number of occurrences to the total count. - fAddOccurrences(nPosition); - // Add identifiers of this or any nested scope to the list. - aSourceElementsData[nPosition].aIdentifiers.forEach( - cAugmentList(oSourceElementsData.aIdentifiers)); - } - // Distribute identifier names among derived primitive values. - do { // If there was any progress, find a better distribution. - oSolutionBest = oSolutionCandidate; - if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) { - // Sort primitive values descending by their worthwhileness. - oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues); - } - oSolutionCandidate = new TSolution(); - oSourceElementsData.aPrimitiveValues.forEach( - fEvaluatePrimitiveValue); - oScope.cname = nIndex; - } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings); - // Take the necessity of adding a variable statement into account. - if ('var' !== oSourceElements[nFrom][0]) { - oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION; - } - if (bEnclose) { - // Take the necessity of forming a closure into account. - oSolutionBest.nSavings -= oWeights.N_CLOSURE; - } - if (oSolutionBest.nSavings > 0) { - // Create variable declarations suitable for UglifyJS. - Object.keys(oSolutionBest.oPrimitiveValues).forEach( - cAugmentVariableDeclarations); - // Rewrite expressions that contain worthwhile primitive values. - for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) { - oWalker = oProcessor.ast_walker(); - oSourceElements[nPosition] = - oWalker.with_walkers( - oWalkersTransformers, - cContext(oWalker, oSourceElements[nPosition])); - } - if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement. - (/** @type {!Array.} */ aVariableDeclarations.reverse( - )).forEach(cAddVariableDeclaration); - } else { // Add a variable statement. - Array.prototype.splice.call( - oSourceElements, - nFrom, - 0, - ['var', aVariableDeclarations]); - nTo += 1; - } - if (bEnclose) { - // Add a closure. - Array.prototype.splice.call( - oSourceElements, - nFrom, - 0, - ['stat', ['call', ['function', null, [], []], []]]); - // Copy source elements into the closure. - for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) { - Array.prototype.unshift.call( - oSourceElements[nFrom][1][1][3], - oSourceElements[nPosition]); - } - // Remove source elements outside the closure. - Array.prototype.splice.call( - oSourceElements, - nFrom + 1, - nTo - nFrom + 1); - } - } - if (bEnclose) { - // Restore the availability of identifier names. - oScope.cname = nIndex; - } - }; - - oSourceElements = (/** @type {!TSyntacticCodeUnit} */ - oSyntacticCodeUnit[bIsGlobal ? 1 : 3]); - if (0 === oSourceElements.length) { - return; - } - oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope; - // Skip a Directive Prologue. - while (nAfterDirectivePrologue < oSourceElements.length && - 'directive' === oSourceElements[nAfterDirectivePrologue][0]) { - nAfterDirectivePrologue += 1; - aSourceElementsData.push(null); - } - if (oSourceElements.length === nAfterDirectivePrologue) { - return; - } - for (nPosition = nAfterDirectivePrologue; - nPosition < oSourceElements.length; - nPosition += 1) { - oSourceElementData = new TSourceElementsData(); - oWalker = oProcessor.ast_walker(); - // Classify a source element. - // Find its derived primitive values and count their occurrences. - // Find all identifiers used (including nested scopes). - oWalker.with_walkers( - oWalkers.oSurveySourceElement, - cContext(oWalker, oSourceElements[nPosition])); - // Establish whether the scope is still wholly examinable. - bIsWhollyExaminable = bIsWhollyExaminable && - ESourceElementCategories.N_WITH !== oSourceElementData.nCategory && - ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory; - aSourceElementsData.push(oSourceElementData); - } - if (bIsWhollyExaminable) { // Examine the whole scope. - fExamineSourceElements( - nAfterDirectivePrologue, - oSourceElements.length - 1, - false); - } else { // Examine unexcluded ranges of source elements. - for (nPosition = oSourceElements.length - 1; - nPosition >= nAfterDirectivePrologue; - nPosition -= 1) { - oSourceElementData = (/** @type {!TSourceElementsData} */ - aSourceElementsData[nPosition]); - if (ESourceElementCategories.N_OTHER === - oSourceElementData.nCategory) { - if ('undefined' === typeof nTo) { - nTo = nPosition; // Indicate the end of a range. - } - // Examine the range if it immediately follows a Directive Prologue. - if (nPosition === nAfterDirectivePrologue) { - fExamineSourceElements(nPosition, nTo, true); - } - } else { - if ('undefined' !== typeof nTo) { - // Examine the range that immediately follows this source element. - fExamineSourceElements(nPosition + 1, nTo, true); - nTo = void 0; // Obliterate the range. - } - // Examine nested functions. - oWalker = oProcessor.ast_walker(); - oWalker.with_walkers( - oWalkers.oExamineFunctions, - cContext(oWalker, oSourceElements[nPosition])); - } - } - } - }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree))); - return oAbstractSyntaxTree; -}; -/*jshint sub:false */ - -/* Local Variables: */ -/* mode: js */ -/* coding: utf-8 */ -/* indent-tabs-mode: nil */ -/* tab-width: 2 */ -/* End: */ -/* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */ -/* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */ - diff --git a/build/vendor/uglify/parse-js.js b/build/vendor/uglify/parse-js.js deleted file mode 100755 index d80c2b5..0000000 --- a/build/vendor/uglify/parse-js.js +++ /dev/null @@ -1,1362 +0,0 @@ -/*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - - This version is suitable for Node.js. With minimal changes (the - exports stuff) it should work on any JS platform. - - This file contains the tokenizer/parser. It is a port to JavaScript - of parse-js [1], a JavaScript parser library written in Common Lisp - by Marijn Haverbeke. Thank you Marijn! - - [1] http://marijn.haverbeke.nl/parse-js/ - - Exported functions: - - - tokenizer(code) -- returns a function. Call the returned - function to fetch the next token. - - - parse(code) -- returns an AST of the given JavaScript code. - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2010 (c) Mihai Bazon - Based on parse-js (http://marijn.haverbeke.nl/parse-js/). - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - -/* -----[ Tokenizer (constants) ]----- */ - -var KEYWORDS = array_to_hash([ - "break", - "case", - "catch", - "const", - "continue", - "debugger", - "default", - "delete", - "do", - "else", - "finally", - "for", - "function", - "if", - "in", - "instanceof", - "new", - "return", - "switch", - "throw", - "try", - "typeof", - "var", - "void", - "while", - "with" -]); - -var RESERVED_WORDS = array_to_hash([ - "abstract", - "boolean", - "byte", - "char", - "class", - "double", - "enum", - "export", - "extends", - "final", - "float", - "goto", - "implements", - "import", - "int", - "interface", - "long", - "native", - "package", - "private", - "protected", - "public", - "short", - "static", - "super", - "synchronized", - "throws", - "transient", - "volatile" -]); - -var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ - "return", - "new", - "delete", - "throw", - "else", - "case" -]); - -var KEYWORDS_ATOM = array_to_hash([ - "false", - "null", - "true", - "undefined" -]); - -var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); - -var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; -var RE_OCT_NUMBER = /^0[0-7]+$/; -var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - -var OPERATORS = array_to_hash([ - "in", - "instanceof", - "typeof", - "new", - "void", - "delete", - "++", - "--", - "+", - "-", - "!", - "~", - "&", - "|", - "^", - "*", - "/", - "%", - ">>", - "<<", - ">>>", - "<", - ">", - "<=", - ">=", - "==", - "===", - "!=", - "!==", - "?", - "=", - "+=", - "-=", - "/=", - "*=", - "%=", - ">>=", - "<<=", - ">>>=", - "|=", - "^=", - "&=", - "&&", - "||" -]); - -var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); - -var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:")); - -var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); - -var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); - -/* -----[ Tokenizer ]----- */ - -var UNICODE = { // Unicode 6.1 - letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), - combining_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u08E4-\\u08FE\\u0900-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C01-\\u0C03\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C82\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0D02\\u0D03\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D82\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF2-\\u1CF4\\u1DC0-\\u1DE6\\u1DFC-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA674-\\uA67D\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA880\\uA881\\uA8B4-\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), - connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"), - digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]") -}; - -function is_letter(ch) { - return UNICODE.letter.test(ch); -}; - -function is_digit(ch) { - ch = ch.charCodeAt(0); - return ch >= 48 && ch <= 57; -}; - -function is_unicode_digit(ch) { - return UNICODE.digit.test(ch); -} - -function is_alphanumeric_char(ch) { - return is_digit(ch) || is_letter(ch); -}; - -function is_unicode_combining_mark(ch) { - return UNICODE.combining_mark.test(ch); -}; - -function is_unicode_connector_punctuation(ch) { - return UNICODE.connector_punctuation.test(ch); -}; - -function is_identifier_start(ch) { - return ch == "$" || ch == "_" || is_letter(ch); -}; - -function is_identifier_char(ch) { - return is_identifier_start(ch) - || is_unicode_combining_mark(ch) - || is_unicode_digit(ch) - || is_unicode_connector_punctuation(ch) - || ch == "\u200c" // zero-width non-joiner - || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) - ; -}; - -function parse_js_number(num) { - if (RE_HEX_NUMBER.test(num)) { - return parseInt(num.substr(2), 16); - } else if (RE_OCT_NUMBER.test(num)) { - return parseInt(num.substr(1), 8); - } else if (RE_DEC_NUMBER.test(num)) { - return parseFloat(num); - } -}; - -function JS_Parse_Error(message, line, col, pos) { - this.message = message; - this.line = line + 1; - this.col = col + 1; - this.pos = pos + 1; - this.stack = new Error().stack; -}; - -JS_Parse_Error.prototype.toString = function() { - return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; -}; - -function js_error(message, line, col, pos) { - throw new JS_Parse_Error(message, line, col, pos); -}; - -function is_token(token, type, val) { - return token.type == type && (val == null || token.value == val); -}; - -var EX_EOF = {}; - -function tokenizer($TEXT) { - - var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false, - comments_before : [] - }; - - function peek() { return S.text.charAt(S.pos); }; - - function next(signal_eof, in_string) { - var ch = S.text.charAt(S.pos++); - if (signal_eof && !ch) - throw EX_EOF; - if (ch == "\n") { - S.newline_before = S.newline_before || !in_string; - ++S.line; - S.col = 0; - } else { - ++S.col; - } - return ch; - }; - - function eof() { - return !S.peek(); - }; - - function find(what, signal_eof) { - var pos = S.text.indexOf(what, S.pos); - if (signal_eof && pos == -1) throw EX_EOF; - return pos; - }; - - function start_token() { - S.tokline = S.line; - S.tokcol = S.col; - S.tokpos = S.pos; - }; - - function token(type, value, is_comment) { - S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || - (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || - (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); - var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - endpos : S.pos, - nlb : S.newline_before - }; - if (!is_comment) { - ret.comments_before = S.comments_before; - S.comments_before = []; - // make note of any newlines in the comments that came before - for (var i = 0, len = ret.comments_before.length; i < len; i++) { - ret.nlb = ret.nlb || ret.comments_before[i].nlb; - } - } - S.newline_before = false; - return ret; - }; - - function skip_whitespace() { - while (HOP(WHITESPACE_CHARS, peek())) - next(); - }; - - function read_while(pred) { - var ret = "", ch = peek(), i = 0; - while (ch && pred(ch, i++)) { - ret += next(); - ch = peek(); - } - return ret; - }; - - function parse_error(err) { - js_error(err, S.tokline, S.tokcol, S.tokpos); - }; - - function read_num(prefix) { - var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; - var num = read_while(function(ch, i){ - if (ch == "x" || ch == "X") { - if (has_x) return false; - return has_x = true; - } - if (!has_x && (ch == "E" || ch == "e")) { - if (has_e) return false; - return has_e = after_e = true; - } - if (ch == "-") { - if (after_e || (i == 0 && !prefix)) return true; - return false; - } - if (ch == "+") return after_e; - after_e = false; - if (ch == ".") { - if (!has_dot && !has_x && !has_e) - return has_dot = true; - return false; - } - return is_alphanumeric_char(ch); - }); - if (prefix) - num = prefix + num; - var valid = parse_js_number(num); - if (!isNaN(valid)) { - return token("num", valid); - } else { - parse_error("Invalid syntax: " + num); - } - }; - - function read_escaped_char(in_string) { - var ch = next(true, in_string); - switch (ch) { - case "n" : return "\n"; - case "r" : return "\r"; - case "t" : return "\t"; - case "b" : return "\b"; - case "v" : return "\u000b"; - case "f" : return "\f"; - case "0" : return "\0"; - case "x" : return String.fromCharCode(hex_bytes(2)); - case "u" : return String.fromCharCode(hex_bytes(4)); - case "\n": return ""; - default : return ch; - } - }; - - function hex_bytes(n) { - var num = 0; - for (; n > 0; --n) { - var digit = parseInt(next(true), 16); - if (isNaN(digit)) - parse_error("Invalid hex-character pattern in string"); - num = (num << 4) | digit; - } - return num; - }; - - function read_string() { - return with_eof_error("Unterminated string constant", function(){ - var quote = next(), ret = ""; - for (;;) { - var ch = next(true); - if (ch == "\\") { - // read OctalEscapeSequence (XXX: deprecated if "strict mode") - // https://github.com/mishoo/UglifyJS/issues/178 - var octal_len = 0, first = null; - ch = read_while(function(ch){ - if (ch >= "0" && ch <= "7") { - if (!first) { - first = ch; - return ++octal_len; - } - else if (first <= "3" && octal_len <= 2) return ++octal_len; - else if (first >= "4" && octal_len <= 1) return ++octal_len; - } - return false; - }); - if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); - else ch = read_escaped_char(true); - } - else if (ch == quote) break; - ret += ch; - } - return token("string", ret); - }); - }; - - function read_line_comment() { - next(); - var i = find("\n"), ret; - if (i == -1) { - ret = S.text.substr(S.pos); - S.pos = S.text.length; - } else { - ret = S.text.substring(S.pos, i); - S.pos = i; - } - return token("comment1", ret, true); - }; - - function read_multiline_comment() { - next(); - return with_eof_error("Unterminated multiline comment", function(){ - var i = find("*/", true), - text = S.text.substring(S.pos, i); - S.pos = i + 2; - S.line += text.split("\n").length - 1; - S.newline_before = S.newline_before || text.indexOf("\n") >= 0; - - // https://github.com/mishoo/UglifyJS/issues/#issue/100 - if (/^@cc_on/i.test(text)) { - warn("WARNING: at line " + S.line); - warn("*** Found \"conditional comment\": " + text); - warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); - } - - return token("comment2", text, true); - }); - }; - - function read_name() { - var backslash = false, name = "", ch, escaped = false, hex; - while ((ch = peek()) != null) { - if (!backslash) { - if (ch == "\\") escaped = backslash = true, next(); - else if (is_identifier_char(ch)) name += next(); - else break; - } - else { - if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); - ch = read_escaped_char(); - if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); - name += ch; - backslash = false; - } - } - if (HOP(KEYWORDS, name) && escaped) { - hex = name.charCodeAt(0).toString(16).toUpperCase(); - name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); - } - return name; - }; - - function read_regexp(regexp) { - return with_eof_error("Unterminated regular expression", function(){ - var prev_backslash = false, ch, in_class = false; - while ((ch = next(true))) if (prev_backslash) { - regexp += "\\" + ch; - prev_backslash = false; - } else if (ch == "[") { - in_class = true; - regexp += ch; - } else if (ch == "]" && in_class) { - in_class = false; - regexp += ch; - } else if (ch == "/" && !in_class) { - break; - } else if (ch == "\\") { - prev_backslash = true; - } else { - regexp += ch; - } - var mods = read_name(); - return token("regexp", [ regexp, mods ]); - }); - }; - - function read_operator(prefix) { - function grow(op) { - if (!peek()) return op; - var bigger = op + peek(); - if (HOP(OPERATORS, bigger)) { - next(); - return grow(bigger); - } else { - return op; - } - }; - return token("operator", grow(prefix || next())); - }; - - function handle_slash() { - next(); - var regex_allowed = S.regex_allowed; - switch (peek()) { - case "/": - S.comments_before.push(read_line_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - case "*": - S.comments_before.push(read_multiline_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - } - return S.regex_allowed ? read_regexp("") : read_operator("/"); - }; - - function handle_dot() { - next(); - return is_digit(peek()) - ? read_num(".") - : token("punc", "."); - }; - - function read_word() { - var word = read_name(); - return !HOP(KEYWORDS, word) - ? token("name", word) - : HOP(OPERATORS, word) - ? token("operator", word) - : HOP(KEYWORDS_ATOM, word) - ? token("atom", word) - : token("keyword", word); - }; - - function with_eof_error(eof_error, cont) { - try { - return cont(); - } catch(ex) { - if (ex === EX_EOF) parse_error(eof_error); - else throw ex; - } - }; - - function next_token(force_regexp) { - if (force_regexp != null) - return read_regexp(force_regexp); - skip_whitespace(); - start_token(); - var ch = peek(); - if (!ch) return token("eof"); - if (is_digit(ch)) return read_num(); - if (ch == '"' || ch == "'") return read_string(); - if (HOP(PUNC_CHARS, ch)) return token("punc", next()); - if (ch == ".") return handle_dot(); - if (ch == "/") return handle_slash(); - if (HOP(OPERATOR_CHARS, ch)) return read_operator(); - if (ch == "\\" || is_identifier_start(ch)) return read_word(); - parse_error("Unexpected character '" + ch + "'"); - }; - - next_token.context = function(nc) { - if (nc) S = nc; - return S; - }; - - return next_token; - -}; - -/* -----[ Parser (constants) ]----- */ - -var UNARY_PREFIX = array_to_hash([ - "typeof", - "void", - "delete", - "--", - "++", - "!", - "~", - "-", - "+" -]); - -var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); - -var ASSIGNMENT = (function(a, ret, i){ - while (i < a.length) { - ret[a[i]] = a[i].substr(0, a[i].length - 1); - i++; - } - return ret; -})( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], - { "=": true }, - 0 -); - -var PRECEDENCE = (function(a, ret){ - for (var i = 0, n = 1; i < a.length; ++i, ++n) { - var b = a[i]; - for (var j = 0; j < b.length; ++j) { - ret[b[j]] = n; - } - } - return ret; -})( - [ - ["||"], - ["&&"], - ["|"], - ["^"], - ["&"], - ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], - [">>", "<<", ">>>"], - ["+", "-"], - ["*", "/", "%"] - ], - {} -); - -var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); - -var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); - -/* -----[ Parser ]----- */ - -function NodeWithToken(str, start, end) { - this.name = str; - this.start = start; - this.end = end; -}; - -NodeWithToken.prototype.toString = function() { return this.name; }; - -function parse($TEXT, exigent_mode, embed_tokens) { - - var S = { - input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, - token : null, - prev : null, - peeked : null, - in_function : 0, - in_directives : true, - in_loop : 0, - labels : [] - }; - - S.token = next(); - - function is(type, value) { - return is_token(S.token, type, value); - }; - - function peek() { return S.peeked || (S.peeked = S.input()); }; - - function next() { - S.prev = S.token; - if (S.peeked) { - S.token = S.peeked; - S.peeked = null; - } else { - S.token = S.input(); - } - S.in_directives = S.in_directives && ( - S.token.type == "string" || is("punc", ";") - ); - return S.token; - }; - - function prev() { - return S.prev; - }; - - function croak(msg, line, col, pos) { - var ctx = S.input.context(); - js_error(msg, - line != null ? line : ctx.tokline, - col != null ? col : ctx.tokcol, - pos != null ? pos : ctx.tokpos); - }; - - function token_error(token, msg) { - croak(msg, token.line, token.col); - }; - - function unexpected(token) { - if (token == null) - token = S.token; - token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); - }; - - function expect_token(type, val) { - if (is(type, val)) { - return next(); - } - token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); - }; - - function expect(punc) { return expect_token("punc", punc); }; - - function can_insert_semicolon() { - return !exigent_mode && ( - S.token.nlb || is("eof") || is("punc", "}") - ); - }; - - function semicolon() { - if (is("punc", ";")) next(); - else if (!can_insert_semicolon()) unexpected(); - }; - - function as() { - return slice(arguments); - }; - - function parenthesised() { - expect("("); - var ex = expression(); - expect(")"); - return ex; - }; - - function add_tokens(str, start, end) { - return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); - }; - - function maybe_embed_tokens(parser) { - if (embed_tokens) return function() { - var start = S.token; - var ast = parser.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - }; - else return parser; - }; - - var statement = maybe_embed_tokens(function() { - if (is("operator", "/") || is("operator", "/=")) { - S.peeked = null; - S.token = S.input(S.token.value.substr(1)); // force regexp - } - switch (S.token.type) { - case "string": - var dir = S.in_directives, stat = simple_statement(); - if (dir && stat[1][0] == "string" && !is("punc", ",")) - return as("directive", stat[1][1]); - return stat; - case "num": - case "regexp": - case "operator": - case "atom": - return simple_statement(); - - case "name": - return is_token(peek(), "punc", ":") - ? labeled_statement(prog1(S.token.value, next, next)) - : simple_statement(); - - case "punc": - switch (S.token.value) { - case "{": - return as("block", block_()); - case "[": - case "(": - return simple_statement(); - case ";": - next(); - return as("block"); - default: - unexpected(); - } - - case "keyword": - switch (prog1(S.token.value, next)) { - case "break": - return break_cont("break"); - - case "continue": - return break_cont("continue"); - - case "debugger": - semicolon(); - return as("debugger"); - - case "do": - return (function(body){ - expect_token("keyword", "while"); - return as("do", prog1(parenthesised, semicolon), body); - })(in_loop(statement)); - - case "for": - return for_(); - - case "function": - return function_(true); - - case "if": - return if_(); - - case "return": - if (S.in_function == 0) - croak("'return' outside of function"); - return as("return", - is("punc", ";") - ? (next(), null) - : can_insert_semicolon() - ? null - : prog1(expression, semicolon)); - - case "switch": - return as("switch", parenthesised(), switch_block_()); - - case "throw": - if (S.token.nlb) - croak("Illegal newline after 'throw'"); - return as("throw", prog1(expression, semicolon)); - - case "try": - return try_(); - - case "var": - return prog1(var_, semicolon); - - case "const": - return prog1(const_, semicolon); - - case "while": - return as("while", parenthesised(), in_loop(statement)); - - case "with": - return as("with", parenthesised(), statement()); - - default: - unexpected(); - } - } - }); - - function labeled_statement(label) { - S.labels.push(label); - var start = S.token, stat = statement(); - if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) - unexpected(start); - S.labels.pop(); - return as("label", label, stat); - }; - - function simple_statement() { - return as("stat", prog1(expression, semicolon)); - }; - - function break_cont(type) { - var name; - if (!can_insert_semicolon()) { - name = is("name") ? S.token.value : null; - } - if (name != null) { - next(); - if (!member(name, S.labels)) - croak("Label " + name + " without matching loop or statement"); - } - else if (S.in_loop == 0) - croak(type + " not inside a loop or switch"); - semicolon(); - return as(type, name); - }; - - function for_() { - expect("("); - var init = null; - if (!is("punc", ";")) { - init = is("keyword", "var") - ? (next(), var_(true)) - : expression(true, true); - if (is("operator", "in")) { - if (init[0] == "var" && init[1].length > 1) - croak("Only one variable declaration allowed in for..in loop"); - return for_in(init); - } - } - return regular_for(init); - }; - - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(); - expect(";"); - var step = is("punc", ")") ? null : expression(); - expect(")"); - return as("for", init, test, step, in_loop(statement)); - }; - - function for_in(init) { - var lhs = init[0] == "var" ? as("name", init[1][0]) : init; - next(); - var obj = expression(); - expect(")"); - return as("for-in", init, lhs, obj, in_loop(statement)); - }; - - var function_ = function(in_statement) { - var name = is("name") ? prog1(S.token.value, next) : null; - if (in_statement && !name) - unexpected(); - expect("("); - return as(in_statement ? "defun" : "function", - name, - // arguments - (function(first, a){ - while (!is("punc", ")")) { - if (first) first = false; else expect(","); - if (!is("name")) unexpected(); - a.push(S.token.value); - next(); - } - next(); - return a; - })(true, []), - // body - (function(){ - ++S.in_function; - var loop = S.in_loop; - S.in_directives = true; - S.in_loop = 0; - var a = block_(); - --S.in_function; - S.in_loop = loop; - return a; - })()); - }; - - function if_() { - var cond = parenthesised(), body = statement(), belse; - if (is("keyword", "else")) { - next(); - belse = statement(); - } - return as("if", cond, body, belse); - }; - - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } - next(); - return a; - }; - - var switch_block_ = curry(in_loop, function(){ - expect("{"); - var a = [], cur = null; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - next(); - cur = []; - a.push([ expression(), cur ]); - expect(":"); - } - else if (is("keyword", "default")) { - next(); - expect(":"); - cur = []; - a.push([ null, cur ]); - } - else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - next(); - return a; - }); - - function try_() { - var body = block_(), bcatch, bfinally; - if (is("keyword", "catch")) { - next(); - expect("("); - if (!is("name")) - croak("Name expected"); - var name = S.token.value; - next(); - expect(")"); - bcatch = [ name, block_() ]; - } - if (is("keyword", "finally")) { - next(); - bfinally = block_(); - } - if (!bcatch && !bfinally) - croak("Missing catch/finally blocks"); - return as("try", body, bcatch, bfinally); - }; - - function vardefs(no_in) { - var a = []; - for (;;) { - if (!is("name")) - unexpected(); - var name = S.token.value; - next(); - if (is("operator", "=")) { - next(); - a.push([ name, expression(false, no_in) ]); - } else { - a.push([ name ]); - } - if (!is("punc", ",")) - break; - next(); - } - return a; - }; - - function var_(no_in) { - return as("var", vardefs(no_in)); - }; - - function const_() { - return as("const", vardefs()); - }; - - function new_() { - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")"); - } else { - args = []; - } - return subscripts(as("new", newexp, args), true); - }; - - var expr_atom = maybe_embed_tokens(function(allow_calls) { - if (is("operator", "new")) { - next(); - return new_(); - } - if (is("punc")) { - switch (S.token.value) { - case "(": - next(); - return subscripts(prog1(expression, curry(expect, ")")), allow_calls); - case "[": - next(); - return subscripts(array_(), allow_calls); - case "{": - next(); - return subscripts(object_(), allow_calls); - } - unexpected(); - } - if (is("keyword", "function")) { - next(); - return subscripts(function_(false), allow_calls); - } - if (HOP(ATOMIC_START_TOKEN, S.token.type)) { - var atom = S.token.type == "regexp" - ? as("regexp", S.token.value[0], S.token.value[1]) - : as(S.token.type, S.token.value); - return subscripts(prog1(atom, next), allow_calls); - } - unexpected(); - }); - - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push([ "atom", "undefined" ]); - } else { - a.push(expression(false)); - } - } - next(); - return a; - }; - - function array_() { - return as("array", expr_list("]", !exigent_mode, true)); - }; - - function object_() { - var first = true, a = []; - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!exigent_mode && is("punc", "}")) - // allow trailing comma - break; - var type = S.token.type; - var name = as_property_name(); - if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { - a.push([ as_name(), function_(false), name ]); - } else { - expect(":"); - a.push([ name, expression(false) ]); - } - } - next(); - return as("object", a); - }; - - function as_property_name() { - switch (S.token.type) { - case "num": - case "string": - return prog1(S.token.value, next); - } - return as_name(); - }; - - function as_name() { - switch (S.token.type) { - case "name": - case "operator": - case "keyword": - case "atom": - return prog1(S.token.value, next); - default: - unexpected(); - } - }; - - function subscripts(expr, allow_calls) { - if (is("punc", ".")) { - next(); - return subscripts(as("dot", expr, as_name()), allow_calls); - } - if (is("punc", "[")) { - next(); - return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - return subscripts(as("call", expr, expr_list(")")), true); - } - return expr; - }; - - function maybe_unary(allow_calls) { - if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { - return make_unary("unary-prefix", - prog1(S.token.value, next), - maybe_unary(allow_calls)); - } - var val = expr_atom(allow_calls); - while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) { - val = make_unary("unary-postfix", S.token.value, val); - next(); - } - return val; - }; - - function make_unary(tag, op, expr) { - if ((op == "++" || op == "--") && !is_assignable(expr)) - croak("Invalid use of " + op + " operator"); - return as(tag, op, expr); - }; - - function expr_op(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op && op == "in" && no_in) op = null; - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && prec > min_prec) { - next(); - var right = expr_op(maybe_unary(true), prec, no_in); - return expr_op(as("binary", op, left, right), min_prec, no_in); - } - return left; - }; - - function expr_ops(no_in) { - return expr_op(maybe_unary(true), 0, no_in); - }; - - function maybe_conditional(no_in) { - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return as("conditional", expr, yes, expression(false, no_in)); - } - return expr; - }; - - function is_assignable(expr) { - if (!exigent_mode) return true; - switch (expr[0]+"") { - case "dot": - case "sub": - case "new": - case "call": - return true; - case "name": - return expr[1] != "this"; - } - }; - - function maybe_assign(no_in) { - var left = maybe_conditional(no_in), val = S.token.value; - if (is("operator") && HOP(ASSIGNMENT, val)) { - if (is_assignable(left)) { - next(); - return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); - } - croak("Invalid assignment"); - } - return left; - }; - - var expression = maybe_embed_tokens(function(commas, no_in) { - if (arguments.length == 0) - commas = true; - var expr = maybe_assign(no_in); - if (commas && is("punc", ",")) { - next(); - return as("seq", expr, expression(true, no_in)); - } - return expr; - }); - - function in_loop(cont) { - try { - ++S.in_loop; - return cont(); - } finally { - --S.in_loop; - } - }; - - return as("toplevel", (function(a){ - while (!is("eof")) - a.push(statement()); - return a; - })([])); - -}; - -/* -----[ Utilities ]----- */ - -function curry(f) { - var args = slice(arguments, 1); - return function() { return f.apply(this, args.concat(slice(arguments))); }; -}; - -function prog1(ret) { - if (ret instanceof Function) - ret = ret(); - for (var i = 1, n = arguments.length; --n > 0; ++i) - arguments[i](); - return ret; -}; - -function array_to_hash(a) { - var ret = {}; - for (var i = 0; i < a.length; ++i) - ret[a[i]] = true; - return ret; -}; - -function slice(a, start) { - return Array.prototype.slice.call(a, start || 0); -}; - -function characters(str) { - return str.split(""); -}; - -function member(name, array) { - for (var i = array.length; --i >= 0;) - if (array[i] == name) - return true; - return false; -}; - -function HOP(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -}; - -var warn = function() {}; - -/* -----[ Exports ]----- */ - -exports.tokenizer = tokenizer; -exports.parse = parse; -exports.slice = slice; -exports.curry = curry; -exports.member = member; -exports.array_to_hash = array_to_hash; -exports.PRECEDENCE = PRECEDENCE; -exports.KEYWORDS_ATOM = KEYWORDS_ATOM; -exports.RESERVED_WORDS = RESERVED_WORDS; -exports.KEYWORDS = KEYWORDS; -exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; -exports.OPERATORS = OPERATORS; -exports.is_alphanumeric_char = is_alphanumeric_char; -exports.set_logger = function(logger) { - warn = logger; -}; diff --git a/build/vendor/uglify/process.js b/build/vendor/uglify/process.js deleted file mode 100755 index 29c66cf..0000000 --- a/build/vendor/uglify/process.js +++ /dev/null @@ -1,2080 +0,0 @@ -/*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - - This version is suitable for Node.js. With minimal changes (the - exports stuff) it should work on any JS platform. - - This file implements some AST processors. They work on data built - by parse-js. - - Exported functions: - - - ast_mangle(ast, options) -- mangles the variable/function names - in the AST. Returns an AST. - - - ast_squeeze(ast) -- employs various optimizations to make the - final generated code even smaller. Returns an AST. - - - gen_code(ast, options) -- generates JS code from the AST. Pass - true (or an object, see the code for some options) as second - argument to get "pretty" (indented) code. - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2010 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - -var jsp = require("./parse-js"), - slice = jsp.slice, - member = jsp.member, - PRECEDENCE = jsp.PRECEDENCE, - OPERATORS = jsp.OPERATORS; - -/* -----[ helper for AST traversal ]----- */ - -function ast_walker() { - function _vardefs(defs) { - return [ this[0], MAP(defs, function(def){ - var a = [ def[0] ]; - if (def.length > 1) - a[1] = walk(def[1]); - return a; - }) ]; - }; - function _block(statements) { - var out = [ this[0] ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; - }; - var walkers = { - "string": function(str) { - return [ this[0], str ]; - }, - "num": function(num) { - return [ this[0], num ]; - }, - "name": function(name) { - return [ this[0], name ]; - }, - "toplevel": function(statements) { - return [ this[0], MAP(statements, walk) ]; - }, - "block": _block, - "splice": _block, - "var": _vardefs, - "const": _vardefs, - "try": function(t, c, f) { - return [ - this[0], - MAP(t, walk), - c != null ? [ c[0], MAP(c[1], walk) ] : null, - f != null ? MAP(f, walk) : null - ]; - }, - "throw": function(expr) { - return [ this[0], walk(expr) ]; - }, - "new": function(ctor, args) { - return [ this[0], walk(ctor), MAP(args, walk) ]; - }, - "switch": function(expr, body) { - return [ this[0], walk(expr), MAP(body, function(branch){ - return [ branch[0] ? walk(branch[0]) : null, - MAP(branch[1], walk) ]; - }) ]; - }, - "break": function(label) { - return [ this[0], label ]; - }, - "continue": function(label) { - return [ this[0], label ]; - }, - "conditional": function(cond, t, e) { - return [ this[0], walk(cond), walk(t), walk(e) ]; - }, - "assign": function(op, lvalue, rvalue) { - return [ this[0], op, walk(lvalue), walk(rvalue) ]; - }, - "dot": function(expr) { - return [ this[0], walk(expr) ].concat(slice(arguments, 1)); - }, - "call": function(expr, args) { - return [ this[0], walk(expr), MAP(args, walk) ]; - }, - "function": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "debugger": function() { - return [ this[0] ]; - }, - "defun": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "if": function(conditional, t, e) { - return [ this[0], walk(conditional), walk(t), walk(e) ]; - }, - "for": function(init, cond, step, block) { - return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; - }, - "for-in": function(vvar, key, hash, block) { - return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; - }, - "while": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "do": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "return": function(expr) { - return [ this[0], walk(expr) ]; - }, - "binary": function(op, left, right) { - return [ this[0], op, walk(left), walk(right) ]; - }, - "unary-prefix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "unary-postfix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "sub": function(expr, subscript) { - return [ this[0], walk(expr), walk(subscript) ]; - }, - "object": function(props) { - return [ this[0], MAP(props, function(p){ - return p.length == 2 - ? [ p[0], walk(p[1]) ] - : [ p[0], walk(p[1]), p[2] ]; // get/set-ter - }) ]; - }, - "regexp": function(rx, mods) { - return [ this[0], rx, mods ]; - }, - "array": function(elements) { - return [ this[0], MAP(elements, walk) ]; - }, - "stat": function(stat) { - return [ this[0], walk(stat) ]; - }, - "seq": function() { - return [ this[0] ].concat(MAP(slice(arguments), walk)); - }, - "label": function(name, block) { - return [ this[0], name, walk(block) ]; - }, - "with": function(expr, block) { - return [ this[0], walk(expr), walk(block) ]; - }, - "atom": function(name) { - return [ this[0], name ]; - }, - "directive": function(dir) { - return [ this[0], dir ]; - } - }; - - var user = {}; - var stack = []; - function walk(ast) { - if (ast == null) - return null; - try { - stack.push(ast); - var type = ast[0]; - var gen = user[type]; - if (gen) { - var ret = gen.apply(ast, ast.slice(1)); - if (ret != null) - return ret; - } - gen = walkers[type]; - return gen.apply(ast, ast.slice(1)); - } finally { - stack.pop(); - } - }; - - function dive(ast) { - if (ast == null) - return null; - try { - stack.push(ast); - return walkers[ast[0]].apply(ast, ast.slice(1)); - } finally { - stack.pop(); - } - }; - - function with_walkers(walkers, cont){ - var save = {}, i; - for (i in walkers) if (HOP(walkers, i)) { - save[i] = user[i]; - user[i] = walkers[i]; - } - var ret = cont(); - for (i in save) if (HOP(save, i)) { - if (!save[i]) delete user[i]; - else user[i] = save[i]; - } - return ret; - }; - - return { - walk: walk, - dive: dive, - with_walkers: with_walkers, - parent: function() { - return stack[stack.length - 2]; // last one is current node - }, - stack: function() { - return stack; - } - }; -}; - -/* -----[ Scope and mangling ]----- */ - -function Scope(parent) { - this.names = {}; // names defined in this scope - this.mangled = {}; // mangled names (orig.name => mangled) - this.rev_mangled = {}; // reverse lookup (mangled => orig.name) - this.cname = -1; // current mangled name - this.refs = {}; // names referenced from this scope - this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes - this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes - this.directives = []; // directives activated from this scope - this.parent = parent; // parent scope - this.children = []; // sub-scopes - if (parent) { - this.level = parent.level + 1; - parent.children.push(this); - } else { - this.level = 0; - } -}; - -function base54_digits() { - if (typeof DIGITS_OVERRIDE_FOR_TESTING != "undefined") - return DIGITS_OVERRIDE_FOR_TESTING; - else - return "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984"; -} - -var base54 = (function(){ - var DIGITS = base54_digits(); - return function(num) { - var ret = "", base = 54; - do { - ret += DIGITS.charAt(num % base); - num = Math.floor(num / base); - base = 64; - } while (num > 0); - return ret; - }; -})(); - -Scope.prototype = { - has: function(name) { - for (var s = this; s; s = s.parent) - if (HOP(s.names, name)) - return s; - }, - has_mangled: function(mname) { - for (var s = this; s; s = s.parent) - if (HOP(s.rev_mangled, mname)) - return s; - }, - toJSON: function() { - return { - names: this.names, - uses_eval: this.uses_eval, - uses_with: this.uses_with - }; - }, - - next_mangled: function() { - // we must be careful that the new mangled name: - // - // 1. doesn't shadow a mangled name from a parent - // scope, unless we don't reference the original - // name from this scope OR from any sub-scopes! - // This will get slow. - // - // 2. doesn't shadow an original name from a parent - // scope, in the event that the name is not mangled - // in the parent scope and we reference that name - // here OR IN ANY SUBSCOPES! - // - // 3. doesn't shadow a name that is referenced but not - // defined (possibly global defined elsewhere). - for (;;) { - var m = base54(++this.cname), prior; - - // case 1. - prior = this.has_mangled(m); - if (prior && this.refs[prior.rev_mangled[m]] === prior) - continue; - - // case 2. - prior = this.has(m); - if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m)) - continue; - - // case 3. - if (HOP(this.refs, m) && this.refs[m] == null) - continue; - - // I got "do" once. :-/ - if (!is_identifier(m)) - continue; - - return m; - } - }, - set_mangle: function(name, m) { - this.rev_mangled[m] = name; - return this.mangled[name] = m; - }, - get_mangled: function(name, newMangle) { - if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use - var s = this.has(name); - if (!s) return name; // not in visible scope, no mangle - if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope - if (!newMangle) return name; // not found and no mangling requested - return s.set_mangle(name, s.next_mangled()); - }, - references: function(name) { - return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name]; - }, - define: function(name, type) { - if (name != null) { - if (type == "var" || !HOP(this.names, name)) - this.names[name] = type || "var"; - return name; - } - }, - active: function(dir) { - return member(dir, this.directives) || this.parent && this.parent.active(dir); - } -}; - -function ast_add_scope(ast) { - - var current_scope = null; - var w = ast_walker(), walk = w.walk; - var having_eval = []; - - function with_new_scope(cont) { - current_scope = new Scope(current_scope); - current_scope.labels = new Scope(); - var ret = current_scope.body = cont(); - ret.scope = current_scope; - current_scope = current_scope.parent; - return ret; - }; - - function define(name, type) { - return current_scope.define(name, type); - }; - - function reference(name) { - current_scope.refs[name] = true; - }; - - function _lambda(name, args, body) { - var is_defun = this[0] == "defun"; - return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){ - if (!is_defun) define(name, "lambda"); - MAP(args, function(name){ define(name, "arg") }); - return MAP(body, walk); - })]; - }; - - function _vardefs(type) { - return function(defs) { - MAP(defs, function(d){ - define(d[0], type); - if (d[1]) reference(d[0]); - }); - }; - }; - - function _breacont(label) { - if (label) - current_scope.labels.refs[label] = true; - }; - - return with_new_scope(function(){ - // process AST - var ret = w.with_walkers({ - "function": _lambda, - "defun": _lambda, - "label": function(name, stat) { current_scope.labels.define(name) }, - "break": _breacont, - "continue": _breacont, - "with": function(expr, block) { - for (var s = current_scope; s; s = s.parent) - s.uses_with = true; - }, - "var": _vardefs("var"), - "const": _vardefs("const"), - "try": function(t, c, f) { - if (c != null) return [ - this[0], - MAP(t, walk), - [ define(c[0], "catch"), MAP(c[1], walk) ], - f != null ? MAP(f, walk) : null - ]; - }, - "name": function(name) { - if (name == "eval") - having_eval.push(current_scope); - reference(name); - } - }, function(){ - return walk(ast); - }); - - // the reason why we need an additional pass here is - // that names can be used prior to their definition. - - // scopes where eval was detected and their parents - // are marked with uses_eval, unless they define the - // "eval" name. - MAP(having_eval, function(scope){ - if (!scope.has("eval")) while (scope) { - scope.uses_eval = true; - scope = scope.parent; - } - }); - - // for referenced names it might be useful to know - // their origin scope. current_scope here is the - // toplevel one. - function fixrefs(scope, i) { - // do children first; order shouldn't matter - for (i = scope.children.length; --i >= 0;) - fixrefs(scope.children[i]); - for (i in scope.refs) if (HOP(scope.refs, i)) { - // find origin scope and propagate the reference to origin - for (var origin = scope.has(i), s = scope; s; s = s.parent) { - s.refs[i] = origin; - if (s === origin) break; - } - } - }; - fixrefs(current_scope); - - return ret; - }); - -}; - -/* -----[ mangle names ]----- */ - -function ast_mangle(ast, options) { - var w = ast_walker(), walk = w.walk, scope; - options = defaults(options, { - mangle : true, - toplevel : false, - defines : null, - except : null, - no_functions : false - }); - - function get_mangled(name, newMangle) { - if (!options.mangle) return name; - if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel - if (options.except && member(name, options.except)) - return name; - if (options.no_functions && HOP(scope.names, name) && - (scope.names[name] == 'defun' || scope.names[name] == 'lambda')) - return name; - return scope.get_mangled(name, newMangle); - }; - - function get_define(name) { - if (options.defines) { - // we always lookup a defined symbol for the current scope FIRST, so declared - // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value - if (!scope.has(name)) { - if (HOP(options.defines, name)) { - return options.defines[name]; - } - } - return null; - } - }; - - function _lambda(name, args, body) { - if (!options.no_functions && options.mangle) { - var is_defun = this[0] == "defun", extra; - if (name) { - if (is_defun) name = get_mangled(name); - else if (body.scope.references(name)) { - extra = {}; - if (!(scope.uses_eval || scope.uses_with)) - name = extra[name] = scope.next_mangled(); - else - extra[name] = name; - } - else name = null; - } - } - body = with_scope(body.scope, function(){ - args = MAP(args, function(name){ return get_mangled(name) }); - return MAP(body, walk); - }, extra); - return [ this[0], name, args, body ]; - }; - - function with_scope(s, cont, extra) { - var _scope = scope; - scope = s; - if (extra) for (var i in extra) if (HOP(extra, i)) { - s.set_mangle(i, extra[i]); - } - for (var i in s.names) if (HOP(s.names, i)) { - get_mangled(i, true); - } - var ret = cont(); - ret.scope = s; - scope = _scope; - return ret; - }; - - function _vardefs(defs) { - return [ this[0], MAP(defs, function(d){ - return [ get_mangled(d[0]), walk(d[1]) ]; - }) ]; - }; - - function _breacont(label) { - if (label) return [ this[0], scope.labels.get_mangled(label) ]; - }; - - return w.with_walkers({ - "function": _lambda, - "defun": function() { - // move function declarations to the top when - // they are not in some block. - var ast = _lambda.apply(this, arguments); - switch (w.parent()[0]) { - case "toplevel": - case "function": - case "defun": - return MAP.at_top(ast); - } - return ast; - }, - "label": function(label, stat) { - if (scope.labels.refs[label]) return [ - this[0], - scope.labels.get_mangled(label, true), - walk(stat) - ]; - return walk(stat); - }, - "break": _breacont, - "continue": _breacont, - "var": _vardefs, - "const": _vardefs, - "name": function(name) { - return get_define(name) || [ this[0], get_mangled(name) ]; - }, - "try": function(t, c, f) { - return [ this[0], - MAP(t, walk), - c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, - f != null ? MAP(f, walk) : null ]; - }, - "toplevel": function(body) { - var self = this; - return with_scope(self.scope, function(){ - return [ self[0], MAP(body, walk) ]; - }); - }, - "directive": function() { - return MAP.at_top(this); - } - }, function() { - return walk(ast_add_scope(ast)); - }); -}; - -/* -----[ - - compress foo["bar"] into foo.bar, - - remove block brackets {} where possible - - join consecutive var declarations - - various optimizations for IFs: - - if (cond) foo(); else bar(); ==> cond?foo():bar(); - - if (cond) foo(); ==> cond&&foo(); - - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw - - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} - ]----- */ - -var warn = function(){}; - -function best_of(ast1, ast2) { - return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1; -}; - -function last_stat(b) { - if (b[0] == "block" && b[1] && b[1].length > 0) - return b[1][b[1].length - 1]; - return b; -} - -function aborts(t) { - if (t) switch (last_stat(t)[0]) { - case "return": - case "break": - case "continue": - case "throw": - return true; - } -}; - -function boolean_expr(expr) { - return ( (expr[0] == "unary-prefix" - && member(expr[1], [ "!", "delete" ])) || - - (expr[0] == "binary" - && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) || - - (expr[0] == "binary" - && member(expr[1], [ "&&", "||" ]) - && boolean_expr(expr[2]) - && boolean_expr(expr[3])) || - - (expr[0] == "conditional" - && boolean_expr(expr[2]) - && boolean_expr(expr[3])) || - - (expr[0] == "assign" - && expr[1] === true - && boolean_expr(expr[3])) || - - (expr[0] == "seq" - && boolean_expr(expr[expr.length - 1])) - ); -}; - -function empty(b) { - return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); -}; - -function is_string(node) { - return (node[0] == "string" || - node[0] == "unary-prefix" && node[1] == "typeof" || - node[0] == "binary" && node[1] == "+" && - (is_string(node[2]) || is_string(node[3]))); -}; - -var when_constant = (function(){ - - var $NOT_CONSTANT = {}; - - // this can only evaluate constant expressions. If it finds anything - // not constant, it throws $NOT_CONSTANT. - function evaluate(expr) { - switch (expr[0]) { - case "string": - case "num": - return expr[1]; - case "name": - case "atom": - switch (expr[1]) { - case "true": return true; - case "false": return false; - case "null": return null; - } - break; - case "unary-prefix": - switch (expr[1]) { - case "!": return !evaluate(expr[2]); - case "typeof": return typeof evaluate(expr[2]); - case "~": return ~evaluate(expr[2]); - case "-": return -evaluate(expr[2]); - case "+": return +evaluate(expr[2]); - } - break; - case "binary": - var left = expr[2], right = expr[3]; - switch (expr[1]) { - case "&&" : return evaluate(left) && evaluate(right); - case "||" : return evaluate(left) || evaluate(right); - case "|" : return evaluate(left) | evaluate(right); - case "&" : return evaluate(left) & evaluate(right); - case "^" : return evaluate(left) ^ evaluate(right); - case "+" : return evaluate(left) + evaluate(right); - case "*" : return evaluate(left) * evaluate(right); - case "/" : return evaluate(left) / evaluate(right); - case "%" : return evaluate(left) % evaluate(right); - case "-" : return evaluate(left) - evaluate(right); - case "<<" : return evaluate(left) << evaluate(right); - case ">>" : return evaluate(left) >> evaluate(right); - case ">>>" : return evaluate(left) >>> evaluate(right); - case "==" : return evaluate(left) == evaluate(right); - case "===" : return evaluate(left) === evaluate(right); - case "!=" : return evaluate(left) != evaluate(right); - case "!==" : return evaluate(left) !== evaluate(right); - case "<" : return evaluate(left) < evaluate(right); - case "<=" : return evaluate(left) <= evaluate(right); - case ">" : return evaluate(left) > evaluate(right); - case ">=" : return evaluate(left) >= evaluate(right); - case "in" : return evaluate(left) in evaluate(right); - case "instanceof" : return evaluate(left) instanceof evaluate(right); - } - } - throw $NOT_CONSTANT; - }; - - return function(expr, yes, no) { - try { - var val = evaluate(expr), ast; - switch (typeof val) { - case "string": ast = [ "string", val ]; break; - case "number": ast = [ "num", val ]; break; - case "boolean": ast = [ "name", String(val) ]; break; - default: - if (val === null) { ast = [ "atom", "null" ]; break; } - throw new Error("Can't handle constant of type: " + (typeof val)); - } - return yes.call(expr, ast, val); - } catch(ex) { - if (ex === $NOT_CONSTANT) { - if (expr[0] == "binary" - && (expr[1] == "===" || expr[1] == "!==") - && ((is_string(expr[2]) && is_string(expr[3])) - || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) { - expr[1] = expr[1].substr(0, 2); - } - else if (no && expr[0] == "binary" - && (expr[1] == "||" || expr[1] == "&&")) { - // the whole expression is not constant but the lval may be... - try { - var lval = evaluate(expr[2]); - expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) || - (expr[1] == "||" && (lval ? lval : expr[3])) || - expr); - } catch(ex2) { - // IGNORE... lval is not constant - } - } - return no ? no.call(expr, expr) : null; - } - else throw ex; - } - }; - -})(); - -function warn_unreachable(ast) { - if (!empty(ast)) - warn("Dropping unreachable code: " + gen_code(ast, true)); -}; - -function prepare_ifs(ast) { - var w = ast_walker(), walk = w.walk; - // In this first pass, we rewrite ifs which abort with no else with an - // if-else. For example: - // - // if (x) { - // blah(); - // return y; - // } - // foobar(); - // - // is rewritten into: - // - // if (x) { - // blah(); - // return y; - // } else { - // foobar(); - // } - function redo_if(statements) { - statements = MAP(statements, walk); - - for (var i = 0; i < statements.length; ++i) { - var fi = statements[i]; - if (fi[0] != "if") continue; - - if (fi[3] && walk(fi[3])) continue; - - var t = walk(fi[2]); - if (!aborts(t)) continue; - - var conditional = walk(fi[1]); - - var e_body = redo_if(statements.slice(i + 1)); - var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ]; - - return statements.slice(0, i).concat([ [ - fi[0], // "if" - conditional, // conditional - t, // then - e // else - ] ]); - } - - return statements; - }; - - function redo_if_lambda(name, args, body) { - body = redo_if(body); - return [ this[0], name, args, body ]; - }; - - function redo_if_block(statements) { - return [ this[0], statements != null ? redo_if(statements) : null ]; - }; - - return w.with_walkers({ - "defun": redo_if_lambda, - "function": redo_if_lambda, - "block": redo_if_block, - "splice": redo_if_block, - "toplevel": function(statements) { - return [ this[0], redo_if(statements) ]; - }, - "try": function(t, c, f) { - return [ - this[0], - redo_if(t), - c != null ? [ c[0], redo_if(c[1]) ] : null, - f != null ? redo_if(f) : null - ]; - } - }, function() { - return walk(ast); - }); -}; - -function for_side_effects(ast, handler) { - var w = ast_walker(), walk = w.walk; - var $stop = {}, $restart = {}; - function stop() { throw $stop }; - function restart() { throw $restart }; - function found(){ return handler.call(this, this, w, stop, restart) }; - function unary(op) { - if (op == "++" || op == "--") - return found.apply(this, arguments); - }; - return w.with_walkers({ - "try": found, - "throw": found, - "return": found, - "new": found, - "switch": found, - "break": found, - "continue": found, - "assign": found, - "call": found, - "if": found, - "for": found, - "for-in": found, - "while": found, - "do": found, - "return": found, - "unary-prefix": unary, - "unary-postfix": unary, - "defun": found - }, function(){ - while (true) try { - walk(ast); - break; - } catch(ex) { - if (ex === $stop) break; - if (ex === $restart) continue; - throw ex; - } - }); -}; - -function ast_lift_variables(ast) { - var w = ast_walker(), walk = w.walk, scope; - function do_body(body, env) { - var _scope = scope; - scope = env; - body = MAP(body, walk); - var hash = {}, names = MAP(env.names, function(type, name){ - if (type != "var") return MAP.skip; - if (!env.references(name)) return MAP.skip; - hash[name] = true; - return [ name ]; - }); - if (names.length > 0) { - // looking for assignments to any of these variables. - // we can save considerable space by moving the definitions - // in the var declaration. - for_side_effects([ "block", body ], function(ast, walker, stop, restart) { - if (ast[0] == "assign" - && ast[1] === true - && ast[2][0] == "name" - && HOP(hash, ast[2][1])) { - // insert the definition into the var declaration - for (var i = names.length; --i >= 0;) { - if (names[i][0] == ast[2][1]) { - if (names[i][1]) // this name already defined, we must stop - stop(); - names[i][1] = ast[3]; // definition - names.push(names.splice(i, 1)[0]); - break; - } - } - // remove this assignment from the AST. - var p = walker.parent(); - if (p[0] == "seq") { - var a = p[2]; - a.unshift(0, p.length); - p.splice.apply(p, a); - } - else if (p[0] == "stat") { - p.splice(0, p.length, "block"); // empty statement - } - else { - stop(); - } - restart(); - } - stop(); - }); - body.unshift([ "var", names ]); - } - scope = _scope; - return body; - }; - function _vardefs(defs) { - var ret = null; - for (var i = defs.length; --i >= 0;) { - var d = defs[i]; - if (!d[1]) continue; - d = [ "assign", true, [ "name", d[0] ], d[1] ]; - if (ret == null) ret = d; - else ret = [ "seq", d, ret ]; - } - if (ret == null) { - if (w.parent()[0] == "for-in") - return [ "name", defs[0][0] ]; - return MAP.skip; - } - return [ "stat", ret ]; - }; - function _toplevel(body) { - return [ this[0], do_body(body, this.scope) ]; - }; - return w.with_walkers({ - "function": function(name, args, body){ - for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) - args.pop(); - if (!body.scope.references(name)) name = null; - return [ this[0], name, args, do_body(body, body.scope) ]; - }, - "defun": function(name, args, body){ - if (!scope.references(name)) return MAP.skip; - for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) - args.pop(); - return [ this[0], name, args, do_body(body, body.scope) ]; - }, - "var": _vardefs, - "toplevel": _toplevel - }, function(){ - return walk(ast_add_scope(ast)); - }); -}; - -function ast_squeeze(ast, options) { - options = defaults(options, { - make_seqs : true, - dead_code : true, - no_warnings : false, - keep_comps : true, - unsafe : false - }); - - var w = ast_walker(), walk = w.walk, scope; - - function negate(c) { - var not_c = [ "unary-prefix", "!", c ]; - switch (c[0]) { - case "unary-prefix": - return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c; - case "seq": - c = slice(c); - c[c.length - 1] = negate(c[c.length - 1]); - return c; - case "conditional": - return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]); - case "binary": - var op = c[1], left = c[2], right = c[3]; - if (!options.keep_comps) switch (op) { - case "<=" : return [ "binary", ">", left, right ]; - case "<" : return [ "binary", ">=", left, right ]; - case ">=" : return [ "binary", "<", left, right ]; - case ">" : return [ "binary", "<=", left, right ]; - } - switch (op) { - case "==" : return [ "binary", "!=", left, right ]; - case "!=" : return [ "binary", "==", left, right ]; - case "===" : return [ "binary", "!==", left, right ]; - case "!==" : return [ "binary", "===", left, right ]; - case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); - case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); - } - break; - } - return not_c; - }; - - function make_conditional(c, t, e) { - var make_real_conditional = function() { - if (c[0] == "unary-prefix" && c[1] == "!") { - return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; - } else { - return e ? best_of( - [ "conditional", c, t, e ], - [ "conditional", negate(c), e, t ] - ) : [ "binary", "&&", c, t ]; - } - }; - // shortcut the conditional if the expression has a constant value - return when_constant(c, function(ast, val){ - warn_unreachable(val ? e : t); - return (val ? t : e); - }, make_real_conditional); - }; - - function rmblock(block) { - if (block != null && block[0] == "block" && block[1]) { - if (block[1].length == 1) - block = block[1][0]; - else if (block[1].length == 0) - block = [ "block" ]; - } - return block; - }; - - function _lambda(name, args, body) { - return [ this[0], name, args, with_scope(body.scope, function() { - return tighten(body, "lambda"); - }) ]; - }; - - function with_scope(s, cont) { - var _scope = scope; - scope = s; - var ret = cont(); - scope = _scope; - return ret; - }; - - // this function does a few things: - // 1. discard useless blocks - // 2. join consecutive var declarations - // 3. remove obviously dead code - // 4. transform consecutive statements using the comma operator - // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... } - function tighten(statements, block_type) { - statements = MAP(statements, walk); - - statements = statements.reduce(function(a, stat){ - if (stat[0] == "block") { - if (stat[1]) { - a.push.apply(a, stat[1]); - } - } else { - a.push(stat); - } - return a; - }, []); - - statements = (function(a, prev){ - statements.forEach(function(cur){ - if (prev && ((cur[0] == "var" && prev[0] == "var") || - (cur[0] == "const" && prev[0] == "const"))) { - prev[1] = prev[1].concat(cur[1]); - } else { - a.push(cur); - prev = cur; - } - }); - return a; - })([]); - - if (options.dead_code) statements = (function(a, has_quit){ - statements.forEach(function(st){ - if (has_quit) { - if (st[0] == "function" || st[0] == "defun") { - a.push(st); - } - else if (st[0] == "var" || st[0] == "const") { - if (!options.no_warnings) - warn("Variables declared in unreachable code"); - st[1] = MAP(st[1], function(def){ - if (def[1] && !options.no_warnings) - warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]); - return [ def[0] ]; - }); - a.push(st); - } - else if (!options.no_warnings) - warn_unreachable(st); - } - else { - a.push(st); - if (member(st[0], [ "return", "throw", "break", "continue" ])) - has_quit = true; - } - }); - return a; - })([]); - - if (options.make_seqs) statements = (function(a, prev) { - statements.forEach(function(cur){ - if (prev && prev[0] == "stat" && cur[0] == "stat") { - prev[1] = [ "seq", prev[1], cur[1] ]; - } else { - a.push(cur); - prev = cur; - } - }); - if (a.length >= 2 - && a[a.length-2][0] == "stat" - && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw") - && a[a.length-1][1]) - { - a.splice(a.length - 2, 2, - [ a[a.length-1][0], - [ "seq", a[a.length-2][1], a[a.length-1][1] ]]); - } - return a; - })([]); - - // this increases jQuery by 1K. Probably not such a good idea after all.. - // part of this is done in prepare_ifs anyway. - // if (block_type == "lambda") statements = (function(i, a, stat){ - // while (i < statements.length) { - // stat = statements[i++]; - // if (stat[0] == "if" && !stat[3]) { - // if (stat[2][0] == "return" && stat[2][1] == null) { - // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ])); - // break; - // } - // var last = last_stat(stat[2]); - // if (last[0] == "return" && last[1] == null) { - // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ])); - // break; - // } - // } - // a.push(stat); - // } - // return a; - // })(0, []); - - return statements; - }; - - function make_if(c, t, e) { - return when_constant(c, function(ast, val){ - if (val) { - t = walk(t); - warn_unreachable(e); - return t || [ "block" ]; - } else { - e = walk(e); - warn_unreachable(t); - return e || [ "block" ]; - } - }, function() { - return make_real_if(c, t, e); - }); - }; - - function abort_else(c, t, e) { - var ret = [ [ "if", negate(c), e ] ]; - if (t[0] == "block") { - if (t[1]) ret = ret.concat(t[1]); - } else { - ret.push(t); - } - return walk([ "block", ret ]); - }; - - function make_real_if(c, t, e) { - c = walk(c); - t = walk(t); - e = walk(e); - - if (empty(e) && empty(t)) - return [ "stat", c ]; - - if (empty(t)) { - c = negate(c); - t = e; - e = null; - } else if (empty(e)) { - e = null; - } else { - // if we have both else and then, maybe it makes sense to switch them? - (function(){ - var a = gen_code(c); - var n = negate(c); - var b = gen_code(n); - if (b.length < a.length) { - var tmp = t; - t = e; - e = tmp; - c = n; - } - })(); - } - var ret = [ "if", c, t, e ]; - if (t[0] == "if" && empty(t[3]) && empty(e)) { - ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ])); - } - else if (t[0] == "stat") { - if (e) { - if (e[0] == "stat") - ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); - else if (aborts(e)) - ret = abort_else(c, t, e); - } - else { - ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]); - } - } - else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) { - ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]); - } - else if (e && aborts(t)) { - ret = [ [ "if", c, t ] ]; - if (e[0] == "block") { - if (e[1]) ret = ret.concat(e[1]); - } - else { - ret.push(e); - } - ret = walk([ "block", ret ]); - } - else if (t && aborts(e)) { - ret = abort_else(c, t, e); - } - return ret; - }; - - function _do_while(cond, body) { - return when_constant(cond, function(cond, val){ - if (!val) { - warn_unreachable(body); - return [ "block" ]; - } else { - return [ "for", null, null, null, walk(body) ]; - } - }); - }; - - return w.with_walkers({ - "sub": function(expr, subscript) { - if (subscript[0] == "string") { - var name = subscript[1]; - if (is_identifier(name)) - return [ "dot", walk(expr), name ]; - else if (/^[1-9][0-9]*$/.test(name) || name === "0") - return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ]; - } - }, - "if": make_if, - "toplevel": function(body) { - return with_scope(this.scope, function() { - return [ "toplevel", tighten(body) ]; - }); - }, - "switch": function(expr, body) { - var last = body.length - 1; - return [ "switch", walk(expr), MAP(body, function(branch, i){ - var block = tighten(branch[1]); - if (i == last && block.length > 0) { - var node = block[block.length - 1]; - if (node[0] == "break" && !node[1]) - block.pop(); - } - return [ branch[0] ? walk(branch[0]) : null, block ]; - }) ]; - }, - "function": _lambda, - "defun": _lambda, - "block": function(body) { - if (body) return rmblock([ "block", tighten(body) ]); - }, - "binary": function(op, left, right) { - return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){ - return best_of(walk(c), this); - }, function no() { - return function(){ - if(op != "==" && op != "!=") return; - var l = walk(left), r = walk(right); - if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num") - left = ['num', +!l[2][1]]; - else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num") - right = ['num', +!r[2][1]]; - return ["binary", op, left, right]; - }() || this; - }); - }, - "conditional": function(c, t, e) { - return make_conditional(walk(c), walk(t), walk(e)); - }, - "try": function(t, c, f) { - return [ - "try", - tighten(t), - c != null ? [ c[0], tighten(c[1]) ] : null, - f != null ? tighten(f) : null - ]; - }, - "unary-prefix": function(op, expr) { - expr = walk(expr); - var ret = [ "unary-prefix", op, expr ]; - if (op == "!") - ret = best_of(ret, negate(expr)); - return when_constant(ret, function(ast, val){ - return walk(ast); // it's either true or false, so minifies to !0 or !1 - }, function() { return ret }); - }, - "name": function(name) { - switch (name) { - case "true": return [ "unary-prefix", "!", [ "num", 0 ]]; - case "false": return [ "unary-prefix", "!", [ "num", 1 ]]; - } - }, - "while": _do_while, - "assign": function(op, lvalue, rvalue) { - lvalue = walk(lvalue); - rvalue = walk(rvalue); - var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; - if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" && - ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" && - rvalue[2][1] === lvalue[1]) { - return [ this[0], rvalue[1], lvalue, rvalue[3] ] - } - return [ this[0], op, lvalue, rvalue ]; - }, - "directive": function(dir) { - if (scope.active(dir)) - return [ "block" ]; - scope.directives.push(dir); - return [ this[0], dir ]; - }, - "call": function(expr, args) { - expr = walk(expr); - if (options.unsafe && expr[0] == "dot" && expr[1][0] == "string" && expr[2] == "toString") { - return expr[1]; - } - return [ this[0], expr, MAP(args, walk) ]; - }, - "num": function (num) { - if (!isFinite(num)) - return [ "binary", "/", num === 1 / 0 - ? [ "num", 1 ] : num === -1 / 0 - ? [ "unary-prefix", "-", [ "num", 1 ] ] - : [ "num", 0 ], [ "num", 0 ] ]; - - return [ this[0], num ]; - } - }, function() { - for (var i = 0; i < 2; ++i) { - ast = prepare_ifs(ast); - ast = walk(ast_add_scope(ast)); - } - return ast; - }); -}; - -/* -----[ re-generate code from the AST ]----- */ - -var DOT_CALL_NO_PARENS = jsp.array_to_hash([ - "name", - "array", - "object", - "string", - "dot", - "sub", - "call", - "regexp", - "defun" -]); - -function make_string(str, ascii_only) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ - switch (s) { - case "\\": return "\\\\"; - case "\b": return "\\b"; - case "\f": return "\\f"; - case "\n": return "\\n"; - case "\r": return "\\r"; - case "\u2028": return "\\u2028"; - case "\u2029": return "\\u2029"; - case '"': ++dq; return '"'; - case "'": ++sq; return "'"; - case "\0": return "\\0"; - } - return s; - }); - if (ascii_only) str = to_ascii(str); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; - else return '"' + str.replace(/\x22/g, '\\"') + '"'; -}; - -function to_ascii(str) { - return str.replace(/[\u0080-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - while (code.length < 4) code = "0" + code; - return "\\u" + code; - }); -}; - -var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); - -function gen_code(ast, options) { - options = defaults(options, { - indent_start : 0, - indent_level : 4, - quote_keys : false, - space_colon : false, - beautify : false, - ascii_only : false, - inline_script: false - }); - var beautify = !!options.beautify; - var indentation = 0, - newline = beautify ? "\n" : "", - space = beautify ? " " : ""; - - function encode_string(str) { - var ret = make_string(str, options.ascii_only); - if (options.inline_script) - ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); - return ret; - }; - - function make_name(name) { - name = name.toString(); - if (options.ascii_only) - name = to_ascii(name); - return name; - }; - - function indent(line) { - if (line == null) - line = ""; - if (beautify) - line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; - return line; - }; - - function with_indent(cont, incr) { - if (incr == null) incr = 1; - indentation += incr; - try { return cont.apply(null, slice(arguments, 1)); } - finally { indentation -= incr; } - }; - - function add_spaces(a) { - if (beautify) - return a.join(" "); - var b = []; - for (var i = 0; i < a.length; ++i) { - var next = a[i + 1]; - b.push(a[i]); - if (next && - ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || - (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { - b.push(" "); - } - } - return b.join(""); - }; - - function add_commas(a) { - return a.join("," + space); - }; - - function parenthesize(expr) { - var gen = make(expr); - for (var i = 1; i < arguments.length; ++i) { - var el = arguments[i]; - if ((el instanceof Function && el(expr)) || expr[0] == el) - return "(" + gen + ")"; - } - return gen; - }; - - function best_of(a) { - if (a.length == 1) { - return a[0]; - } - if (a.length == 2) { - var b = a[1]; - a = a[0]; - return a.length <= b.length ? a : b; - } - return best_of([ a[0], best_of(a.slice(1)) ]); - }; - - function needs_parens(expr) { - if (expr[0] == "function" || expr[0] == "object") { - // dot/call on a literal function requires the - // function literal itself to be parenthesized - // only if it's the first "thing" in a - // statement. This means that the parent is - // "stat", but it could also be a "seq" and - // we're the first in this "seq" and the - // parent is "stat", and so on. Messy stuff, - // but it worths the trouble. - var a = slice(w.stack()), self = a.pop(), p = a.pop(); - while (p) { - if (p[0] == "stat") return true; - if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || - ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { - self = p; - p = a.pop(); - } else { - return false; - } - } - } - return !HOP(DOT_CALL_NO_PARENS, expr[0]); - }; - - function make_num(num) { - var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m; - if (Math.floor(num) === num) { - if (num >= 0) { - a.push("0x" + num.toString(16).toLowerCase(), // probably pointless - "0" + num.toString(8)); // same. - } else { - a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless - "-0" + (-num).toString(8)); // same. - } - if ((m = /^(.*?)(0+)$/.exec(num))) { - a.push(m[1] + "e" + m[2].length); - } - } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { - a.push(m[2] + "e-" + (m[1].length + m[2].length), - str.substr(str.indexOf("."))); - } - return best_of(a); - }; - - var w = ast_walker(); - var make = w.walk; - return w.with_walkers({ - "string": encode_string, - "num": make_num, - "name": make_name, - "debugger": function(){ return "debugger;" }, - "toplevel": function(statements) { - return make_block_statements(statements) - .join(newline + newline); - }, - "splice": function(statements) { - var parent = w.parent(); - if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { - // we need block brackets in this case - return make_block.apply(this, arguments); - } else { - return MAP(make_block_statements(statements, true), - function(line, i) { - // the first line is already indented - return i > 0 ? indent(line) : line; - }).join(newline); - } - }, - "block": make_block, - "var": function(defs) { - return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "const": function(defs) { - return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "try": function(tr, ca, fi) { - var out = [ "try", make_block(tr) ]; - if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); - if (fi) out.push("finally", make_block(fi)); - return add_spaces(out); - }, - "throw": function(expr) { - return add_spaces([ "throw", make(expr) ]) + ";"; - }, - "new": function(ctor, args) { - args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){ - return parenthesize(expr, "seq"); - })) + ")" : ""; - return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ - var w = ast_walker(), has_call = {}; - try { - w.with_walkers({ - "call": function() { throw has_call }, - "function": function() { return this } - }, function(){ - w.walk(expr); - }); - } catch(ex) { - if (ex === has_call) - return true; - throw ex; - } - }) + args ]); - }, - "switch": function(expr, body) { - return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); - }, - "break": function(label) { - var out = "break"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "continue": function(label) { - var out = "continue"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "conditional": function(co, th, el) { - return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", - parenthesize(th, "seq"), ":", - parenthesize(el, "seq") ]); - }, - "assign": function(op, lvalue, rvalue) { - if (op && op !== true) op += "="; - else op = "="; - return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); - }, - "dot": function(expr) { - var out = make(expr), i = 1; - if (expr[0] == "num") { - if (!/[a-f.]/i.test(out)) - out += "."; - } else if (expr[0] != "function" && needs_parens(expr)) - out = "(" + out + ")"; - while (i < arguments.length) - out += "." + make_name(arguments[i++]); - return out; - }, - "call": function(func, args) { - var f = make(func); - if (f.charAt(0) != "(" && needs_parens(func)) - f = "(" + f + ")"; - return f + "(" + add_commas(MAP(args, function(expr){ - return parenthesize(expr, "seq"); - })) + ")"; - }, - "function": make_function, - "defun": make_function, - "if": function(co, th, el) { - var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; - if (el) { - out.push("else", make(el)); - } - return add_spaces(out); - }, - "for": function(init, cond, step, block) { - var out = [ "for" ]; - init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); - cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); - step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); - var args = init + cond + step; - if (args == "; ; ") args = ";;"; - out.push("(" + args + ")", make(block)); - return add_spaces(out); - }, - "for-in": function(vvar, key, hash, block) { - return add_spaces([ "for", "(" + - (vvar ? make(vvar).replace(/;+$/, "") : make(key)), - "in", - make(hash) + ")", make(block) ]); - }, - "while": function(condition, block) { - return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); - }, - "do": function(condition, block) { - return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; - }, - "return": function(expr) { - var out = [ "return" ]; - if (expr != null) out.push(make(expr)); - return add_spaces(out) + ";"; - }, - "binary": function(operator, lvalue, rvalue) { - var left = make(lvalue), right = make(rvalue); - // XXX: I'm pretty sure other cases will bite here. - // we need to be smarter. - // adding parens all the time is the safest bet. - if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || - lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] || - lvalue[0] == "function" && needs_parens(this)) { - left = "(" + left + ")"; - } - if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && - !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { - right = "(" + right + ")"; - } - else if (!beautify && options.inline_script && (operator == "<" || operator == "<<") - && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) { - right = " " + right; - } - return add_spaces([ left, operator, right ]); - }, - "unary-prefix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; - }, - "unary-postfix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return val + operator; - }, - "sub": function(expr, subscript) { - var hash = make(expr); - if (needs_parens(expr)) - hash = "(" + hash + ")"; - return hash + "[" + make(subscript) + "]"; - }, - "object": function(props) { - var obj_needs_parens = needs_parens(this); - if (props.length == 0) - return obj_needs_parens ? "({})" : "{}"; - var out = "{" + newline + with_indent(function(){ - return MAP(props, function(p){ - if (p.length == 3) { - // getter/setter. The name is in p[0], the arg.list in p[1][2], the - // body in p[1][3] and type ("get" / "set") in p[2]. - return indent(make_function(p[0], p[1][2], p[1][3], p[2], true)); - } - var key = p[0], val = parenthesize(p[1], "seq"); - if (options.quote_keys) { - key = encode_string(key); - } else if ((typeof key == "number" || !beautify && +key + "" == key) - && parseFloat(key) >= 0) { - key = make_num(+key); - } else if (!is_identifier(key)) { - key = encode_string(key); - } - return indent(add_spaces(beautify && options.space_colon - ? [ key, ":", val ] - : [ key + ":", val ])); - }).join("," + newline); - }) + newline + indent("}"); - return obj_needs_parens ? "(" + out + ")" : out; - }, - "regexp": function(rx, mods) { - if (options.ascii_only) rx = to_ascii(rx); - return "/" + rx + "/" + mods; - }, - "array": function(elements) { - if (elements.length == 0) return "[]"; - return add_spaces([ "[", add_commas(MAP(elements, function(el, i){ - if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : ""; - return parenthesize(el, "seq"); - })), "]" ]); - }, - "stat": function(stmt) { - return make(stmt).replace(/;*\s*$/, ";"); - }, - "seq": function() { - return add_commas(MAP(slice(arguments), make)); - }, - "label": function(name, block) { - return add_spaces([ make_name(name), ":", make(block) ]); - }, - "with": function(expr, block) { - return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); - }, - "atom": function(name) { - return make_name(name); - }, - "directive": function(dir) { - return make_string(dir) + ";"; - } - }, function(){ return make(ast) }); - - // The squeezer replaces "block"-s that contain only a single - // statement with the statement itself; technically, the AST - // is correct, but this can create problems when we output an - // IF having an ELSE clause where the THEN clause ends in an - // IF *without* an ELSE block (then the outer ELSE would refer - // to the inner IF). This function checks for this case and - // adds the block brackets if needed. - function make_then(th) { - if (th == null) return ";"; - if (th[0] == "do") { - // https://github.com/mishoo/UglifyJS/issues/#issue/57 - // IE croaks with "syntax error" on code like this: - // if (foo) do ... while(cond); else ... - // we need block brackets around do/while - return make_block([ th ]); - } - var b = th; - while (true) { - var type = b[0]; - if (type == "if") { - if (!b[3]) - // no else, we must add the block - return make([ "block", [ th ]]); - b = b[3]; - } - else if (type == "while" || type == "do") b = b[2]; - else if (type == "for" || type == "for-in") b = b[4]; - else break; - } - return make(th); - }; - - function make_function(name, args, body, keyword, no_parens) { - var out = keyword || "function"; - if (name) { - out += " " + make_name(name); - } - out += "(" + add_commas(MAP(args, make_name)) + ")"; - out = add_spaces([ out, make_block(body) ]); - return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out; - }; - - function must_has_semicolon(node) { - switch (node[0]) { - case "with": - case "while": - return empty(node[2]) || must_has_semicolon(node[2]); - case "for": - case "for-in": - return empty(node[4]) || must_has_semicolon(node[4]); - case "if": - if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else' - if (node[3]) { - if (empty(node[3])) return true; // `else' present but empty - return must_has_semicolon(node[3]); // dive into the `else' branch - } - return must_has_semicolon(node[2]); // dive into the `then' branch - case "directive": - return true; - } - }; - - function make_block_statements(statements, noindent) { - for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { - var stat = statements[i]; - var code = make(stat); - if (code != ";") { - if (!beautify && i == last && !must_has_semicolon(stat)) { - code = code.replace(/;+\s*$/, ""); - } - a.push(code); - } - } - return noindent ? a : MAP(a, indent); - }; - - function make_switch_block(body) { - var n = body.length; - if (n == 0) return "{}"; - return "{" + newline + MAP(body, function(branch, i){ - var has_body = branch[1].length > 0, code = with_indent(function(){ - return indent(branch[0] - ? add_spaces([ "case", make(branch[0]) + ":" ]) - : "default:"); - }, 0.5) + (has_body ? newline + with_indent(function(){ - return make_block_statements(branch[1]).join(newline); - }) : ""); - if (!beautify && has_body && i < n - 1) - code += ";"; - return code; - }).join(newline) + newline + indent("}"); - }; - - function make_block(statements) { - if (!statements) return ";"; - if (statements.length == 0) return "{}"; - return "{" + newline + with_indent(function(){ - return make_block_statements(statements).join(newline); - }) + newline + indent("}"); - }; - - function make_1vardef(def) { - var name = def[0], val = def[1]; - if (val != null) - name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); - return name; - }; - -}; - -function split_lines(code, max_line_length) { - var splits = [ 0 ]; - jsp.parse(function(){ - var next_token = jsp.tokenizer(code); - var last_split = 0; - var prev_token; - function current_length(tok) { - return tok.pos - last_split; - }; - function split_here(tok) { - last_split = tok.pos; - splits.push(last_split); - }; - function custom(){ - var tok = next_token.apply(this, arguments); - out: { - if (prev_token) { - if (prev_token.type == "keyword") break out; - } - if (current_length(tok) > max_line_length) { - switch (tok.type) { - case "keyword": - case "atom": - case "name": - case "punc": - split_here(tok); - break out; - } - } - } - prev_token = tok; - return tok; - }; - custom.context = function() { - return next_token.context.apply(this, arguments); - }; - return custom; - }()); - return splits.map(function(pos, i){ - return code.substring(pos, splits[i + 1] || code.length); - }).join("\n"); -}; - -/* -----[ Utilities ]----- */ - -function repeat_string(str, i) { - if (i <= 0) return ""; - if (i == 1) return str; - var d = repeat_string(str, i >> 1); - d += d; - if (i & 1) d += str; - return d; -}; - -function defaults(args, defs) { - var ret = {}; - if (args === true) - args = {}; - for (var i in defs) if (HOP(defs, i)) { - ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; - } - return ret; -}; - -function is_identifier(name) { - return /^[a-z_$][a-z0-9_$]*$/i.test(name) - && name != "this" - && !HOP(jsp.KEYWORDS_ATOM, name) - && !HOP(jsp.RESERVED_WORDS, name) - && !HOP(jsp.KEYWORDS, name); -}; - -function HOP(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -}; - -// some utilities - -var MAP; - -(function(){ - MAP = function(a, f, o) { - var ret = [], top = [], i; - function doit() { - var val = f.call(o, a[i], i); - if (val instanceof AtTop) { - val = val.v; - if (val instanceof Splice) { - top.push.apply(top, val.v); - } else { - top.push(val); - } - } - else if (val != skip) { - if (val instanceof Splice) { - ret.push.apply(ret, val.v); - } else { - ret.push(val); - } - } - }; - if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); - else for (i in a) if (HOP(a, i)) doit(); - return top.concat(ret); - }; - MAP.at_top = function(val) { return new AtTop(val) }; - MAP.splice = function(val) { return new Splice(val) }; - var skip = MAP.skip = {}; - function AtTop(val) { this.v = val }; - function Splice(val) { this.v = val }; -})(); - -/* -----[ Exports ]----- */ - -exports.ast_walker = ast_walker; -exports.ast_mangle = ast_mangle; -exports.ast_squeeze = ast_squeeze; -exports.ast_lift_variables = ast_lift_variables; -exports.gen_code = gen_code; -exports.ast_add_scope = ast_add_scope; -exports.set_logger = function(logger) { warn = logger }; -exports.make_string = make_string; -exports.split_lines = split_lines; -exports.MAP = MAP; - -// keep this last! -exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; diff --git a/build/vendor/uglify/squeeze-more.js b/build/vendor/uglify/squeeze-more.js deleted file mode 100755 index 3721f89..0000000 --- a/build/vendor/uglify/squeeze-more.js +++ /dev/null @@ -1,74 +0,0 @@ -var jsp = require("./parse-js"), - pro = require("./process"), - slice = jsp.slice, - member = jsp.member, - curry = jsp.curry, - MAP = pro.MAP, - PRECEDENCE = jsp.PRECEDENCE, - OPERATORS = jsp.OPERATORS; - -function ast_squeeze_more(ast) { - var w = pro.ast_walker(), walk = w.walk, scope; - function with_scope(s, cont) { - var save = scope, ret; - scope = s; - ret = cont(); - scope = save; - return ret; - }; - function _lambda(name, args, body) { - return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ]; - }; - return w.with_walkers({ - "toplevel": function(body) { - return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ]; - }, - "function": _lambda, - "defun": _lambda, - "new": function(ctor, args) { - if (ctor[0] == "name") { - if (ctor[1] == "Array" && !scope.has("Array")) { - if (args.length != 1) { - return [ "array", args ]; - } else { - return walk([ "call", [ "name", "Array" ], args ]); - } - } else if (ctor[1] == "Object" && !scope.has("Object")) { - if (!args.length) { - return [ "object", [] ]; - } else { - return walk([ "call", [ "name", "Object" ], args ]); - } - } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) { - return walk([ "call", [ "name", ctor[1] ], args]); - } - } - }, - "call": function(expr, args) { - if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1 - && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) { - return [ "call", [ "dot", expr[1], "slice"], args]; - } - if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) { - // foo.toString() ==> foo+"" - if (expr[1][0] == "string") return expr[1]; - return [ "binary", "+", expr[1], [ "string", "" ]]; - } - if (expr[0] == "name") { - if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { - return [ "array", args ]; - } - if (expr[1] == "Object" && !args.length && !scope.has("Object")) { - return [ "object", [] ]; - } - if (expr[1] == "String" && !scope.has("String")) { - return [ "binary", "+", args[0], [ "string", "" ]]; - } - } - } - }, function() { - return walk(pro.ast_add_scope(ast)); - }); -}; - -exports.ast_squeeze_more = ast_squeeze_more;