From 789308a12a3f16a9ff67844b26044fb8ff9e156a Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Wed, 10 Jun 2015 14:36:22 +0200 Subject: [PATCH 01/18] add empty planner package --- .meteor/packages | 1 + .meteor/versions | 1 + packages/planner/README.md | 0 packages/planner/package.js | 22 ++++++++++++++++++++++ packages/planner/planner-tests.js | 5 +++++ packages/planner/planner.js | 1 + 6 files changed, 30 insertions(+) create mode 100644 packages/planner/README.md create mode 100644 packages/planner/package.js create mode 100644 packages/planner/planner-tests.js create mode 100644 packages/planner/planner.js diff --git a/.meteor/packages b/.meteor/packages index f504d7d6..141449c4 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -45,3 +45,4 @@ rzymek:moment-locale-nl appshore:recaptcha tmeasday:publish-counts tail:core +planner diff --git a/.meteor/versions b/.meteor/versions index 75a2a932..c11bcd16 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -76,6 +76,7 @@ ordered-dict@1.0.3 percolate:paginated-subscription@0.2.4 percolate:synced-cron@1.2.0 percolate:velocityjs@1.2.1_1 +planner@0.0.1 qnub:emojione@0.0.3 random@1.0.3 reactive-dict@1.1.0 diff --git a/packages/planner/README.md b/packages/planner/README.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/planner/package.js b/packages/planner/package.js new file mode 100644 index 00000000..d08be307 --- /dev/null +++ b/packages/planner/package.js @@ -0,0 +1,22 @@ +Package.describe({ + name: 'planner', + version: '0.0.1', + // Brief, one-line summary of the package. + summary: 'The plan algorithm of simplyHomework.', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.1.0.2'); + api.addFiles('planner.js'); +}); + +Package.onTest(function(api) { + api.use('tinytest'); + api.use('planner'); + api.addFiles('planner-tests.js'); +}); diff --git a/packages/planner/planner-tests.js b/packages/planner/planner-tests.js new file mode 100644 index 00000000..c5623d89 --- /dev/null +++ b/packages/planner/planner-tests.js @@ -0,0 +1,5 @@ +// Write your tests here! +// Here is an example. +Tinytest.add('example', function (test) { + test.equal(true, true); +}); diff --git a/packages/planner/planner.js b/packages/planner/planner.js new file mode 100644 index 00000000..164ddd9e --- /dev/null +++ b/packages/planner/planner.js @@ -0,0 +1 @@ +// Write your package code here! From 0f2444e615f408d11c7663c8bd654686fc4d5c28 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Wed, 10 Jun 2015 14:42:27 +0200 Subject: [PATCH 02/18] Beginning for planner --- packages/planner/planner.js | 94 ++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 164ddd9e..ad6dad34 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -1 +1,93 @@ -// Write your package code here! +var assert=require("assert"); + +function HomeworkDescription(){ + if(!(this instanceof HomeworkDescription))return new HomeworkDescription; + + //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type + // and unique and fixed, i.e. there is only one identifier per subject and only one subject per identifier. + this.subject=null; + + //Items in `location` can be multiple things, e.g. + //- [chapter,paragraph,exercise] + //- [bookid,page,exercise] + //- [chapter,exercise] + //- [bookid,page] + //In general, anything that can be expressed in a sequence of integers that specifies the location. + //The `location` property contains an array of those, because homework can be multiple exercises, for example. + //Please make the array contiguous, though; don't mix indexing conventions! (!) (!!) + this.location=[]; +} + +function Planner(){ + if(!(this instanceof Planner))return new Planner; + + var subjects={}; //The Cache + + //`timetaken` in any unit you find convenient; but please be consistent. Suggestion: seconds. + this.learn=function(hwdesc,timetaken){ + var i,j,idx,subj,loc; + assert(hwdesc instanceof HomeworkDescription); + subj=hwdesc.subject; + loc=hwdesc.location; + assert(loc.length!=0); + if(!subjects[subj]){ + subjects[subj]=new Array(loc[0].length); + for(i=0;i Date: Wed, 10 Jun 2015 14:48:03 +0200 Subject: [PATCH 03/18] meteorify current planner --- packages/planner/package.js | 31 +++++++++++++++++-------------- packages/planner/planner.js | 13 +++---------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/packages/planner/package.js b/packages/planner/package.js index d08be307..6f8b1b61 100644 --- a/packages/planner/package.js +++ b/packages/planner/package.js @@ -1,22 +1,25 @@ Package.describe({ - name: 'planner', - version: '0.0.1', - // Brief, one-line summary of the package. - summary: 'The plan algorithm of simplyHomework.', - // URL to the Git repository containing the source code for this package. - git: '', - // By default, Meteor will default to using README.md for documentation. - // To avoid submitting documentation, set this field to null. - documentation: 'README.md' + name: 'planner', + version: '0.0.1', + // Brief, one-line summary of the package. + summary: 'The plan algorithm of simplyHomework.', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' }); Package.onUse(function(api) { - api.versionsFrom('1.1.0.2'); - api.addFiles('planner.js'); + api.versionsFrom('1.1.0.2'); + api.addFiles('planner.js'); + + api.export("HomeworkDescription"); + api.export("Planner"); }); Package.onTest(function(api) { - api.use('tinytest'); - api.use('planner'); - api.addFiles('planner-tests.js'); + api.use('tinytest'); + api.use('planner'); + api.addFiles('planner-tests.js'); }); diff --git a/packages/planner/planner.js b/packages/planner/planner.js index ad6dad34..868cc40a 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -1,6 +1,6 @@ -var assert=require("assert"); +var assert = Npm.require("assert"); -function HomeworkDescription(){ +HomeworkDescription = function () { if(!(this instanceof HomeworkDescription))return new HomeworkDescription; //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type @@ -18,7 +18,7 @@ function HomeworkDescription(){ this.location=[]; } -function Planner(){ +Planner = function () { if(!(this instanceof Planner))return new Planner; var subjects={}; //The Cache @@ -74,13 +74,6 @@ function rms(arr){ return Math.sqrt(sum/len); } - - -module.exports={ - HomeworkDescription:HomeworkDescription, - Planner:Planner -}; - /* var REQ=require("./planner"); var h=REQ.HomeworkDescription(); From 41b7f21521a4d2d7f63edd4bb7c2f4b900f08423 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Wed, 10 Jun 2015 16:24:55 +0200 Subject: [PATCH 04/18] Make planner meteory and nodey at the same time --- packages/planner/planner.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 868cc40a..51cc6e24 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -1,6 +1,8 @@ -var assert = Npm.require("assert"); +var assert; +if(typeof Meteor!="undefined")assert=Npm.require("assert"); +else assert=require("assert"); -HomeworkDescription = function () { +HomeworkDescription=function(){ if(!(this instanceof HomeworkDescription))return new HomeworkDescription; //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type @@ -18,7 +20,7 @@ HomeworkDescription = function () { this.location=[]; } -Planner = function () { +Planner=function(){ if(!(this instanceof Planner))return new Planner; var subjects={}; //The Cache @@ -74,6 +76,13 @@ function rms(arr){ return Math.sqrt(sum/len); } +if(typeof Meteor=="undefined"){ + module.exports={ + HomeworkDescription:HomeworkDescription, + Planner:Planner + }; +} + /* var REQ=require("./planner"); var h=REQ.HomeworkDescription(); From 5fe4f75baf654aaf2ac81fed748bef13d814e4ff Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Fri, 12 Jun 2015 20:10:56 +0200 Subject: [PATCH 05/18] add module info to planner --- packages/planner/planner.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 51cc6e24..a79cc7b7 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -1,3 +1,9 @@ +/* + * simplyHomework plan algorithm and stuff. + * @author simply + * @module planner + */ + var assert; if(typeof Meteor!="undefined")assert=Npm.require("assert"); else assert=require("assert"); From 8a41a64a0e3989c11122be23ad87f9fd0609dcc8 Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Fri, 17 Jul 2015 02:28:03 +0200 Subject: [PATCH 06/18] make planner runnable clientside --- packages/planner/planner.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index a79cc7b7..275b272d 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -4,9 +4,9 @@ * @module planner */ -var assert; -if(typeof Meteor!="undefined")assert=Npm.require("assert"); -else assert=require("assert"); +var assert = function (val) { + if (!val) throw new Error("AssertionError: false == true"); +}; HomeworkDescription=function(){ if(!(this instanceof HomeworkDescription))return new HomeworkDescription; From 9365b6a575ec07602f2d2b1d2ccf9eaf8abab52f Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Thu, 27 Aug 2015 20:18:15 +0200 Subject: [PATCH 07/18] Add deepcopy to repo --- .../planner/node_modules/deepcopy/.npmignore | 4 + .../planner/node_modules/deepcopy/HISTORY.md | 46 + .../planner/node_modules/deepcopy/LICENSE | 21 + .../planner/node_modules/deepcopy/README.md | 156 + .../planner/node_modules/deepcopy/bower.json | 14 + .../bower_components/es5-shim/.bower.json | 43 + .../bower_components/es5-shim/CHANGES | 176 + .../bower_components/es5-shim/CONTRIBUTORS.md | 27 + .../bower_components/es5-shim/LICENSE | 22 + .../bower_components/es5-shim/Makefile | 23 + .../bower_components/es5-shim/README.md | 167 + .../bower_components/es5-shim/bower.json | 34 + .../bower_components/es5-shim/component.json | 19 + .../bower_components/es5-shim/es5-sham.js | 496 + .../bower_components/es5-shim/es5-sham.map | 1 + .../bower_components/es5-shim/es5-sham.min.js | 7 + .../bower_components/es5-shim/es5-shim.js | 1435 ++ .../bower_components/es5-shim/es5-shim.map | 1 + .../bower_components/es5-shim/es5-shim.min.js | 7 + .../bower_components/es5-shim/package.json | 74 + .../bower_components/es5-shim/shims.json | 7 + .../bower_components/mocha/.bower.json | 56 + .../bower_components/mocha/.editorconfig | 18 + .../deepcopy/bower_components/mocha/.mailmap | 1 + .../bower_components/mocha/CONTRIBUTING.md | 49 + .../bower_components/mocha/HISTORY.md | 801 ++ .../deepcopy/bower_components/mocha/LICENSE | 22 + .../deepcopy/bower_components/mocha/README.md | 226 + .../bower_components/mocha/bower.json | 47 + .../bower_components/mocha/media/logo.svg | 7 + .../deepcopy/bower_components/mocha/mocha.css | 270 + .../deepcopy/bower_components/mocha/mocha.js | 6298 +++++++++ .../bower_components/power-assert/.bower.json | 56 + .../power-assert/CHANGELOG.md | 217 + .../power-assert/MIT-LICENSE.txt | 20 + .../bower_components/power-assert/README.md | 982 ++ .../bower_components/power-assert/bower.json | 46 + .../power-assert/build/power-assert.js | 11647 ++++++++++++++++ .../planner/node_modules/deepcopy/deepcopy.js | 229 + .../node_modules/deepcopy/package.json | 69 + .../planner/node_modules/deepcopy/testem.json | 5 + 41 files changed, 23846 insertions(+) create mode 100644 packages/planner/node_modules/deepcopy/.npmignore create mode 100644 packages/planner/node_modules/deepcopy/HISTORY.md create mode 100644 packages/planner/node_modules/deepcopy/LICENSE create mode 100644 packages/planner/node_modules/deepcopy/README.md create mode 100644 packages/planner/node_modules/deepcopy/bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/CONTRIBUTORS.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/LICENSE create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/Makefile create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/README.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/component.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.js create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.map create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.min.js create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.js create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.map create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.min.js create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/package.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/shims.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.editorconfig create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.mailmap create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/CONTRIBUTING.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/HISTORY.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/LICENSE create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/README.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/media/logo.svg create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/mocha.css create mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/mocha.js create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/.bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/CHANGELOG.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/MIT-LICENSE.txt create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/README.md create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json create mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js create mode 100644 packages/planner/node_modules/deepcopy/deepcopy.js create mode 100644 packages/planner/node_modules/deepcopy/package.json create mode 100644 packages/planner/node_modules/deepcopy/testem.json diff --git a/packages/planner/node_modules/deepcopy/.npmignore b/packages/planner/node_modules/deepcopy/.npmignore new file mode 100644 index 00000000..7cd09eab --- /dev/null +++ b/packages/planner/node_modules/deepcopy/.npmignore @@ -0,0 +1,4 @@ +deepcopy.min.js +.closurelinter +.travis.yml +test/ diff --git a/packages/planner/node_modules/deepcopy/HISTORY.md b/packages/planner/node_modules/deepcopy/HISTORY.md new file mode 100644 index 00000000..ab2105d3 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/HISTORY.md @@ -0,0 +1,46 @@ +# 0.5.0 / 2015-04-11 + + - supported for Symbol + +# 0.4.0 / 2015-01-10 + + - refactored + - bugfix for Firefox + - supported for Buffer (node.js only) + - changed to use power-assert from expect.js + +# 0.3.3 / 2013-12-03 + + - bugfix + - thanks to @kjirou + +# 0.3.2 / 2013-09-08 + + - more compressed deepcopy.min.js + - changed from chai to expect.js + +# 0.3.1 / 2013-06-12 + + - changed from Array#indexOf to indexOfArray + +# 0.3.0 / 2013-06-01 + + - added support for browser + - changed repository name to deepcopy.js from deepcopy + +# 0.2.0 / 2013-05-26 + + - added support for circular reference + - rewrote README.md + +# 0.1.2 / 2013-03-29 + + - added support for node.js 0.10 + +# 0.1.1 / 2013-01-28 + + - rewrote README.md + +# 0.1.0 / 2013-01-26 + + - initial release diff --git a/packages/planner/node_modules/deepcopy/LICENSE b/packages/planner/node_modules/deepcopy/LICENSE new file mode 100644 index 00000000..95dccda6 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/LICENSE @@ -0,0 +1,21 @@ +(The MIT LICENSE) + +Copyright (c) 2013 sasa+1 + +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 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. diff --git a/packages/planner/node_modules/deepcopy/README.md b/packages/planner/node_modules/deepcopy/README.md new file mode 100644 index 00000000..f2ea14aa --- /dev/null +++ b/packages/planner/node_modules/deepcopy/README.md @@ -0,0 +1,156 @@ +# deepcopy.js + +[![Build Status](https://travis-ci.org/sasaplus1/deepcopy.js.svg)](https://travis-ci.org/sasaplus1/deepcopy.js) +[![Dependency Status](https://gemnasium.com/sasaplus1/deepcopy.js.svg)](https://gemnasium.com/sasaplus1/deepcopy.js) +[![NPM version](https://badge.fury.io/js/deepcopy.svg)](http://badge.fury.io/js/deepcopy) +[![Bower version](https://badge.fury.io/bo/deepcopy.svg)](http://badge.fury.io/bo/deepcopy) + +deep copy for any data + +## Installation + +### npm + +```sh +$ npm install deepcopy +``` + +### bower + +```sh +$ bower install deepcopy +``` + +## Usage + +### node.js + +```js +var deepcopy = require('deepcopy'); +``` + +### browser + +```html + +``` + +define `deepcopy` by `define()` if using AMD loader. + +otherwise `deepcopy` export to global. + +### Example + +```js +var data, shallow, deep; + +data = { + objects: { + array: [ + null, undefined, new Date, /deepcopy/ig + ], + object: { + number: NaN, + string: 'A', + boolean: true + }, + to: null + } +}; + +// circular reference +data.objects.to = data; + +// shallow copy and deep copy +shallow = data; +deep = deepcopy(data); + +// remove entry +delete data.objects; + +// results +console.log(data); +// {} +console.log(shallow); +// {} +console.log(require('util').inspect(deep, { depth: null })); +// { objects: +// { array: +// [ null, +// undefined, +// Sat Jan 10 2015 03:18:32 GMT+0900 (JST), +// /deepcopy/gi ], +// object: { number: NaN, string: 'A', boolean: true }, +// to: [Circular] } } +``` + +```js +var data, deep; + +data = { object: {} }; +data.object[Symbol.for('sym')] = 123; + +deep = deepcopy(data); + +delete data.object; + +console.log(data.object); +// undefined +console.log(deep.object[Symbol.for('sym')]); +// 123 +``` + +## Functions + +### deepcopy(value) + +* `value` + * `*` - copy target value +* `return` + * `*` - deep copied value + +return deep copied value. + +supported types are below: + +* Number +* String +* Boolean +* Null +* Undefined +* Function (shallow copy) +* Date +* RegExp +* Array + * recursive copy + * also can copy if it has circular reference +* Object + * recursive copy + * also can copy if it has circular reference +* Buffer (node.js only) +* Symbol + +## Test + +### node.js + +```sh +$ npm install +$ npm test +``` + +### browser + +```sh +$ npm install +$ npm run bower +$ npm run testem +``` + +## Contributors + +* [kjirou](https://github.com/kjirou) + +## License + +The MIT license. Please see LICENSE file. diff --git a/packages/planner/node_modules/deepcopy/bower.json b/packages/planner/node_modules/deepcopy/bower.json new file mode 100644 index 00000000..8cc555c6 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/bower.json @@ -0,0 +1,14 @@ +{ + "name": "deepcopy", + "main": "./deepcopy.min.js", + "ignore": [ + "**/.*", + "node_modules", + "bower_components" + ], + "devDependencies": { + "es5-shim": "~4.0", + "mocha": "~2.1", + "power-assert": "~0.10" + } +} diff --git a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json new file mode 100644 index 00000000..a856b1f8 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json @@ -0,0 +1,43 @@ +{ + "name": "es5-shim", + "version": "4.0.6", + "main": "es5-shim.js", + "repository": { + "type": "git", + "url": "git://github.com/es-shims/es5-shim" + }, + "homepage": "https://github.com/es-shims/es5-shim", + "authors": [ + "Kris Kowal (http://github.com/kriskowal/)", + "Sami Samhuri (http://samhuri.net/)", + "Florian Schäfer (http://github.com/fschaefer)", + "Irakli Gozalishvili (http://jeditoolkit.com)", + "Kit Cambridge (http://kitcambridge.github.com)", + "Jordan Harband (https://github.com/ljharb/)" + ], + "description": "ECMAScript 5 compatibility shims for legacy JavaScript engines", + "keywords": [ + "shim", + "es5", + "es5 shim", + "javascript", + "ecmascript", + "polyfill" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "tests" + ], + "_release": "4.0.6", + "_resolution": { + "type": "version", + "tag": "v4.0.6", + "commit": "aeb6b1cc477d1f452f0badff4631aba9ba501562" + }, + "_source": "git://github.com/es-shims/es5-shim.git", + "_target": "~4.0", + "_originalSource": "es5-shim" +} \ No newline at end of file diff --git a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES new file mode 100644 index 00000000..d5480c48 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES @@ -0,0 +1,176 @@ +4.0.6 + - Update `jscs`, `uglify-js`, add `eslint` + - es5-sham: fix Object.defineProperty to not check for own properties (#211) + - Fix Array#splice bug in Safari 5 (#284) + - Fix `Object.keys` issue with boxed primitives with extra properties in older browsers. (#242, #285) + +4.0.5 + - Update `jscs` so tests pass + +4.0.4 + - Style/indentation/whitespace cleanups. + - README tweaks + +4.0.3 + - Fix keywords (#268) + - add some Date tests + - Note in README that the es5-sham requires the es5-shim (https://github.com/es-shims/es5-shim/issues/256#issuecomment-52875710) + +4.0.2 + - Start including version numbers in minified files (#267) + +4.0.1 + - Fix legacy arguments object detection in Object.keys (#260) + +4.0.0 + - No longer shim the ES5-spec behavior of splice when `deleteCount` is omitted - since no engines implement it, and ES6 changes it. (#255) + - Use Object.defineProperty where available, so that polyfills are non-enumerable when possible (#250) + - lots of internal refactoring + - Fixed a bug referencing String#indexOf and String#lastIndexOf before polyfilling it (#253, #254) + +3.4.0 + - Removed nonstandard SpiderMonkey extension to Array#splice - when `deleteCount` is omitted, it's now treated as 0. (#192, #239) + - Fix Object.keys with Arguments objects in Safari 5.0 + - Now shimming String#split in Opera 10.6 + - Avoid using "toString" as a variable name, since that breaks Opera + - Internal implementation and test cleanups + +3.3.2 + - Remove an internal "bind" call, which should make the shim a bit faster + - Fix a bug with object boxing in Array#reduceRight that was failing a test in IE 6 + +3.3.1 + - Fixing an Array#splice bug in IE 6/7 + - cleaning up Array#splice tests + +3.3.0 + - Fix Array#reduceRight in node 0.6 and older browsers (#238) + +3.2.0 + - Fix es5-sham UMD definition to work properly with AMD (#237) + - Ensure that Array methods do not autobox context in strict mode (#233) + +3.1.1 + - Update minified files (#231) + +3.1.0 + - Fix String#replace in Firefox up through 29 (#228) + +3.0.2 + - Fix `Function#bind` in IE 7 and 8 (#224, #225, #226) + +3.0.1 + - Version bump to ensure npm has newest minified assets + +3.0.0 + - es5-sham: fix `Object.getPrototypeOf` and `Object.getOwnPropertyDescriptor` for Opera Mini + - Better override noncompliant native ES5 methods: `Array#forEach`, `Array#map`, `Array#filter`, `Array#every`, `Array#some`, `Array#reduce`, `Date.parse`, `String#trim` + - Added spec-compliant shim for `parseInt` + - Ensure `Object.keys` handles more edge cases with `arguments` objects and boxed primitives + - Improve minification of builds + +2.3.0 + - parseInt is now properly shimmed in ES3 browsers to default the radix + - update URLs to point to the new organization + +2.2.0 + - Function.prototype.bind shim now reports correct length on a bound function + - fix node 0.6.x v8 bug in Array#forEach + - test improvements + +2.1.0 + - Object.create fixes + - tweaks to the Object.defineProperties shim + +2.0.0 + - Separate reliable shims from dubious shims (shams). + +1.2.10 + - Group-effort Style Cleanup + - Took a stab at fixing Object.defineProperty on IE8 without + bad side-effects. (@hax) + - Object.isExtensible no longer fakes it. (@xavierm) + - Date.prototype.toISOString no longer deals with partial + ISO dates, per spec (@kitcambridge) + - More (mostly from @bryanforbes) + +1.2.9 + - Corrections to toISOString by @kitcambridge + - Fixed three bugs in array methods revealed by Jasmine tests. + - Cleaned up Function.prototype.bind with more fixes and tests from + @bryanforbes. + +1.2.8 + - Actually fixed problems with Function.prototype.bind, and regressions + from 1.2.7 (@bryanforbes, @jdalton #36) + +1.2.7 - REGRESSED + - Fixed problems with Function.prototype.bind when called as a constructor. + (@jdalton #36) + +1.2.6 + - Revised Date.parse to match ES 5.1 (kitcambridge) + +1.2.5 + - Fixed a bug for padding it Date..toISOString (tadfisher issue #33) + +1.2.4 + - Fixed a descriptor bug in Object.defineProperty (raynos) + +1.2.3 + - Cleaned up RequireJS and + +Then, generate espowered code. + + $ espower test/your_test.js > powered/your_test.js + +Lastly, run your test in your way. For example, + + $ mocha-phantomjs path/to/test.html + + + +### using `grunt-espower` + +On the browser side and you are not using [browserify](http://browserify.org/) but [bower](http://bower.io/) and [Grunt](http://gruntjs.com/), you can use `power-assert` via bower, with generated code by `grunt-espower` + +First, install `power-assert` via bower and `grunt-espower` via npm. This means that you run grunt (on Node), then run tests on browser. + + $ bower install --save-dev power-assert + $ npm install --save-dev grunt-espower + +Second, require `build/power-assert.js` (all-in-one build for browsers) in your test html. + + + +Third, configure `grunt-espower` task to generate espowered code. + +```javascript +grunt.initConfig({ + + . . . + + espower: { + test: { + files: [ + { + expand: true, // Enable dynamic expansion. + cwd: 'test/', // Src matches are relative to this path. + src: ['**/*.js'], // Actual pattern(s) to match. + dest: 'espowered/', // Destination path prefix. + ext: '.js' // Dest filepaths will have this extension. + } + ] + }, + }, + + . . . + +}) +``` + +Then, generate espowered code using `espower` task. + + $ grunt espower:test + +Lastly, run your test in your way. For example, + + $ grunt test + + + + +### using `gulp-espower` + +On the browser side and you are not using [browserify](http://browserify.org/) but [bower](http://bower.io/) and [gulp](http://gulpjs.com/), you can use `power-assert` via bower, with generated code by `gulp-espower` + +First, install `power-assert` via bower and `gulp-espower` via npm. This means that you run gulp (on Node), then run tests on browser. + + $ bower install --save-dev power-assert + $ npm install --save-dev gulp-espower + +Second, require `build/power-assert.js` (all-in-one build for browsers) in your test html. + + + +Third, configure `gulp-espower` task to generate espowered code. + +```javascript +var gulp = require('gulp'), + espower = require('gulp-espower'); + . . . +gulp.task('espower', function() { + return gulp + .src('test/**/*_test.js', {base: './test/'}) + .pipe(espower()) + .pipe(gulp.dest('espowered')); +}); + . . . +}) +``` + +Then, generate espowered code (in this example, using `espower` task). + + $ gulp espower + +Lastly, run your test in your way. For example, + + $ gulp test + + + + +CUSTOMIZATION API +--------------------------------------- + +`power-assert` provides an API for customization. + +### var assert = assert.customize(options) + +Through this API, you can customize power-assert by changing some options. + +```javascript +var assert = require('power-assert').customize({ + output: { + maxDepth: 2 + } +}); +``` + +### options + +`options` has two top-level keys. `assertion` and `output`. + +#### options.assertion + +customization options for [empower](http://github.com/twada/empower) module. See [empower API documentation](https://github.com/twada/empower#api) for details. Note that some default values are different from `empower`'s (`modifyMessageOnRethrow: true` and `saveContextOnRethrow: true`). + +#### options.output + +customization options for [power-assert-formatter](http://github.com/twada/power-assert-formatter) module. See [power-assert-formatter API documentation](https://github.com/twada/power-assert-formatter#api) for details. + +#### default values + +customizable properties and their default values are as follows. + +``` +var assert = require('power-assert').customize({ + assertion: { + destructive: false, + modifyMessageOnRethrow: true, + saveContextOnRethrow: true, + patterns: [ + 'assert(value, [message])', + 'assert.ok(value, [message])', + 'assert.equal(actual, expected, [message])', + 'assert.notEqual(actual, expected, [message])', + 'assert.strictEqual(actual, expected, [message])', + 'assert.notStrictEqual(actual, expected, [message])', + 'assert.deepEqual(actual, expected, [message])', + 'assert.notDeepEqual(actual, expected, [message])' + ] + }, + output: { + lineDiffThreshold: 5, + maxDepth: 1, + anonymous: 'Object', + circular: '#@Circular#', + lineSeparator: '\n', + ambiguousEastAsianCharWidth: 2, + widthOf: (Function to calculate width of string. Please see power-assert-formatter's documentation) + stringify: (Function to stringify any target value. Please see power-assert-formatter's documentation) + diff: (Function to create diff string between two strings. Please see power-assert-formatter's documentation) + writerClass: (Constructor Function for output writer class. Please see power-assert-formatter's documentation) + renderers: [ + './built-in/file', + './built-in/assertion', + './built-in/diagram', + './built-in/binary-expression' + ] + } +}); +``` + + +INTERNAL DESIGN +--------------------------------------- + +`power-assert` family provides 1 main module, 4 core modules and many more instrumentors. + + +Main (facade) module is, + +| module | description | +|:-------|:------------| +| [power-assert](http://github.com/twada/power-assert) | Standard `assert` function on top of `empower` and `power-assert-formatter` | + +core modules are, + +| module | description | +|:-------|:------------| +| [empower](http://github.com/twada/empower) | Power Assert feature enhancer for assert function/object. | +| [power-assert-formatter](http://github.com/twada/power-assert-formatter) | Power Assert output formatter. | +| [espower](http://github.com/twada/espower) | Power Assert feature instrumentor core based on the [Mozilla JavaScript AST](https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API). | +| [espower-source](http://github.com/twada/espower-source) | Power Assert instrumentor from source to source, with source-map. (Thin wrapper of `espower`). | + +and instrumentors are, + +| module | description | +|:-------|:------------| +| [espower-cli](http://github.com/twada/espower-cli) | Command line tool for power-assert. | +| [espower-loader](http://github.com/twada/espower-loader) | Node module loader to apply `espower` on the fly. | +| [intelli-espower-loader](https://github.com/azu/intelli-espower-loader) | configure `espower-loader` with ease. | +| [espowerify](http://github.com/twada/espowerify) | [Browserify](http://browserify.org/) transform to apply `espower` to target files. | +| [webpack-espower-loader](https://github.com/zoncoen/webpack-espower-loader) | Power Assert instrumentor module for [webpack](http://webpack.github.io/). | +| [grunt-espower](http://github.com/twada/grunt-espower) | Grunt task to apply `espower` to target files. | +| [gulp-espower](http://github.com/twada/gulp-espower) | Gulp plugin to apply `espower` to target files. | +| [karma-espower-preprocessor](https://github.com/vvakame/karma-espower-preprocessor) | karma-preprocessor for power-assert. | +| [espower-coffee](http://github.com/twada/espower-coffee) | power-assert instrumentor for CoffeeScript. | +| [espower-traceur](https://github.com/yosuke-furukawa/espower-traceur) | power-assert instrumentor for ES6 using [Traceur Compiler](https://github.com/google/traceur-compiler/). | +| [espower-babel](https://github.com/azu/espower-babel) | power-assert instrumentor for ES6 using [Babel](https://babeljs.io/). | + + +`power-assert` provides standard [assert](http://nodejs.org/api/assert.html) compatible function with Power Assert feature. +(Best fit with [Mocha](http://visionmedia.github.io/mocha/). If you use assert-like objects provided by various testing frameworks such as [QUnit](http://qunitjs.com/) or [nodeunit](https://github.com/caolan/nodeunit). Please use [empower](http://github.com/twada/empower) and [power-assert-formatter](http://github.com/twada/power-assert-formatter) modules directly). + + +Internally, `power-assert` uses [empower](http://github.com/twada/empower) module to enhance power assert feature into the standard [assert](http://nodejs.org/api/assert.html) module, to run with the power assert feature added code by [espower](http://github.com/twada/espower) module, and prettify output using [power-assert-formatter](http://github.com/twada/power-assert-formatter). + + +See [power-assert-demo](http://github.com/twada/power-assert-demo) project for power-assert Demo running with mocha. + + +TESTED FRAMEWORKS +--------------------------------------- +* [Mocha](http://visionmedia.github.io/mocha/) +* [QUnit](http://qunitjs.com/) +* [nodeunit](https://github.com/caolan/nodeunit) +* [buster-assertions](http://docs.busterjs.org/en/latest/modules/buster-assertions/) + + +TESTED ENVIRONMENTS +--------------------------------------- +* [Node.js](http://nodejs.org/) +* [Rhino](https://developer.mozilla.org/en/Rhino) +* [PhantomJS](http://phantomjs.org/) +* [RequireJS](http://requirejs.org/) +* [Browserify](http://browserify.org/) + + +AUTHOR +--------------------------------------- +* [Takuto Wada](http://github.com/twada) + + +CONTRIBUTORS +--------------------------------------- +* [azu](https://github.com/azu) +* [vvakame](https://github.com/vvakame) + + +LICENSE +--------------------------------------- +Licensed under the [MIT](https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt) license. + + + +MORE OUTPUT EXAMPLES +--------------------------------------- + +### Target test code (using QUnit in this example) + +```javascript +var q = require('qunitjs'); + +(function () { + var empower = require('empower'), + formatter = require('power-assert-formatter'), + qunitTap = require("qunit-tap"); + empower(q.assert, formatter(), {destructive: true}); + qunitTap(q, require('util').puts, {showSourceOnFailure: false}); + q.config.autorun = false; +})(); + +q.test('spike', function (assert) { + assert.ok(true); + + var hoge = 'foo'; + var fuga = 'bar'; + assert.ok(hoge === fuga, 'comment'); + + var piyo = 3; + assert.ok(fuga === piyo); + + var longString = 'very very loooooooooooooooooooooooooooooooooooooooooooooooooooong message'; + var anotherLongString = 'yet another loooooooooooooooooooooooooooooooooooooooooooooooooooong message'; + assert.ok(longString === anotherLongString); + + assert.ok(4 === piyo); + + assert.ok(4 !== 4); + + var falsyStr = ''; + assert.ok(falsyStr); + + var falsyNum = 0; + assert.ok(falsyNum); + + var ary1 = ['foo', 'bar']; + var ary2 = ['aaa', 'bbb', 'ccc']; + assert.ok(ary1.length === ary2.length); + assert.deepEqual(ary1, ary2); + + var actual = 16; + assert.ok(5 < actual && actual < 13); + + actual = 4; + assert.ok(5 < actual && actual < 13); + + actual = 10; + assert.ok(actual < 5 || 13 < actual); + + + var propName = 'bar', + foo = { + bar: { + baz: false + } + }; + + assert.ok(foo.bar.baz); + assert.ok(foo['bar'].baz); + assert.ok(foo[propName]['baz']); + + + var truth = true; + assert.ok(!truth); + + + var func = function () { return false; }; + assert.ok(func()); + + + var obj = { + age: function () { + return 0; + } + }; + assert.ok(obj.age()); + + + var isFalsy = function (arg) { + return !(arg); + }; + var positiveInt = 50; + assert.ok(isFalsy(positiveInt)); + + + var sum = function () { + var result = 0; + for (var i = 0; i < arguments.length; i += 1) { + result += arguments[i]; + } + return result; + }; + var one = 1, two = 2, three = 3, seven = 7, ten = 10; + assert.ok(sum(one, two, three) === seven); + assert.ok(sum(sum(one, two), three) === sum(sum(two, three), seven)); + assert.ok((three * (seven * ten)) === three); + + + var math = { + calc: { + sum: function () { + var result = 0; + for (var i = 0; i < arguments.length; i += 1) { + result += arguments[i]; + } + return result; + } + } + }; + assert.ok(math.calc.sum(one, two, three) === seven); +}); + +q.load(); +``` + + +### `espower` code above then running under Node.js + +``` +# module: undefined +# test: spike +ok 1 - okay +not ok 2 - comment # /path/to/examples/qunit_node.js:17 +# +# assert.ok(hoge === fuga, 'comment') +# | | | +# | | "bar" +# | false +# "foo" +# +# --- [string] fuga +# +++ [string] hoge +# @@ -1,3 +1,3 @@ +# -bar +# +foo +# +# , test: spike +not ok 3 - # /path/to/examples/qunit_node.js:20 +# +# assert.ok(fuga === piyo) +# | | | +# | | 3 +# | false +# "bar" +# +# [number] piyo +# => 3 +# [string] fuga +# => "bar" + +# , test: spike +not ok 4 - # /path/to/examples/qunit_node.js:24 +# +# assert.ok(longString === anotherLongString) +# | | | +# | | "yet another loooooooooooooooooooooooooooooooooooooooooooooooooooong message" +# | false +# "very very loooooooooooooooooooooooooooooooooooooooooooooooooooong message" +# +# --- [string] anotherLongString +# +++ [string] longString +# @@ -1,15 +1,13 @@ +# -yet anoth +# +very v +# er +# +y +# loo +# +# , test: spike +not ok 5 - # /path/to/examples/qunit_node.js:26 +# +# assert.ok(4 === piyo) +# | | +# | 3 +# false +# +# [number] piyo +# => 3 +# [number] 4 +# => 4 +# , test: spike +not ok 6 - # /path/to/examples/qunit_node.js:28 +# +# assert.ok(4 !== 4) +# | +# false +# , test: spike +not ok 7 - # /path/to/examples/qunit_node.js:31 +# +# assert.ok(falsyStr) +# | +# "" +# , test: spike +not ok 8 - # /path/to/examples/qunit_node.js:34 +# +# assert.ok(falsyNum) +# | +# 0 +# , test: spike +not ok 9 - # /path/to/examples/qunit_node.js:38 +# +# assert.ok(ary1.length === ary2.length) +# | | | | | +# | | | | 3 +# | | | ["aaa","bbb","ccc"] +# | 2 false +# ["foo","bar"] +# +# [number] ary2.length +# => 3 +# [number] ary1.length +# => 2 +# , test: spike +not ok 10 - # /path/to/examples/qunit_node.js:39 +# +# assert.deepEqual(ary1, ary2) +# | | +# | ["aaa","bbb","ccc"] +# ["foo","bar"] +# , expected: [ +# "aaa", +# "bbb", +# "ccc" +# ], got: [ +# "foo", +# "bar" +# ], test: spike +not ok 11 - # /path/to/examples/qunit_node.js:42 +# +# assert.ok(5 < actual && actual < 13) +# | | | | | +# | | | 16 false +# | 16 false +# true +# , test: spike +not ok 12 - # /path/to/examples/qunit_node.js:45 +# +# assert.ok(5 < actual && actual < 13) +# | | | +# | 4 false +# false +# , test: spike +not ok 13 - # /path/to/examples/qunit_node.js:48 +# +# assert.ok(actual < 5 || 13 < actual) +# | | | | | +# | | | | 10 +# | | false false +# 10 false +# , test: spike +not ok 14 - # /path/to/examples/qunit_node.js:58 +# +# assert.ok(foo.bar.baz) +# | | | +# | | false +# | Object{baz:false} +# Object{bar:#Object#} +# , test: spike +not ok 15 - # /path/to/examples/qunit_node.js:59 +# +# assert.ok(foo['bar'].baz) +# | | | +# | | false +# | Object{baz:false} +# Object{bar:#Object#} +# , test: spike +not ok 16 - # /path/to/examples/qunit_node.js:60 +# +# assert.ok(foo[propName]['baz']) +# | || | +# | |"bar" false +# | Object{baz:false} +# Object{bar:#Object#} +# , test: spike +not ok 17 - # /path/to/examples/qunit_node.js:64 +# +# assert.ok(!truth) +# || +# |true +# false +# , test: spike +not ok 18 - # /path/to/examples/qunit_node.js:68 +# +# assert.ok(func()) +# | +# false +# , test: spike +not ok 19 - # /path/to/examples/qunit_node.js:76 +# +# assert.ok(obj.age()) +# | | +# | 0 +# Object{age:#function#} +# , test: spike +not ok 20 - # /path/to/examples/qunit_node.js:83 +# +# assert.ok(isFalsy(positiveInt)) +# | | +# false 50 +# , test: spike +not ok 21 - # /path/to/examples/qunit_node.js:94 +# +# assert.ok(sum(one, two, three) === seven) +# | | | | | | +# | | | | | 7 +# 6 1 2 3 false +# +# [number] seven +# => 7 +# [number] sum(one, two, three) +# => 6 +# , test: spike +not ok 22 - # /path/to/examples/qunit_node.js:95 +# +# assert.ok(sum(sum(one, two), three) === sum(sum(two, three), seven)) +# | | | | | | | | | | | +# | | | | | | 12 5 2 3 7 +# 6 3 1 2 3 false +# +# [number] sum(sum(two, three), seven) +# => 12 +# [number] sum(sum(one, two), three) +# => 6 +# , test: spike +not ok 23 - # /path/to/examples/qunit_node.js:96 +# +# assert.ok(three * (seven * ten) === three) +# | | | | | | | +# | | | | | | 3 +# | | | | 10 false +# | | 7 70 +# 3 210 +# +# [number] three +# => 3 +# [number] three * (seven * ten) +# => 210 +# , test: spike +not ok 24 - # /path/to/examples/qunit_node.js:110 +# +# assert.ok(math.calc.sum(one, two, three) === seven) +# | | | | | | | | +# | | | | | | | 7 +# | | 6 1 2 3 false +# | Object{sum:#function#} +# Object{calc:#Object#} +# +# [number] seven +# => 7 +# [number] math.calc.sum(one, two, three) +# => 6 +# , test: spike +1..24 +``` + +Have fun! + + +[npm-url]: https://npmjs.org/package/power-assert +[npm-image]: https://badge.fury.io/js/power-assert.svg + +[bower-url]: http://badge.fury.io/bo/power-assert +[bower-image]: https://badge.fury.io/bo/power-assert.svg + +[travis-url]: http://travis-ci.org/twada/power-assert +[travis-image]: https://secure.travis-ci.org/twada/power-assert.svg?branch=master + +[depstat-url]: https://gemnasium.com/twada/power-assert +[depstat-image]: https://gemnasium.com/twada/power-assert.svg + +[license-url]: https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt +[license-image]: http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat diff --git a/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json b/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json new file mode 100644 index 00000000..5cf8cdf8 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json @@ -0,0 +1,46 @@ +{ + "name": "power-assert", + "description": "Power Assert in JavaScript", + "main": "build/power-assert.js", + "license": "MIT", + "ignore": [ + "**/.*", + "package.json", + "index.js", + "test", + "enable_power_assert.js" + ], + "keywords": [ + "power-assert", + "test", + "assert", + "testing", + "ecmascript", + "ast" + ], + "authors": [ + { + "name": "Takuto Wada", + "email": "takuto.wada@gmail.com", + "homepage": "https://github.com/twada" + }, + { + "name": "azu", + "url": "https://github.com/azu" + }, + { + "name": "vvakame", + "url": "https://github.com/vvakame" + } + ], + "homepage": "https://github.com/twada/power-assert", + "repository": { + "type": "git", + "url": "git://github.com/twada/power-assert.git" + }, + "devDependencies": { + "expect": "~0.3.1", + "mocha": "~2.1.0", + "requirejs": "~2.1.15" + } +} diff --git a/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js b/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js new file mode 100644 index 00000000..113289bb --- /dev/null +++ b/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js @@ -0,0 +1,11647 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.assert=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o +// +// 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 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 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. + +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = _dereq_('util/'); + +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert["throws"] = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":6}],2:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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 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. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],3:[function(_dereq_,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],4:[function(_dereq_,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; + +function drainQueue() { + if (draining) { + return; + } + draining = true; + var currentQueue; + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + var i = -1; + while (++i < len) { + currentQueue[i](); + } + len = queue.length; + } + draining = false; +} +process.nextTick = function (fun) { + queue.push(fun); + if (!draining) { + setTimeout(drainQueue, 0); + } +}; + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],5:[function(_dereq_,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],6:[function(_dereq_,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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 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. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = _dereq_('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = _dereq_('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":5,"_process":4,"inherits":3}],7:[function(_dereq_,module,exports){ +/** + * power-assert.js - Power Assert in JavaScript. + * + * https://github.com/twada/power-assert + * + * Copyright (c) 2013-2015 Takuto Wada + * Licensed under the MIT license. + * https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt + */ +'use strict'; + +var baseAssert = _dereq_('assert'), + empower = _dereq_('empower'), + formatter = _dereq_('power-assert-formatter'), + extend = _dereq_('xtend'), + empowerOptions = {modifyMessageOnRethrow: true, saveContextOnRethrow: true}; + +function customize (customOptions) { + var options = customOptions || {}; + var poweredAssert = empower( + baseAssert, + formatter(options.output), + extend(empowerOptions, options.assertion) + ); + poweredAssert.customize = customize; + return poweredAssert; +} + +module.exports = customize(); + +},{"assert":1,"empower":8,"power-assert-formatter":22,"xtend":45}],8:[function(_dereq_,module,exports){ +/** + * empower - Power Assert feature enhancer for assert function/object. + * + * https://github.com/twada/empower + * + * Copyright (c) 2013-2014 Takuto Wada + * Licensed under the MIT license. + * https://github.com/twada/empower/blob/master/MIT-LICENSE.txt + */ +var defaultOptions = _dereq_('./lib/default-options'), + Decorator = _dereq_('./lib/decorator'), + slice = Array.prototype.slice, + extend = _dereq_('xtend/mutable'); + +/** + * Enhance Power Assert feature to assert function/object. + * @param assert target assert function or object to enhance + * @param formatter power assert format function + * @param options enhancement options + * @return enhanced assert function/object + */ +function empower (assert, formatter, options) { + var typeOfAssert = (typeof assert), + config; + if ((typeOfAssert !== 'object' && typeOfAssert !== 'function') || assert === null) { + throw new TypeError('empower argument should be a function or object.'); + } + if (isEmpowered(assert)) { + return assert; + } + config = extend(defaultOptions(), options); + switch (typeOfAssert) { + case 'function': + return empowerAssertFunction(assert, formatter, config); + case 'object': + return empowerAssertObject(assert, formatter, config); + default: + throw new Error('Cannot be here'); + } +} + +function empowerAssertObject (assertObject, formatter, config) { + var target = config.destructive ? assertObject : Object.create(assertObject); + var decorator = new Decorator(target, formatter, config); + return extend(target, decorator.enhancement()); +} + +function empowerAssertFunction (assertFunction, formatter, config) { + if (config.destructive) { + throw new Error('cannot use destructive:true to function.'); + } + var decorator = new Decorator(assertFunction, formatter, config); + var enhancement = decorator.enhancement(); + var powerAssert; + if (typeof enhancement === 'function') { + powerAssert = function powerAssert () { + return enhancement.apply(null, slice.apply(arguments)); + }; + } else { + powerAssert = function powerAssert () { + return assertFunction.apply(null, slice.apply(arguments)); + }; + } + extend(powerAssert, assertFunction); + return extend(powerAssert, enhancement); +} + +function isEmpowered (assertObjectOrFunction) { + return (typeof assertObjectOrFunction._capt === 'function') && (typeof assertObjectOrFunction._expr === 'function'); +} + +empower.defaultOptions = defaultOptions; +module.exports = empower; + +},{"./lib/decorator":11,"./lib/default-options":12,"xtend/mutable":46}],9:[function(_dereq_,module,exports){ +'use strict'; + +module.exports = function capturable () { + var events = []; + + function _capt (value, espath) { + events.push({value: value, espath: espath}); + return value; + } + + function _expr (value, args) { + var captured = events; + events = []; + return { + powerAssertContext: { + value: value, + events: captured + }, + source: { + content: args.content, + filepath: args.filepath, + line: args.line + } + }; + } + + return { + _capt: _capt, + _expr: _expr + }; +}; + +},{}],10:[function(_dereq_,module,exports){ +'use strict'; + +var slice = Array.prototype.slice; + +function decorate (callSpec, decorator) { + var func = callSpec.func, + thisObj = callSpec.thisObj, + numArgsToCapture = callSpec.numArgsToCapture; + + return function decoratedAssert () { + var context, message, args = slice.apply(arguments); + + if (args.every(isNotCaptured)) { + return func.apply(thisObj, args); + } + + var values = args.slice(0, numArgsToCapture).map(function (arg) { + if (isNotCaptured(arg)) { + return arg; + } + if (!context) { + context = { + source: arg.source, + args: [] + }; + } + context.args.push({ + value: arg.powerAssertContext.value, + events: arg.powerAssertContext.events + }); + return arg.powerAssertContext.value; + }); + + if (numArgsToCapture === (args.length - 1)) { + message = args[args.length - 1]; + } + + var invocation = { + thisObj: thisObj, + func: func, + values: values, + message: message + }; + return decorator.concreteAssert(invocation, context); + }; +} + +function isNotCaptured (value) { + return !isCaptured(value); +} + +function isCaptured (value) { + return (typeof value === 'object') && + (value !== null) && + (typeof value.powerAssertContext !== 'undefined'); +} + +module.exports = decorate; + +},{}],11:[function(_dereq_,module,exports){ +'use strict'; + +var escallmatch = _dereq_('escallmatch'), + extend = _dereq_('xtend/mutable'), + capturable = _dereq_('./capturable'), + decorate = _dereq_('./decorate'); + + +function Decorator (receiver, formatter, config) { + this.receiver = receiver; + this.formatter = formatter; + this.config = config; + this.matchers = config.patterns.map(escallmatch); + this.eagerEvaluation = !(config.modifyMessageOnRethrow || config.saveContextOnRethrow); +} + +Decorator.prototype.enhancement = function () { + var that = this; + var container = this.container(); + this.matchers.filter(methodCall).forEach(function (matcher) { + var methodName = detectMethodName(matcher.calleeAst()); + if (typeof that.receiver[methodName] === 'function') { + var callSpec = { + thisObj: that.receiver, + func: that.receiver[methodName], + numArgsToCapture: numberOfArgumentsToCapture(matcher) + }; + container[methodName] = decorate(callSpec, that); + } + }); + extend(container, capturable()); + return container; +}; + +Decorator.prototype.container = function () { + var basement = {}; + if (typeof this.receiver === 'function') { + var candidates = this.matchers.filter(functionCall); + if (candidates.length === 1) { + var callSpec = { + thisObj: null, + func: this.receiver, + numArgsToCapture: numberOfArgumentsToCapture(candidates[0]) + }; + basement = decorate(callSpec, this); + } + } + return basement; +}; + +Decorator.prototype.concreteAssert = function (invocation, context) { + var func = invocation.func, + thisObj = invocation.thisObj, + args = invocation.values, + message = invocation.message; + if (this.eagerEvaluation) { + var poweredMessage = this.buildPowerAssertText(message, context); + return func.apply(thisObj, args.concat(poweredMessage)); + } + try { + return func.apply(thisObj, args.concat(message)); + } catch (e) { + throw this.errorToRethrow(e, message, context); + } +}; + +Decorator.prototype.errorToRethrow = function (e, originalMessage, context) { + if (e.name !== 'AssertionError') { + return e; + } + if (typeof this.receiver.AssertionError !== 'function') { + return e; + } + var f = new this.receiver.AssertionError({ + actual: e.actual, + expected: e.expected, + operator: e.operator, + message: this.config.modifyMessageOnRethrow ? this.buildPowerAssertText(originalMessage, context) : e.message, + stackStartFunction: Decorator.prototype.concreteAssert + }); + if (this.config.saveContextOnRethrow) { + f.powerAssertContext = context; + } + return f; +}; + +Decorator.prototype.buildPowerAssertText = function (message, context) { + var powerAssertText = this.formatter(context); + return message ? message + ' ' + powerAssertText : powerAssertText; +}; + + +function numberOfArgumentsToCapture (matcher) { + var argSpecs = matcher.argumentSignatures(), + len = argSpecs.length, + lastArg; + if (0 < len) { + lastArg = argSpecs[len - 1]; + if (lastArg.name === 'message' && lastArg.kind === 'optional') { + len -= 1; + } + } + return len; +} + + +function detectMethodName (node) { + if (node.type === 'MemberExpression') { + return node.property.name; + } + return null; +} + + +function functionCall (matcher) { + return matcher.calleeAst().type === 'Identifier'; +} + + +function methodCall (matcher) { + return matcher.calleeAst().type === 'MemberExpression'; +} + + +module.exports = Decorator; + +},{"./capturable":9,"./decorate":10,"escallmatch":13,"xtend/mutable":46}],12:[function(_dereq_,module,exports){ +'use strict'; + +module.exports = function defaultOptions () { + return { + destructive: false, + modifyMessageOnRethrow: false, + saveContextOnRethrow: false, + patterns: [ + 'assert(value, [message])', + 'assert.ok(value, [message])', + 'assert.equal(actual, expected, [message])', + 'assert.notEqual(actual, expected, [message])', + 'assert.strictEqual(actual, expected, [message])', + 'assert.notStrictEqual(actual, expected, [message])', + 'assert.deepEqual(actual, expected, [message])', + 'assert.notDeepEqual(actual, expected, [message])' + ] + }; +}; + +},{}],13:[function(_dereq_,module,exports){ +/** + * escallmatch: + * ECMAScript CallExpression matcher made from function/method signature + * + * https://github.com/twada/escallmatch + * + * Copyright (c) 2014 Takuto Wada + * Licensed under the MIT license. + * http://twada.mit-license.org/ + */ +'use strict'; +/* jshint -W024 */ + +var esprima = _dereq_('esprima'), + estraverse = _dereq_('estraverse'), + espurify = _dereq_('espurify'), + syntax = estraverse.Syntax, + hasOwn = Object.prototype.hasOwnProperty, + deepEqual = _dereq_('deep-equal'), + notCallExprMessage = 'Argument should be in the form of CallExpression', + duplicatedArgMessage = 'Duplicate argument name: ', + invalidFormMessage = 'Argument should be in the form of `name` or `[name]`'; + +function createMatcher (signatureStr) { + var ast = extractExpressionFrom(esprima.parse(signatureStr)); + return new Matcher(ast); +} + +function Matcher (signatureAst) { + this.signatureAst = signatureAst; + this.signatureCalleeDepth = astDepth(signatureAst.callee); + this.numMaxArgs = this.signatureAst.arguments.length; + this.numMinArgs = this.signatureAst.arguments.filter(identifiers).length; +} + +Matcher.prototype.test = function (currentNode) { + var calleeMatched = isCalleeMatched(this.signatureAst, this.signatureCalleeDepth, currentNode), + numArgs; + if (calleeMatched) { + numArgs = currentNode.arguments.length; + return this.numMinArgs <= numArgs && numArgs <= this.numMaxArgs; + } + return false; +}; + +Matcher.prototype.matchArgument = function (currentNode, parentNode) { + if (isCalleeOfParent(currentNode, parentNode)) { + return null; + } + if (this.test(parentNode)) { + var indexOfCurrentArg = parentNode.arguments.indexOf(currentNode); + var numOptional = parentNode.arguments.length - this.numMinArgs; + var matchedSignatures = this.argumentSignatures().reduce(function (accum, argSig) { + if (argSig.kind === 'mandatory') { + accum.push(argSig); + } + if (argSig.kind === 'optional' && 0 < numOptional) { + numOptional -= 1; + accum.push(argSig); + } + return accum; + }, []); + return matchedSignatures[indexOfCurrentArg]; + } + return null; +}; + +Matcher.prototype.calleeAst = function () { + return espurify(this.signatureAst.callee); +}; + +Matcher.prototype.argumentSignatures = function () { + return this.signatureAst.arguments.map(toArgumentSignature); +}; + +function toArgumentSignature (argSignatureNode) { + switch(argSignatureNode.type) { + case syntax.Identifier: + return { + name: argSignatureNode.name, + kind: 'mandatory' + }; + case syntax.ArrayExpression: + return { + name: argSignatureNode.elements[0].name, + kind: 'optional' + }; + default: + return null; + } +} + +function isCalleeMatched(callSignature, signatureCalleeDepth, node) { + if (!isCallExpression(node)) { + return false; + } + if (!isSameAstDepth(node.callee, signatureCalleeDepth)) { + return false; + } + return deepEqual(espurify(callSignature.callee), espurify(node.callee)); +} + +function isSameAstDepth (ast, depth) { + var currentDepth = 0; + estraverse.traverse(ast, { + enter: function (currentNode, parentNode) { + var path = this.path(), + pathDepth = path ? path.length : 0; + if (currentDepth < pathDepth) { + currentDepth = pathDepth; + } + if (depth < currentDepth) { + this['break'](); + } + } + }); + return (depth === currentDepth); +} + +function astDepth (ast) { + var maxDepth = 0; + estraverse.traverse(ast, { + enter: function (currentNode, parentNode) { + var path = this.path(), + pathDepth = path ? path.length : 0; + if (maxDepth < pathDepth) { + maxDepth = pathDepth; + } + } + }); + return maxDepth; +} + +function isCallExpression (node) { + return node && node.type === syntax.CallExpression; +} + +function isCalleeOfParent(currentNode, parentNode) { + return parentNode && currentNode && + parentNode.type === syntax.CallExpression && + parentNode.callee === currentNode; +} + +function identifiers (node) { + return node.type === syntax.Identifier; +} + +function validateApiExpression (callExpression) { + if (callExpression.type !== syntax.CallExpression) { + throw new Error(notCallExprMessage); + } + var names = {}; + callExpression.arguments.forEach(function (arg) { + var name = validateArg(arg); + if (hasOwn.call(names, name)) { + throw new Error(duplicatedArgMessage + name); + } else { + names[name] = name; + } + }); +} + +function validateArg (arg) { + var inner; + switch(arg.type) { + case syntax.Identifier: + return arg.name; + case syntax.ArrayExpression: + if (arg.elements.length !== 1) { + throw new Error(invalidFormMessage); + } + inner = arg.elements[0]; + if (inner.type !== syntax.Identifier) { + throw new Error(invalidFormMessage); + } + return inner.name; + default: + throw new Error(invalidFormMessage); + } +} + +function extractExpressionFrom (tree) { + var statement, expression; + statement = tree.body[0]; + if (statement.type !== syntax.ExpressionStatement) { + throw new Error(notCallExprMessage); + } + expression = statement.expression; + validateApiExpression(expression); + return expression; +} + +module.exports = createMatcher; + +},{"deep-equal":14,"esprima":21,"espurify":17,"estraverse":20}],14:[function(_dereq_,module,exports){ +var pSlice = Array.prototype.slice; +var objectKeys = _dereq_('./lib/keys.js'); +var isArguments = _dereq_('./lib/is_arguments.js'); + +var deepEqual = module.exports = function (actual, expected, opts) { + if (!opts) opts = {}; + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return opts.strict ? actual === expected : actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected, opts); + } +} + +function isUndefinedOrNull(value) { + return value === null || value === undefined; +} + +function isBuffer (x) { + if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false; + if (typeof x.copy !== 'function' || typeof x.slice !== 'function') { + return false; + } + if (x.length > 0 && typeof x[0] !== 'number') return false; + return true; +} + +function objEquiv(a, b, opts) { + var i, key; + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return deepEqual(a, b, opts); + } + if (isBuffer(a)) { + if (!isBuffer(b)) { + return false; + } + if (a.length !== b.length) return false; + for (i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false; + } + return true; + } + try { + var ka = objectKeys(a), + kb = objectKeys(b); + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], opts)) return false; + } + return typeof a === typeof b; +} + +},{"./lib/is_arguments.js":15,"./lib/keys.js":16}],15:[function(_dereq_,module,exports){ +var supportsArgumentsClass = (function(){ + return Object.prototype.toString.call(arguments) +})() == '[object Arguments]'; + +exports = module.exports = supportsArgumentsClass ? supported : unsupported; + +exports.supported = supported; +function supported(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +}; + +exports.unsupported = unsupported; +function unsupported(object){ + return object && + typeof object == 'object' && + typeof object.length == 'number' && + Object.prototype.hasOwnProperty.call(object, 'callee') && + !Object.prototype.propertyIsEnumerable.call(object, 'callee') || + false; +}; + +},{}],16:[function(_dereq_,module,exports){ +exports = module.exports = typeof Object.keys === 'function' + ? Object.keys : shim; + +exports.shim = shim; +function shim (obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; +} + +},{}],17:[function(_dereq_,module,exports){ +/** + * espurify - Clone new AST without extra properties + * + * https://github.com/twada/espurify + * + * Copyright (c) 2014 Takuto Wada + * Licensed under the MIT license. + * http://twada.mit-license.org/ + */ +'use strict'; + +var traverse = _dereq_('traverse'), + deepCopy = _dereq_('./lib/ast-deepcopy'), + astProps = _dereq_('./lib/ast-properties'), + hasOwn = Object.prototype.hasOwnProperty; + +function espurify (node) { + var result = deepCopy(node); + traverse(result).forEach(function (x) { + if (this.parent && + this.parent.node && + this.parent.node.type && + isSupportedNodeType(this.parent.node.type) && + !isSupportedKey(this.parent.node.type, this.key)) + { + this.remove(true); + } + }); + return result; +} + +function isSupportedNodeType (type) { + return hasOwn.call(astProps, type); +} + +function isSupportedKey (type, key) { + return astProps[type].indexOf(key) !== -1; +} + +module.exports = espurify; + +},{"./lib/ast-deepcopy":18,"./lib/ast-properties":19,"traverse":44}],18:[function(_dereq_,module,exports){ +/** + * Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors. + * Released under the BSD license. + * https://github.com/Constellation/esmangle/blob/master/LICENSE.BSD + */ +'use strict'; + +var isArray = Array.isArray || function isArray (array) { + return Object.prototype.toString.call(array) === '[object Array]'; +}; + +function deepCopyInternal (obj, result) { + var key, val; + for (key in obj) { + if (key.lastIndexOf('__', 0) === 0) { + continue; + } + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + if (val instanceof RegExp) { + val = new RegExp(val); + } else { + val = deepCopyInternal(val, isArray(val) ? [] : {}); + } + } + result[key] = val; + } + } + return result; +} + +function deepCopy (obj) { + return deepCopyInternal(obj, isArray(obj) ? [] : {}); +} + +module.exports = deepCopy; + +},{}],19:[function(_dereq_,module,exports){ +module.exports = { + AssignmentExpression: ['type', 'operator', 'left', 'right'], + ArrayExpression: ['type', 'elements'], + ArrayPattern: ['type', 'elements'], + // ArrowFunctionExpression: ['type', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], + BlockStatement: ['type', 'body'], + BinaryExpression: ['type', 'operator', 'left', 'right'], + BreakStatement: ['type', 'label'], + CallExpression: ['type', 'callee', 'arguments'], + CatchClause: ['type', 'param', 'guard', 'body'], + // ClassBody: ['type', 'body'], + // ClassDeclaration: ['type', 'id', 'body', 'superClass'], + // ClassExpression: ['type', 'id', 'body', 'superClass'], + ConditionalExpression: ['type', 'test', 'consequent', 'alternate'], + ContinueStatement: ['type', 'label'], + DebuggerStatement: ['type'], + // DirectiveStatement: ['type'], + DoWhileStatement: ['type', 'body', 'test'], + EmptyStatement: ['type'], + ExpressionStatement: ['type', 'expression'], + ForStatement: ['type', 'init', 'test', 'update', 'body'], + ForInStatement: ['type', 'left', 'right', 'body', 'each'], + FunctionDeclaration: ['type', 'id', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], + FunctionExpression: ['type', 'id', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], + Identifier: ['type', 'name'], + IfStatement: ['type', 'test', 'consequent', 'alternate'], + Literal: ['type', 'value'], + LabeledStatement: ['type', 'label', 'body'], + LogicalExpression: ['type', 'operator', 'left', 'right'], + MemberExpression: ['type', 'object', 'property', 'computed'], + // MethodDefinition: ['type', 'key', 'value'], + NewExpression: ['type', 'callee', 'arguments'], + ObjectExpression: ['type', 'properties'], + ObjectPattern: ['type', 'properties'], + Program: ['type', 'body'], + Property: ['type', 'key', 'value', 'kind'], + ReturnStatement: ['type', 'argument'], + SequenceExpression: ['type', 'expressions'], + SwitchStatement: ['type', 'discriminant', 'cases', 'lexical'], + SwitchCase: ['type', 'test', 'consequent'], + ThisExpression: ['type'], + ThrowStatement: ['type', 'argument'], + TryStatement: ['type', 'block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], + UnaryExpression: ['type', 'operator', 'prefix', 'argument'], + UpdateExpression: ['type', 'operator', 'argument', 'prefix'], + VariableDeclaration: ['type', 'declarations', 'kind'], + VariableDeclarator: ['type', 'id', 'init'], + WhileStatement: ['type', 'test', 'body'], + WithStatement: ['type', 'object', 'body'], + YieldExpression: ['type', 'argument'] +}; + +},{}],20:[function(_dereq_,module,exports){ +/* + Copyright (C) 2012-2013 Yusuke Suzuki + Copyright (C) 2012 Ariya Hidayat + + 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 HOLDERS AND CONTRIBUTORS "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 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. +*/ +/*jslint vars:false, bitwise:true*/ +/*jshint indent:4*/ +/*global exports:true, define:true*/ +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // and plain browser loading, + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.estraverse = {})); + } +}(this, function (exports) { + 'use strict'; + + var Syntax, + isArray, + VisitorOption, + VisitorKeys, + objectCreate, + objectKeys, + BREAK, + SKIP, + REMOVE; + + function ignoreJSHintError() { } + + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + + function deepCopy(obj) { + var ret = {}, key, val; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + ret[key] = deepCopy(val); + } else { + ret[key] = val; + } + } + } + return ret; + } + + function shallowCopy(obj) { + var ret = {}, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = obj[key]; + } + } + return ret; + } + ignoreJSHintError(shallowCopy); + + // based on LLVM libc++ upper_bound / lower_bound + // MIT License + + function upperBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + len = diff; + } else { + i = current + 1; + len -= diff + 1; + } + } + return i; + } + + function lowerBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + i = current + 1; + len -= diff + 1; + } else { + len = diff; + } + } + return i; + } + ignoreJSHintError(lowerBound); + + objectCreate = Object.create || (function () { + function F() { } + + return function (o) { + F.prototype = o; + return new F(); + }; + })(); + + objectKeys = Object.keys || function (o) { + var keys = [], key; + for (key in o) { + keys.push(key); + } + return keys; + }; + + function extend(to, from) { + objectKeys(from).forEach(function (key) { + to[key] = from[key]; + }); + return to; + } + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. + ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportBatchSpecifier: 'ExportBatchSpecifier', + ExportDeclaration: 'ExportDeclaration', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', + ImportSpecifier: 'ImportSpecifier', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleSpecifier: 'ModuleSpecifier', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + VisitorKeys = { + AssignmentExpression: ['left', 'right'], + ArrayExpression: ['elements'], + ArrayPattern: ['elements'], + ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'], + BlockStatement: ['body'], + BinaryExpression: ['left', 'right'], + BreakStatement: ['label'], + CallExpression: ['callee', 'arguments'], + CatchClause: ['param', 'body'], + ClassBody: ['body'], + ClassDeclaration: ['id', 'body', 'superClass'], + ClassExpression: ['id', 'body', 'superClass'], + ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. + ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + ConditionalExpression: ['test', 'consequent', 'alternate'], + ContinueStatement: ['label'], + DebuggerStatement: [], + DirectiveStatement: [], + DoWhileStatement: ['body', 'test'], + EmptyStatement: [], + ExportBatchSpecifier: [], + ExportDeclaration: ['declaration', 'specifiers', 'source'], + ExportSpecifier: ['id', 'name'], + ExpressionStatement: ['expression'], + ForStatement: ['init', 'test', 'update', 'body'], + ForInStatement: ['left', 'right', 'body'], + ForOfStatement: ['left', 'right', 'body'], + FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'], + FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], + GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + Identifier: [], + IfStatement: ['test', 'consequent', 'alternate'], + ImportDeclaration: ['specifiers', 'source'], + ImportDefaultSpecifier: ['id'], + ImportNamespaceSpecifier: ['id'], + ImportSpecifier: ['id', 'name'], + Literal: [], + LabeledStatement: ['label', 'body'], + LogicalExpression: ['left', 'right'], + MemberExpression: ['object', 'property'], + MethodDefinition: ['key', 'value'], + ModuleSpecifier: [], + NewExpression: ['callee', 'arguments'], + ObjectExpression: ['properties'], + ObjectPattern: ['properties'], + Program: ['body'], + Property: ['key', 'value'], + ReturnStatement: ['argument'], + SequenceExpression: ['expressions'], + SpreadElement: ['argument'], + SwitchStatement: ['discriminant', 'cases'], + SwitchCase: ['test', 'consequent'], + TaggedTemplateExpression: ['tag', 'quasi'], + TemplateElement: [], + TemplateLiteral: ['quasis', 'expressions'], + ThisExpression: [], + ThrowStatement: ['argument'], + TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], + UnaryExpression: ['argument'], + UpdateExpression: ['argument'], + VariableDeclaration: ['declarations'], + VariableDeclarator: ['id', 'init'], + WhileStatement: ['test', 'body'], + WithStatement: ['object', 'body'], + YieldExpression: ['argument'] + }; + + // unique id + BREAK = {}; + SKIP = {}; + REMOVE = {}; + + VisitorOption = { + Break: BREAK, + Skip: SKIP, + Remove: REMOVE + }; + + function Reference(parent, key) { + this.parent = parent; + this.key = key; + } + + Reference.prototype.replace = function replace(node) { + this.parent[this.key] = node; + }; + + Reference.prototype.remove = function remove() { + if (isArray(this.parent)) { + this.parent.splice(this.key, 1); + return true; + } else { + this.replace(null); + return false; + } + }; + + function Element(node, path, wrap, ref) { + this.node = node; + this.path = path; + this.wrap = wrap; + this.ref = ref; + } + + function Controller() { } + + // API: + // return property path array from root to current node + Controller.prototype.path = function path() { + var i, iz, j, jz, result, element; + + function addToPath(result, path) { + if (isArray(path)) { + for (j = 0, jz = path.length; j < jz; ++j) { + result.push(path[j]); + } + } else { + result.push(path); + } + } + + // root node + if (!this.__current.path) { + return null; + } + + // first node is sentinel, second node is root element + result = []; + for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { + element = this.__leavelist[i]; + addToPath(result, element.path); + } + addToPath(result, this.__current.path); + return result; + }; + + // API: + // return type of current node + Controller.prototype.type = function () { + var node = this.current(); + return node.type || this.__current.wrap; + }; + + // API: + // return array of parent elements + Controller.prototype.parents = function parents() { + var i, iz, result; + + // first node is sentinel + result = []; + for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { + result.push(this.__leavelist[i].node); + } + + return result; + }; + + // API: + // return current node + Controller.prototype.current = function current() { + return this.__current.node; + }; + + Controller.prototype.__execute = function __execute(callback, element) { + var previous, result; + + result = undefined; + + previous = this.__current; + this.__current = element; + this.__state = null; + if (callback) { + result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); + } + this.__current = previous; + + return result; + }; + + // API: + // notify control skip / break + Controller.prototype.notify = function notify(flag) { + this.__state = flag; + }; + + // API: + // skip child nodes of current node + Controller.prototype.skip = function () { + this.notify(SKIP); + }; + + // API: + // break traversals + Controller.prototype['break'] = function () { + this.notify(BREAK); + }; + + // API: + // remove node + Controller.prototype.remove = function () { + this.notify(REMOVE); + }; + + Controller.prototype.__initialize = function(root, visitor) { + this.visitor = visitor; + this.root = root; + this.__worklist = []; + this.__leavelist = []; + this.__current = null; + this.__state = null; + this.__fallback = visitor.fallback === 'iteration'; + this.__keys = VisitorKeys; + if (visitor.keys) { + this.__keys = extend(objectCreate(this.__keys), visitor.keys); + } + }; + + function isNode(node) { + if (node == null) { + return false; + } + return typeof node === 'object' && typeof node.type === 'string'; + } + + function isProperty(nodeType, key) { + return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; + } + + Controller.prototype.traverse = function traverse(root, visitor) { + var worklist, + leavelist, + element, + node, + nodeType, + ret, + key, + current, + current2, + candidates, + candidate, + sentinel; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + worklist.push(new Element(root, null, null, null)); + leavelist.push(new Element(null, null, null, null)); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + ret = this.__execute(visitor.leave, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + continue; + } + + if (element.node) { + + ret = this.__execute(visitor.enter, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || ret === SKIP) { + continue; + } + + node = element.node; + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', null); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, null); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, null)); + } + } + } + } + }; + + Controller.prototype.replace = function replace(root, visitor) { + function removeElem(element) { + var i, + key, + nextElem, + parent; + + if (element.ref.remove()) { + // When the reference is an element of an array. + key = element.ref.key; + parent = element.ref.parent; + + // If removed from array, then decrease following items' keys. + i = worklist.length; + while (i--) { + nextElem = worklist[i]; + if (nextElem.ref && nextElem.ref.parent === parent) { + if (nextElem.ref.key < key) { + break; + } + --nextElem.ref.key; + } + } + } + } + + var worklist, + leavelist, + node, + nodeType, + target, + element, + current, + current2, + candidates, + candidate, + sentinel, + outer, + key; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + outer = { + root: root + }; + element = new Element(root, null, null, new Reference(outer, 'root')); + worklist.push(element); + leavelist.push(element); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + target = this.__execute(visitor.leave, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + continue; + } + + target = this.__execute(visitor.enter, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + element.node = target; + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + element.node = null; + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + + // node may be null + node = element.node; + if (!node) { + continue; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || target === SKIP) { + continue; + } + + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, new Reference(node, key))); + } + } + } + + return outer.root; + }; + + function traverse(root, visitor) { + var controller = new Controller(); + return controller.traverse(root, visitor); + } + + function replace(root, visitor) { + var controller = new Controller(); + return controller.replace(root, visitor); + } + + function extendCommentRange(comment, tokens) { + var target; + + target = upperBound(tokens, function search(token) { + return token.range[0] > comment.range[0]; + }); + + comment.extendedRange = [comment.range[0], comment.range[1]]; + + if (target !== tokens.length) { + comment.extendedRange[1] = tokens[target].range[0]; + } + + target -= 1; + if (target >= 0) { + comment.extendedRange[0] = tokens[target].range[1]; + } + + return comment; + } + + function attachComments(tree, providedComments, tokens) { + // At first, we should calculate extended comment ranges. + var comments = [], comment, len, i, cursor; + + if (!tree.range) { + throw new Error('attachComments needs range information'); + } + + // tokens array is empty, we attach comments to tree as 'leadingComments' + if (!tokens.length) { + if (providedComments.length) { + for (i = 0, len = providedComments.length; i < len; i += 1) { + comment = deepCopy(providedComments[i]); + comment.extendedRange = [0, tree.range[0]]; + comments.push(comment); + } + tree.leadingComments = comments; + } + return tree; + } + + for (i = 0, len = providedComments.length; i < len; i += 1) { + comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); + } + + // This is based on John Freeman's implementation. + cursor = 0; + traverse(tree, { + enter: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (comment.extendedRange[1] > node.range[0]) { + break; + } + + if (comment.extendedRange[1] === node.range[0]) { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + cursor = 0; + traverse(tree, { + leave: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (node.range[1] < comment.extendedRange[0]) { + break; + } + + if (node.range[1] === comment.extendedRange[0]) { + if (!node.trailingComments) { + node.trailingComments = []; + } + node.trailingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + return tree; + } + + exports.version = '1.8.0'; + exports.Syntax = Syntax; + exports.traverse = traverse; + exports.replace = replace; + exports.attachComments = attachComments; + exports.VisitorKeys = VisitorKeys; + exports.VisitorOption = VisitorOption; + exports.Controller = Controller; +})); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{}],21:[function(_dereq_,module,exports){ +/* + Copyright (C) 2013 Ariya Hidayat + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2013 Mathias Bynens + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + 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 HOLDERS AND CONTRIBUTORS "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 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. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwErrorTolerant: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, parseExpression: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseLeftHandSideExpression: true, +parseUnaryExpression: true, +parseStatement: true, parseSourceElement: true */ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + + /* istanbul ignore next */ + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PropertyKind, + Messages, + Regex, + SyntaxTreeDelegate, + source, + strict, + index, + lineNumber, + lineStart, + length, + delegate, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', + // assignment operators + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', + // binary/unary operators + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalReturn: 'Illegal return statement', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\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]'), + NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\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\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\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\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\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-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\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-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + /* istanbul ignore if */ + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 48 && ch <= 57); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || + (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch >= 0x30 && ch <= 0x39) || // 0..9 + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function addComment(type, value, start, end, loc) { + var comment, attacher; + + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (state.lastCommentStart >= start) { + return; + } + state.lastCommentStart = start; + + comment = { + type: type, + value: value + }; + if (extra.range) { + comment.range = [start, end]; + } + if (extra.loc) { + comment.loc = loc; + } + extra.comments.push(comment); + if (extra.attachComment) { + extra.leadingComments.push(comment); + extra.trailingComments.push(comment); + } + } + + function skipSingleLineComment(offset) { + var start, loc, ch, comment; + + start = index - offset; + loc = { + start: { + line: lineNumber, + column: index - lineStart - offset + } + }; + + while (index < length) { + ch = source.charCodeAt(index); + ++index; + if (isLineTerminator(ch)) { + if (extra.comments) { + comment = source.slice(start + offset, index - 1); + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + addComment('Line', comment, start, index - 1, loc); + } + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + return; + } + } + + if (extra.comments) { + comment = source.slice(start + offset, index); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Line', comment, start, index, loc); + } + } + + function skipMultiLineComment() { + var start, loc, ch, comment; + + if (extra.comments) { + start = index - 2; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (isLineTerminator(ch)) { + if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else if (ch === 0x2A) { + // Block comment ends with '*/'. + if (source.charCodeAt(index + 1) === 0x2F) { + ++index; + ++index; + if (extra.comments) { + comment = source.slice(start + 2, index - 2); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + } + return; + } + ++index; + } else { + ++index; + } + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + function skipComment() { + var ch, start; + + start = (index === 0); + while (index < length) { + ch = source.charCodeAt(index); + + if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { + ++index; + } + ++lineNumber; + lineStart = index; + start = true; + } else if (ch === 0x2F) { // U+002F is '/' + ch = source.charCodeAt(index + 1); + if (ch === 0x2F) { + ++index; + ++index; + skipSingleLineComment(2); + start = true; + } else if (ch === 0x2A) { // U+002A is '*' + ++index; + ++index; + skipMultiLineComment(); + } else { + break; + } + } else if (start && ch === 0x2D) { // U+002D is '-' + // U+003E is '>' + if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { + // '-->' is a single-line comment + index += 3; + skipSingleLineComment(3); + } else { + break; + } + } else if (ch === 0x3C) { // U+003C is '<' + if (source.slice(index + 1, index + 4) === '!--') { + ++index; // `<` + ++index; // `!` + ++index; // `-` + ++index; // `-` + skipSingleLineComment(4); + } else { + break; + } + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function getEscapedIdentifier() { + var ch, id; + + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id = ch; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 0x5C) { + // Blackslash (U+005C) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (U+005C) starts an escaped character. + id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + code = source.charCodeAt(index), + code2, + ch1 = source[index], + ch2, + ch3, + ch4; + + switch (code) { + + // Check for most common single-character punctuators. + case 0x2E: // . dot + case 0x28: // ( open bracket + case 0x29: // ) close bracket + case 0x3B: // ; semicolon + case 0x2C: // , comma + case 0x7B: // { open curly brace + case 0x7D: // } close curly brace + case 0x5B: // [ + case 0x5D: // ] + case 0x3A: // : + case 0x3F: // ? + case 0x7E: // ~ + ++index; + if (extra.tokenize) { + if (code === 0x28) { + extra.openParenToken = extra.tokens.length; + } else if (code === 0x7B) { + extra.openCurlyToken = extra.tokens.length; + } + } + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (U+003D) marks an assignment or comparison operator. + if (code2 === 0x3D) { + switch (code) { + case 0x2B: // + + case 0x2D: // - + case 0x2F: // / + case 0x3C: // < + case 0x3E: // > + case 0x5E: // ^ + case 0x7C: // | + case 0x25: // % + case 0x26: // & + case 0x2A: // * + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + case 0x21: // ! + case 0x3D: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 0x3D) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + } + } + + // 4-character punctuator: >>>= + + ch4 = source.substr(index, 4); + + if (ch4 === '>>>=') { + index += 4; + return { + type: Token.Punctuator, + value: ch4, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 3-character punctuators: === !== >>> <<= >>= + + ch3 = ch4.substr(0, 3); + + if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { + index += 3; + return { + type: Token.Punctuator, + value: ch3, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // Other 2-character punctuators: ++ -- << >> && || + ch2 = ch3.substr(0, 2); + + if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { + index += 2; + return { + type: Token.Punctuator, + value: ch2, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 1-character punctuators: < > = ! + - * % & | ^ / + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanOctalLiteral(start) { + var number = '0' + source[index++]; + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: true, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanNumericLiteral() { + var number, start, ch; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (isOctalDigit(ch)) { + return scanOctalLiteral(start); + } + + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDecimalDigit(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; + startLineNumber = lineNumber; + startLineStart = lineStart; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'u': + case 'x': + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + lineStart = index; + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + startLineNumber: startLineNumber, + startLineStart: startLineStart, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function testRegExp(pattern, flags) { + var value; + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + return value; + } + + function scanRegExpBody() { + var ch, str, classMarker, terminated, body; + + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + classMarker = false; + terminated = false; + while (index < length) { + ch = source[index++]; + str += ch; + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } else if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + body = str.substr(1, str.length - 2); + return { + value: body, + literal: str + }; + } + + function scanRegExpFlags() { + var ch, str, flags, restore; + + str = ''; + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + } else { + str += '\\'; + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + flags += ch; + str += ch; + } + } + + return { + value: flags, + literal: str + }; + } + + function scanRegExp() { + var start, body, flags, pattern, value; + + lookahead = null; + skipComment(); + start = index; + + body = scanRegExpBody(); + flags = scanRegExpFlags(); + value = testRegExp(body.value, flags.value); + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + return { + literal: body.literal + flags.literal, + value: value, + start: start, + end: index + }; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + /* istanbul ignore next */ + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return collectRegex(); + } + if (prevToken.type === 'Punctuator') { + if (prevToken.value === ']') { + return scanPunctuator(); + } + if (prevToken.value === ')') { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { + return collectRegex(); + } + return scanPunctuator(); + } + if (prevToken.value === '}') { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return collectRegex(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return collectRegex(); + } + return collectRegex(); + } + if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { + return collectRegex(); + } + return scanPunctuator(); + } + + function advance() { + var ch; + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + start: index, + end: index + }; + } + + ch = source.charCodeAt(index); + + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + + // Very common: ( and ) and ; + if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { + return scanPunctuator(); + } + + // String literal starts with single quote (U+0027) or double quote (U+0022). + if (ch === 0x27 || ch === 0x22) { + return scanStringLiteral(); + } + + + // Dot (.) U+002E can also start a floating-point number, hence the need + // to check the next character. + if (ch === 0x2E) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + // Slash (/) U+002F can also start a regex. + if (extra.tokenize && ch === 0x2F) { + return advanceSlash(); + } + + return scanPunctuator(); + } + + function collectToken() { + var loc, token, range, value; + + skipComment(); + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + value = source.slice(token.start, token.end); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: [token.start, token.end], + loc: loc + }); + } + + return token; + } + + function lex() { + var token; + + token = lookahead; + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + function Position(line, column) { + this.line = line; + this.column = column; + } + + function SourceLocation(startLine, startColumn, line, column) { + this.start = new Position(startLine, startColumn); + this.end = new Position(line, column); + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + processComment: function (node) { + var lastChild, trailingComments; + + if (node.type === Syntax.Program) { + if (node.body.length > 0) { + return; + } + } + + if (extra.trailingComments.length > 0) { + if (extra.trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.trailingComments; + extra.trailingComments = []; + } else { + extra.trailingComments.length = 0; + } + } else { + if (extra.bottomRightStack.length > 0 && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + } + } + + // Eating the stack. + while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { + lastChild = extra.bottomRightStack.pop(); + } + + if (lastChild) { + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments; + delete lastChild.leadingComments; + } + } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = extra.leadingComments; + extra.leadingComments = []; + } + + + if (trailingComments) { + node.trailingComments = trailingComments; + } + + extra.bottomRightStack.push(node); + }, + + markEnd: function (node, startToken) { + if (extra.range) { + node.range = [startToken.start, index]; + } + if (extra.loc) { + node.loc = new SourceLocation( + startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, + startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), + lineNumber, + index - lineStart + ); + this.postProcess(node); + } + + if (extra.attachComment) { + this.processComment(node); + } + return node; + }, + + postProcess: function (node) { + if (extra.source) { + node.loc.source = extra.source; + } + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createFunctionExpression: function (id, params, defaults, body) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.start, token.end) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument, + prefix: true + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + } + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + assert(index < args.length, 'Message reference must be in range'); + return args[index]; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.start; + error.lineNumber = token.lineNumber; + error.column = token.start - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + error.description = msg; + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line, oldIndex = index, oldLineNumber = lineNumber, + oldLineStart = lineStart, oldLookahead = lookahead; + + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B || match(';')) { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + index = oldIndex; + lineNumber = oldLineNumber; + lineStart = oldLineStart; + lookahead = oldLookahead; + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = [], startToken; + + startToken = lookahead; + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else { + elements.push(parseAssignmentExpression()); + + if (!match(']')) { + expect(','); + } + } + } + + lex(); + + return delegate.markEnd(delegate.createArrayExpression(elements), startToken); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(param, first) { + var previousStrict, body, startToken; + + previousStrict = strict; + startToken = lookahead; + body = parseFunctionSourceElements(); + if (first && strict && isRestrictedWord(param[0].name)) { + throwErrorTolerant(first, Messages.StrictParamName); + } + strict = previousStrict; + return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); + } + + function parseObjectPropertyKey() { + var token, startToken; + + startToken = lookahead; + token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return delegate.markEnd(delegate.createLiteral(token), startToken); + } + + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + } + + function parseObjectProperty() { + var token, key, id, value, param, startToken; + + token = lookahead; + startToken = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + value = parsePropertyFunction([]); + return delegate.markEnd(delegate.createProperty('get', key, value), startToken); + } + if (token.value === 'set' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + if (token.type !== Token.Identifier) { + expect(')'); + throwErrorTolerant(token, Messages.UnexpectedToken, token.value); + value = parsePropertyFunction([]); + } else { + param = [ parseVariableIdentifier() ]; + expect(')'); + value = parsePropertyFunction(param, token); + } + return delegate.markEnd(delegate.createProperty('set', key, value), startToken); + } + expect(':'); + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', id, value), startToken); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + throwUnexpected(token); + } else { + key = parseObjectPropertyKey(); + expect(':'); + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', key, value), startToken); + } + } + + function parseObjectInitialiser() { + var properties = [], property, name, key, kind, map = {}, toString = String, startToken; + + startToken = lookahead; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[key] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[key] |= kind; + } else { + map[key] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return delegate.markEnd(delegate.createObjectExpression(properties), startToken); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + expr = parseExpression(); + + expect(')'); + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token, expr, startToken; + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + type = lookahead.type; + startToken = lookahead; + + if (type === Token.Identifier) { + expr = delegate.createIdentifier(lex().value); + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + expr = delegate.createLiteral(lex()); + } else if (type === Token.Keyword) { + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + if (matchKeyword('this')) { + lex(); + expr = delegate.createThisExpression(); + } else { + throwUnexpected(lex()); + } + } else if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + expr = delegate.createLiteral(token); + } else if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + expr = delegate.createLiteral(token); + } else if (match('/') || match('/=')) { + if (typeof extra.tokens !== 'undefined') { + expr = delegate.createLiteral(collectRegex()); + } else { + expr = delegate.createLiteral(scanRegExp()); + } + peek(); + } else { + throwUnexpected(lex()); + } + + return delegate.markEnd(expr, startToken); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = []; + + expect('('); + + if (!match(')')) { + while (index < length) { + args.push(parseAssignmentExpression()); + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseNonComputedProperty() { + var token, startToken; + + startToken = lookahead; + token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args, startToken; + + startToken = lookahead; + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property, startToken, previousAllowIn = state.allowIn; + + startToken = lookahead; + state.allowIn = true; + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + for (;;) { + if (match('.')) { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } else if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + } else if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + } else { + break; + } + delegate.markEnd(expr, startToken); + } + state.allowIn = previousAllowIn; + + return expr; + } + + function parseLeftHandSideExpression() { + var expr, property, startToken; + assert(state.allowIn, 'callee of new expression always allow in keyword.'); + + startToken = lookahead; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[')) { + if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + } else { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } + delegate.markEnd(expr, startToken); + } + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr, token, startToken = lookahead; + + expr = parseLeftHandSideExpressionAllowCall(); + + if (lookahead.type === Token.Punctuator) { + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); + } + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr, startToken; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + expr = parsePostfixExpression(); + } else if (match('++') || match('--')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (match('+') || match('-') || match('~') || match('!')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + } else { + expr = parsePostfixExpression(); + } + + return expr; + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + function parseBinaryExpression() { + var marker, markers, expr, token, prec, stack, right, operator, left, i; + + marker = lookahead; + left = parseUnaryExpression(); + + token = lookahead; + prec = binaryPrecedence(token, state.allowIn); + if (prec === 0) { + return left; + } + token.prec = prec; + lex(); + + markers = [marker, lookahead]; + right = parseUnaryExpression(); + + stack = [left, token, right]; + + while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + expr = delegate.createBinaryExpression(operator, left, right); + markers.pop(); + marker = markers[markers.length - 1]; + delegate.markEnd(expr, marker); + stack.push(expr); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + markers.push(lookahead); + expr = parseUnaryExpression(); + stack.push(expr); + } + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + markers.pop(); + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + marker = markers.pop(); + delegate.markEnd(expr, marker); + } + + return expr; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate, startToken; + + startToken = lookahead; + + expr = parseBinaryExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = delegate.createConditionalExpression(expr, consequent, alternate); + delegate.markEnd(expr, startToken); + } + + return expr; + } + + // 11.13 Assignment Operators + + function parseAssignmentExpression() { + var token, left, right, node, startToken; + + token = lookahead; + startToken = lookahead; + + node = left = parseConditionalExpression(); + + if (matchAssign()) { + // LeftHandSideExpression + if (!isLeftHandSide(left)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + // 11.13.1 + if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + token = lex(); + right = parseAssignmentExpression(); + node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); + } + + return node; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr, startToken = lookahead; + + expr = parseAssignmentExpression(); + + if (match(',')) { + expr = delegate.createSequenceExpression([ expr ]); + + while (index < length) { + if (!match(',')) { + break; + } + lex(); + expr.expressions.push(parseAssignmentExpression()); + } + + delegate.markEnd(expr, startToken); + } + + return expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block, startToken; + + startToken = lookahead; + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return delegate.markEnd(delegate.createBlockStatement(block), startToken); + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token, startToken; + + startToken = lookahead; + token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + } + + function parseVariableDeclaration(kind) { + var init = null, id, startToken; + + startToken = lookahead; + id = parseVariableIdentifier(); + + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + + if (kind === 'const') { + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations, startToken; + + startToken = lookahead; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + return delegate.createEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + consumeSemicolon(); + return delegate.createExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return delegate.createIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return delegate.createDoWhileStatement(body, test); + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return delegate.createWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token, declarations, startToken; + + startToken = lookahead; + token = lex(); + declarations = parseVariableDeclarationList(); + + return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); + } + + function parseForStatement() { + var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; + + init = test = update = null; + + expectKeyword('for'); + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = previousAllowIn; + + if (init.declarations.length === 1 && matchKeyword('in')) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = previousAllowIn; + + if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isLeftHandSide(init)) { + throwErrorTolerant({}, Messages.InvalidLHSInForIn); + } + + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return (typeof left === 'undefined') ? + delegate.createForStatement(init, test, update, body) : + delegate.createForInStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(index) === 0x3B) { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement() { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement() { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(index) === 0x20) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return delegate.createReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return delegate.createReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return delegate.createReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + // TODO(ikarienator): Should we update the test cases instead? + skipComment(); + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return delegate.createWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, consequent = [], statement, startToken; + + startToken = lookahead; + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + statement = parseStatement(); + consequent.push(statement); + } + + return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return delegate.createSwitchStatement(discriminant, cases); + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return delegate.createSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return delegate.createThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body, startToken; + + startToken = lookahead; + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpected(lookahead); + } + + param = parseVariableIdentifier(); + // 12.14.1 + if (strict && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return delegate.markEnd(delegate.createCatchClause(param, body), startToken); + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return delegate.createTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return delegate.createDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key, + startToken; + + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator && lookahead.value === '{') { + return parseBlock(); + } + + startToken = lookahead; + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return delegate.markEnd(parseEmptyStatement(), startToken); + case '(': + return delegate.markEnd(parseExpressionStatement(), startToken); + default: + break; + } + } + + if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return delegate.markEnd(parseBreakStatement(), startToken); + case 'continue': + return delegate.markEnd(parseContinueStatement(), startToken); + case 'debugger': + return delegate.markEnd(parseDebuggerStatement(), startToken); + case 'do': + return delegate.markEnd(parseDoWhileStatement(), startToken); + case 'for': + return delegate.markEnd(parseForStatement(), startToken); + case 'function': + return delegate.markEnd(parseFunctionDeclaration(), startToken); + case 'if': + return delegate.markEnd(parseIfStatement(), startToken); + case 'return': + return delegate.markEnd(parseReturnStatement(), startToken); + case 'switch': + return delegate.markEnd(parseSwitchStatement(), startToken); + case 'throw': + return delegate.markEnd(parseThrowStatement(), startToken); + case 'try': + return delegate.markEnd(parseTryStatement(), startToken); + case 'var': + return delegate.markEnd(parseVariableStatement(), startToken); + case 'while': + return delegate.markEnd(parseWhileStatement(), startToken); + case 'with': + return delegate.markEnd(parseWithStatement(), startToken); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); + } + + consumeSemicolon(); + + return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); + } + + // 13 Function Definition + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; + + startToken = lookahead; + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + + return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); + } + + function parseParams(firstRestricted) { + var param, params = [], token, stricted, paramSet, key, message; + expect('('); + + if (!match(')')) { + paramSet = {}; + while (index < length) { + token = lookahead; + param = parseVariableIdentifier(); + key = '$' + token.value; + if (strict) { + if (isRestrictedWord(token.value)) { + stricted = token; + message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(paramSet, key)) { + stricted = token; + message = Messages.StrictParamDupe; + } + } else if (!firstRestricted) { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { + firstRestricted = token; + message = Messages.StrictParamDupe; + } + } + params.push(param); + paramSet[key] = true; + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + return { + params: params, + stricted: stricted, + firstRestricted: firstRestricted, + message: message + }; + } + + function parseFunctionDeclaration() { + var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; + + startToken = lookahead; + + expectKeyword('function'); + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); + } + + function parseFunctionExpression() { + var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; + + startToken = lookahead; + expectKeyword('function'); + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); + } + + // 14 Program + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + default: + return parseStatement(); + } + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseSourceElement(); + /* istanbul ignore if */ + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseProgram() { + var body, startToken; + + skipComment(); + peek(); + startToken = lookahead; + strict = false; + + body = parseSourceElements(); + return delegate.markEnd(delegate.createProgram(body), startToken); + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function tokenize(code, options) { + var toString, + token, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; + + if (extra.loc && options.source !== null && options.source !== undefined) { + extra.source = toString(options.source); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + if (extra.attachComment) { + extra.range = true; + extra.comments = []; + extra.bottomRightStack = []; + extra.trailingComments = []; + extra.leadingComments = []; + } + } + + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + + return program; + } + + // Sync with *.json manifests. + exports.version = '1.2.4'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + /* istanbul ignore next */ + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{}],22:[function(_dereq_,module,exports){ +/** + * power-assert-formatter.js - Power Assert output formatter + * + * https://github.com/twada/power-assert-formatter + * + * Copyright (c) 2013-2015 Takuto Wada + * Licensed under the MIT license. + * https://github.com/twada/power-assert-formatter/blob/master/MIT-LICENSE.txt + */ +'use strict'; + +module.exports = _dereq_('./lib/create'); + +},{"./lib/create":27}],23:[function(_dereq_,module,exports){ +'use strict'; + +function AssertionRenderer (traversal, config) { + var assertionLine; + traversal.on('start', function (context) { + assertionLine = context.source.content; + }); + traversal.on('render', function (writer) { + writer.write(''); + writer.write(assertionLine); + }); +} +module.exports = AssertionRenderer; + +},{}],24:[function(_dereq_,module,exports){ +'use strict'; + +var typeName = _dereq_('type-name'), + keys = Object.keys || _dereq_('object-keys'), + syntax = _dereq_('estraverse').Syntax; + + +function BinaryExpressionRenderer(traversal, config) { + this.config = config; + this.stringify = config.stringify; + this.diff = config.diff; + this.espathToPair = {}; + var _this = this; + traversal.on('esnode', function (esNode) { + var pair; + if (!esNode.isCaptured()) { + if (isTargetBinaryExpression(esNode.getParent()) && esNode.currentNode.type === syntax.Literal) { + _this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()}; + } + return; + } + if (isTargetBinaryExpression(esNode.getParent())) { + _this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()}; + } + if (isTargetBinaryExpression(esNode)) { + pair = { + operator: esNode.currentNode.operator, + value: esNode.value() + }; + _this.espathToPair[esNode.espath] = pair; + } + }); + traversal.on('render', function (writer) { + var pairs = []; + keys(_this.espathToPair).forEach(function (espath) { + var pair = _this.espathToPair[espath]; + if (pair.left && pair.right) { + pairs.push(pair); + } + }); + pairs.forEach(function (pair) { + _this.compare(pair, writer); + }); + }); +} + +BinaryExpressionRenderer.prototype.compare = function (pair, writer) { + if (isStringDiffTarget(pair)) { + this.showStringDiff(pair, writer); + } else { + this.showExpectedAndActual(pair, writer); + } +}; + +BinaryExpressionRenderer.prototype.showExpectedAndActual = function (pair, writer) { + writer.write(''); + writer.write('[' + typeName(pair.right.value) + '] ' + pair.right.code); + writer.write('=> ' + this.stringify(pair.right.value)); + writer.write('[' + typeName(pair.left.value) + '] ' + pair.left.code); + writer.write('=> ' + this.stringify(pair.left.value)); +}; + +BinaryExpressionRenderer.prototype.showStringDiff = function (pair, writer) { + writer.write(''); + writer.write('--- [string] ' + pair.right.code); + writer.write('+++ [string] ' + pair.left.code); + writer.write(this.diff(pair.right.value, pair.left.value, this.config)); +}; + +function isTargetBinaryExpression (esNode) { + return esNode && + esNode.currentNode.type === syntax.BinaryExpression && + (esNode.currentNode.operator === '===' || esNode.currentNode.operator === '==') && + esNode.isCaptured() && + !(esNode.value()); +} + +function isStringDiffTarget(pair) { + return typeof pair.left.value === 'string' && typeof pair.right.value === 'string'; +} + +module.exports = BinaryExpressionRenderer; + +},{"estraverse":36,"object-keys":39,"type-name":43}],25:[function(_dereq_,module,exports){ +'use strict'; + +function DiagramRenderer (traversal, config) { + this.config = config; + this.events = []; + this.stringify = config.stringify; + this.widthOf = config.widthOf; + this.initialVertivalBarLength = 1; + var _this = this; + traversal.on('start', function (context) { + _this.context = context; + _this.assertionLine = context.source.content; + _this.initializeRows(); + }); + traversal.on('esnode', function (esNode) { + if (!esNode.isCaptured()) { + return; + } + _this.events.push({value: esNode.value(), loc: esNode.location()}); + }); + traversal.on('render', function (writer) { + _this.events.sort(rightToLeft); + _this.constructRows(_this.events); + _this.rows.forEach(function (columns) { + writer.write(columns.join('')); + }); + }); +} + +DiagramRenderer.prototype.initializeRows = function () { + this.rows = []; + for (var i = 0; i <= this.initialVertivalBarLength; i += 1) { + this.addOneMoreRow(); + } +}; + +DiagramRenderer.prototype.newRowFor = function (assertionLine) { + return createRow(this.widthOf(assertionLine), ' '); +}; + +DiagramRenderer.prototype.addOneMoreRow = function () { + this.rows.push(this.newRowFor(this.assertionLine)); +}; + +DiagramRenderer.prototype.lastRow = function () { + return this.rows[this.rows.length - 1]; +}; + +DiagramRenderer.prototype.renderVerticalBarAt = function (columnIndex) { + var i, lastRowIndex = this.rows.length - 1; + for (i = 0; i < lastRowIndex; i += 1) { + this.rows[i].splice(columnIndex, 1, '|'); + } +}; + +DiagramRenderer.prototype.renderValueAt = function (columnIndex, dumpedValue) { + var i, width = this.widthOf(dumpedValue); + for (i = 0; i < width; i += 1) { + this.lastRow().splice(columnIndex + i, 1, dumpedValue.charAt(i)); + } +}; + +DiagramRenderer.prototype.isOverlapped = function (prevCapturing, nextCaputuring, dumpedValue) { + return (typeof prevCapturing !== 'undefined') && this.startColumnFor(prevCapturing) <= (this.startColumnFor(nextCaputuring) + this.widthOf(dumpedValue)); +}; + +DiagramRenderer.prototype.constructRows = function (capturedEvents) { + var that = this, + prevCaptured; + capturedEvents.forEach(function (captured) { + var dumpedValue = that.stringify(captured.value); + if (that.isOverlapped(prevCaptured, captured, dumpedValue)) { + that.addOneMoreRow(); + } + that.renderVerticalBarAt(that.startColumnFor(captured)); + that.renderValueAt(that.startColumnFor(captured), dumpedValue); + prevCaptured = captured; + }); +}; + +DiagramRenderer.prototype.startColumnFor = function (captured) { + return this.widthOf(this.assertionLine.slice(0, captured.loc.start.column)); +}; + +function createRow (numCols, initial) { + var row = [], i; + for(i = 0; i < numCols; i += 1) { + row[i] = initial; + } + return row; +} + +function rightToLeft (a, b) { + return b.loc.start.column - a.loc.start.column; +} + +module.exports = DiagramRenderer; + +},{}],26:[function(_dereq_,module,exports){ +'use strict'; + +function FileRenderer (traversal, config) { + var filepath, lineNumber; + traversal.on('start', function (context) { + filepath = context.source.filepath; + lineNumber = context.source.line; + }); + traversal.on('render', function (writer) { + if (filepath) { + writer.write('# ' + [filepath, lineNumber].join(':')); + } else { + writer.write('# at line: ' + lineNumber); + } + }); +} +module.exports = FileRenderer; + +},{}],27:[function(_dereq_,module,exports){ +'use strict'; + +var stringifier = _dereq_('stringifier'), + stringWidth = _dereq_('./string-width'), + StringWriter = _dereq_('./string-writer'), + ContextTraversal = _dereq_('./traverse'), + udiff = _dereq_('./udiff'), + defaultOptions = _dereq_('./default-options'), + typeName = _dereq_('type-name'), + extend = _dereq_('xtend'); + +(function() { + // "Browserify can only analyze static requires. It is not in the scope of browserify to handle dynamic requires." + // https://github.com/substack/node-browserify/issues/377 + _dereq_('./built-in/assertion'); + _dereq_('./built-in/binary-expression'); + _dereq_('./built-in/diagram'); + _dereq_('./built-in/file'); +})(); + +function create (options) { + var config = extend(defaultOptions(), options); + if (typeof config.widthOf !== 'function') { + config.widthOf = stringWidth(extend(config)); + } + if (typeof config.stringify !== 'function') { + config.stringify = stringifier(extend(config)); + } + if (typeof config.diff !== 'function') { + config.diff = udiff(extend(config)); + } + if (!config.writerClass) { + config.writerClass = StringWriter; + } + return function (context) { + var traversal = new ContextTraversal(context); + var writer = new config.writerClass(extend(config)); + var renderers = config.renderers.map(function (rendererName) { + var RendererClass; + if (typeName(rendererName) === 'function') { + RendererClass = rendererName; + } else if (typeName(rendererName) === 'string') { + RendererClass = _dereq_(rendererName); + } + return new RendererClass(traversal, extend(config)); + }); + traversal.emit('start', context); + traversal.traverse(); + traversal.emit('render', writer); + writer.write(''); + renderers.length = 0; + return writer.flush(); + }; +} + +create.defaultOptions = defaultOptions; +create.stringWidth = stringWidth; +module.exports = create; + +},{"./built-in/assertion":23,"./built-in/binary-expression":24,"./built-in/diagram":25,"./built-in/file":26,"./default-options":28,"./string-width":31,"./string-writer":32,"./traverse":33,"./udiff":34,"stringifier":41,"type-name":43,"xtend":45}],28:[function(_dereq_,module,exports){ +module.exports = function defaultOptions () { + 'use strict'; + return { + lineDiffThreshold: 5, + maxDepth: 1, + outputOffset: 2, + anonymous: 'Object', + circular: '#@Circular#', + lineSeparator: '\n', + ambiguousEastAsianCharWidth: 2, + renderers: [ + './built-in/file', + './built-in/assertion', + './built-in/diagram', + './built-in/binary-expression' + ] + }; +}; + +},{}],29:[function(_dereq_,module,exports){ +'use strict'; + +var syntax = _dereq_('estraverse').Syntax, + locationOf = _dereq_('./location'); + +function EsNode (path, currentNode, parentNode, espathToValue, jsCode, jsAST) { + if (path) { + this.espath = path.join('/'); + this.parentEspath = path.slice(0, path.length - 1).join('/'); + this.currentProp = path[path.length - 1]; + } else { + this.espath = ''; + this.parentEspath = ''; + this.currentProp = null; + } + this.currentNode = currentNode; + this.parentNode = parentNode; + this.parentEsNode = null; + this.espathToValue = espathToValue; + this.jsCode = jsCode; + this.jsAST = jsAST; +} + +EsNode.prototype.setParent = function (parentEsNode) { + this.parentEsNode = parentEsNode; +}; + +EsNode.prototype.getParent = function () { + return this.parentEsNode; +}; + +EsNode.prototype.code = function () { + return this.jsCode.slice(this.currentNode.loc.start.column, this.currentNode.loc.end.column); +}; + +EsNode.prototype.value = function () { + if (this.currentNode.type === syntax.Literal) { + return this.currentNode.value; + } + return this.espathToValue[this.espath]; +}; + +EsNode.prototype.isCaptured = function () { + return this.espathToValue.hasOwnProperty(this.espath); +}; + +EsNode.prototype.location = function () { + return locationOf(this.currentNode, this.jsAST.tokens); +}; + +module.exports = EsNode; + +},{"./location":30,"estraverse":36}],30:[function(_dereq_,module,exports){ +'use strict'; + +var syntax = _dereq_('estraverse').Syntax; + +function locationOf(currentNode, tokens) { + switch(currentNode.type) { + case syntax.MemberExpression: + return propertyLocationOf(currentNode, tokens); + case syntax.CallExpression: + if (currentNode.callee.type === syntax.MemberExpression) { + return propertyLocationOf(currentNode.callee, tokens); + } + break; + case syntax.BinaryExpression: + case syntax.LogicalExpression: + case syntax.AssignmentExpression: + return infixOperatorLocationOf(currentNode, tokens); + default: + break; + } + return currentNode.loc; +} + +function propertyLocationOf(memberExpression, tokens) { + var prop = memberExpression.property, + token; + if (!memberExpression.computed) { + return prop.loc; + } + token = findLeftBracketTokenOf(memberExpression, tokens); + return token ? token.loc : prop.loc; +} + +// calculate location of infix operator for BinaryExpression, AssignmentExpression and LogicalExpression. +function infixOperatorLocationOf (expression, tokens) { + var token = findOperatorTokenOf(expression, tokens); + return token ? token.loc : expression.left.loc; +} + +function findLeftBracketTokenOf(expression, tokens) { + var fromLine = expression.loc.start.line, + toLine = expression.property.loc.start.line, + fromColumn = expression.property.loc.start.column; + return searchToken(tokens, fromLine, toLine, function (token, index) { + var prevToken; + if (token.loc.start.column === fromColumn) { + prevToken = tokens[index - 1]; + if (prevToken.type === 'Punctuator' && prevToken.value === '[') { + return prevToken; + } + } + return undefined; + }); +} + +function findOperatorTokenOf(expression, tokens) { + var fromLine = expression.left.loc.end.line, + toLine = expression.right.loc.start.line, + fromColumn = expression.left.loc.end.column, + toColumn = expression.right.loc.start.column; + return searchToken(tokens, fromLine, toLine, function (token, index) { + if (fromColumn < token.loc.start.column && + token.loc.end.column < toColumn && + token.type === 'Punctuator' && + token.value === expression.operator) { + return token; + } + return undefined; + }); +} + +function searchToken(tokens, fromLine, toLine, predicate) { + var i, token, found; + for(i = 0; i < tokens.length; i += 1) { + token = tokens[i]; + if (token.loc.start.line < fromLine) { + continue; + } + if (toLine < token.loc.end.line) { + break; + } + found = predicate(token, i); + if (found) { + return found; + } + } + return undefined; +} + +module.exports = locationOf; + +},{"estraverse":36}],31:[function(_dereq_,module,exports){ +'use strict'; + +var eaw = _dereq_('eastasianwidth'); + +function stringWidth (config) { + var ambiguousCharWidth = (config && config.ambiguousEastAsianCharWidth) || 1; + return function widthOf (str) { + var i, code, width = 0; + for(i = 0; i < str.length; i+=1) { + code = eaw.eastAsianWidth(str.charAt(i)); + switch(code) { + case 'F': + case 'W': + width += 2; + break; + case 'H': + case 'Na': + case 'N': + width += 1; + break; + case 'A': + width += ambiguousCharWidth; + break; + } + } + return width; + }; +} + +module.exports = stringWidth; + +},{"eastasianwidth":35}],32:[function(_dereq_,module,exports){ +'use strict'; + +function spacerStr (len) { + var str = ''; + for(var i = 0; i < len; i += 1) { + str += ' '; + } + return str; +} + +function StringWriter (config) { + this.lines = []; + this.lineSeparator = config.lineSeparator; + this.regex = new RegExp(this.lineSeparator, 'g'); + this.spacer = spacerStr(config.outputOffset); +} + +StringWriter.prototype.write = function (str) { + this.lines.push(this.spacer + str.replace(this.regex, this.lineSeparator + this.spacer)); +}; + +StringWriter.prototype.flush = function () { + var str = this.lines.join(this.lineSeparator); + this.lines.length = 0; + return str; +}; + +module.exports = StringWriter; + +},{}],33:[function(_dereq_,module,exports){ +'use strict'; + +var estraverse = _dereq_('estraverse'), + esprima = _dereq_('esprima'), + EventEmitter = _dereq_('events').EventEmitter, + inherits = _dereq_('util').inherits, + EsNode = _dereq_('./esnode'); + +function ContextTraversal (context) { + this.context = context; + EventEmitter.call(this); +} +inherits(ContextTraversal, EventEmitter); + +ContextTraversal.prototype.traverse = function () { + var _this = this; + this.context.args.forEach(function (arg) { + onEachEsNode(arg, _this.context.source.content, function (esNode) { + _this.emit('esnode', esNode); + }); + }); +}; + +function onEachEsNode(arg, jsCode, callback) { + var jsAST = esprima.parse(jsCode, {tolerant: true, loc: true, tokens: true, raw: true}), + espathToValue = arg.events.reduce(function (accum, ev) { + accum[ev.espath] = ev.value; + return accum; + }, {}), + nodeStack = []; + estraverse.traverse(extractExpressionFrom(jsAST), { + enter: function (currentNode, parentNode) { + var esNode = new EsNode(this.path(), currentNode, parentNode, espathToValue, jsCode, jsAST); + if (1 < nodeStack.length) { + esNode.setParent(nodeStack[nodeStack.length - 1]); + } + nodeStack.push(esNode); + callback(esNode); + }, + leave: function (currentNode, parentNode) { + nodeStack.pop(); + } + }); +} + +function extractExpressionFrom (tree) { + var expressionStatement = tree.body[0], + expression = expressionStatement.expression; + return expression; +} + +module.exports = ContextTraversal; + +},{"./esnode":29,"esprima":21,"estraverse":36,"events":2,"util":6}],34:[function(_dereq_,module,exports){ +'use strict'; + +var DiffMatchPatch = _dereq_('googlediff'), + dmp = new DiffMatchPatch(); + +function udiff (config) { + return function diff (text1, text2) { + var patch; + if (config && shouldUseLineLevelDiff(text1, config)) { + patch = udiffLines(text1, text2); + } else { + patch = udiffChars(text1, text2); + } + return decodeURIComponent(patch); + }; +} + +function shouldUseLineLevelDiff (text, config) { + return config.lineDiffThreshold < text.split(/\r\n|\r|\n/).length; +} + +function udiffLines(text1, text2) { + /*jshint camelcase: false */ + var a = dmp.diff_linesToChars_(text1, text2), + diffs = dmp.diff_main(a.chars1, a.chars2, false); + dmp.diff_charsToLines_(diffs, a.lineArray); + dmp.diff_cleanupSemantic(diffs); + return dmp.patch_toText(dmp.patch_make(text1, diffs)); +} + +function udiffChars (text1, text2) { + /*jshint camelcase: false */ + var diffs = dmp.diff_main(text1, text2, false); + dmp.diff_cleanupSemantic(diffs); + return dmp.patch_toText(dmp.patch_make(text1, diffs)); +} + +module.exports = udiff; + +},{"googlediff":37}],35:[function(_dereq_,module,exports){ +var eaw = exports; + +eaw.eastAsianWidth = function(character) { + var x = character.charCodeAt(0); + var y = (character.length == 2) ? character.charCodeAt(1) : 0; + var codePoint = x; + if ((0xD800 <= x && x <= 0xDBFF) && (0xDC00 <= y && y <= 0xDFFF)) { + x &= 0x3FF; + y &= 0x3FF; + codePoint = (x << 10) | y; + codePoint += 0x10000; + } + + if ((0x3000 == codePoint) || + (0xFF01 <= codePoint && codePoint <= 0xFF60) || + (0xFFE0 <= codePoint && codePoint <= 0xFFE6)) { + return 'F'; + } + if ((0x20A9 == codePoint) || + (0xFF61 <= codePoint && codePoint <= 0xFFBE) || + (0xFFC2 <= codePoint && codePoint <= 0xFFC7) || + (0xFFCA <= codePoint && codePoint <= 0xFFCF) || + (0xFFD2 <= codePoint && codePoint <= 0xFFD7) || + (0xFFDA <= codePoint && codePoint <= 0xFFDC) || + (0xFFE8 <= codePoint && codePoint <= 0xFFEE)) { + return 'H'; + } + if ((0x1100 <= codePoint && codePoint <= 0x115F) || + (0x11A3 <= codePoint && codePoint <= 0x11A7) || + (0x11FA <= codePoint && codePoint <= 0x11FF) || + (0x2329 <= codePoint && codePoint <= 0x232A) || + (0x2E80 <= codePoint && codePoint <= 0x2E99) || + (0x2E9B <= codePoint && codePoint <= 0x2EF3) || + (0x2F00 <= codePoint && codePoint <= 0x2FD5) || + (0x2FF0 <= codePoint && codePoint <= 0x2FFB) || + (0x3001 <= codePoint && codePoint <= 0x303E) || + (0x3041 <= codePoint && codePoint <= 0x3096) || + (0x3099 <= codePoint && codePoint <= 0x30FF) || + (0x3105 <= codePoint && codePoint <= 0x312D) || + (0x3131 <= codePoint && codePoint <= 0x318E) || + (0x3190 <= codePoint && codePoint <= 0x31BA) || + (0x31C0 <= codePoint && codePoint <= 0x31E3) || + (0x31F0 <= codePoint && codePoint <= 0x321E) || + (0x3220 <= codePoint && codePoint <= 0x3247) || + (0x3250 <= codePoint && codePoint <= 0x32FE) || + (0x3300 <= codePoint && codePoint <= 0x4DBF) || + (0x4E00 <= codePoint && codePoint <= 0xA48C) || + (0xA490 <= codePoint && codePoint <= 0xA4C6) || + (0xA960 <= codePoint && codePoint <= 0xA97C) || + (0xAC00 <= codePoint && codePoint <= 0xD7A3) || + (0xD7B0 <= codePoint && codePoint <= 0xD7C6) || + (0xD7CB <= codePoint && codePoint <= 0xD7FB) || + (0xF900 <= codePoint && codePoint <= 0xFAFF) || + (0xFE10 <= codePoint && codePoint <= 0xFE19) || + (0xFE30 <= codePoint && codePoint <= 0xFE52) || + (0xFE54 <= codePoint && codePoint <= 0xFE66) || + (0xFE68 <= codePoint && codePoint <= 0xFE6B) || + (0x1B000 <= codePoint && codePoint <= 0x1B001) || + (0x1F200 <= codePoint && codePoint <= 0x1F202) || + (0x1F210 <= codePoint && codePoint <= 0x1F23A) || + (0x1F240 <= codePoint && codePoint <= 0x1F248) || + (0x1F250 <= codePoint && codePoint <= 0x1F251) || + (0x20000 <= codePoint && codePoint <= 0x2F73F) || + (0x2B740 <= codePoint && codePoint <= 0x2FFFD) || + (0x30000 <= codePoint && codePoint <= 0x3FFFD)) { + return 'W'; + } + if ((0x0020 <= codePoint && codePoint <= 0x007E) || + (0x00A2 <= codePoint && codePoint <= 0x00A3) || + (0x00A5 <= codePoint && codePoint <= 0x00A6) || + (0x00AC == codePoint) || + (0x00AF == codePoint) || + (0x27E6 <= codePoint && codePoint <= 0x27ED) || + (0x2985 <= codePoint && codePoint <= 0x2986)) { + return 'Na'; + } + if ((0x00A1 == codePoint) || + (0x00A4 == codePoint) || + (0x00A7 <= codePoint && codePoint <= 0x00A8) || + (0x00AA == codePoint) || + (0x00AD <= codePoint && codePoint <= 0x00AE) || + (0x00B0 <= codePoint && codePoint <= 0x00B4) || + (0x00B6 <= codePoint && codePoint <= 0x00BA) || + (0x00BC <= codePoint && codePoint <= 0x00BF) || + (0x00C6 == codePoint) || + (0x00D0 == codePoint) || + (0x00D7 <= codePoint && codePoint <= 0x00D8) || + (0x00DE <= codePoint && codePoint <= 0x00E1) || + (0x00E6 == codePoint) || + (0x00E8 <= codePoint && codePoint <= 0x00EA) || + (0x00EC <= codePoint && codePoint <= 0x00ED) || + (0x00F0 == codePoint) || + (0x00F2 <= codePoint && codePoint <= 0x00F3) || + (0x00F7 <= codePoint && codePoint <= 0x00FA) || + (0x00FC == codePoint) || + (0x00FE == codePoint) || + (0x0101 == codePoint) || + (0x0111 == codePoint) || + (0x0113 == codePoint) || + (0x011B == codePoint) || + (0x0126 <= codePoint && codePoint <= 0x0127) || + (0x012B == codePoint) || + (0x0131 <= codePoint && codePoint <= 0x0133) || + (0x0138 == codePoint) || + (0x013F <= codePoint && codePoint <= 0x0142) || + (0x0144 == codePoint) || + (0x0148 <= codePoint && codePoint <= 0x014B) || + (0x014D == codePoint) || + (0x0152 <= codePoint && codePoint <= 0x0153) || + (0x0166 <= codePoint && codePoint <= 0x0167) || + (0x016B == codePoint) || + (0x01CE == codePoint) || + (0x01D0 == codePoint) || + (0x01D2 == codePoint) || + (0x01D4 == codePoint) || + (0x01D6 == codePoint) || + (0x01D8 == codePoint) || + (0x01DA == codePoint) || + (0x01DC == codePoint) || + (0x0251 == codePoint) || + (0x0261 == codePoint) || + (0x02C4 == codePoint) || + (0x02C7 == codePoint) || + (0x02C9 <= codePoint && codePoint <= 0x02CB) || + (0x02CD == codePoint) || + (0x02D0 == codePoint) || + (0x02D8 <= codePoint && codePoint <= 0x02DB) || + (0x02DD == codePoint) || + (0x02DF == codePoint) || + (0x0300 <= codePoint && codePoint <= 0x036F) || + (0x0391 <= codePoint && codePoint <= 0x03A1) || + (0x03A3 <= codePoint && codePoint <= 0x03A9) || + (0x03B1 <= codePoint && codePoint <= 0x03C1) || + (0x03C3 <= codePoint && codePoint <= 0x03C9) || + (0x0401 == codePoint) || + (0x0410 <= codePoint && codePoint <= 0x044F) || + (0x0451 == codePoint) || + (0x2010 == codePoint) || + (0x2013 <= codePoint && codePoint <= 0x2016) || + (0x2018 <= codePoint && codePoint <= 0x2019) || + (0x201C <= codePoint && codePoint <= 0x201D) || + (0x2020 <= codePoint && codePoint <= 0x2022) || + (0x2024 <= codePoint && codePoint <= 0x2027) || + (0x2030 == codePoint) || + (0x2032 <= codePoint && codePoint <= 0x2033) || + (0x2035 == codePoint) || + (0x203B == codePoint) || + (0x203E == codePoint) || + (0x2074 == codePoint) || + (0x207F == codePoint) || + (0x2081 <= codePoint && codePoint <= 0x2084) || + (0x20AC == codePoint) || + (0x2103 == codePoint) || + (0x2105 == codePoint) || + (0x2109 == codePoint) || + (0x2113 == codePoint) || + (0x2116 == codePoint) || + (0x2121 <= codePoint && codePoint <= 0x2122) || + (0x2126 == codePoint) || + (0x212B == codePoint) || + (0x2153 <= codePoint && codePoint <= 0x2154) || + (0x215B <= codePoint && codePoint <= 0x215E) || + (0x2160 <= codePoint && codePoint <= 0x216B) || + (0x2170 <= codePoint && codePoint <= 0x2179) || + (0x2189 == codePoint) || + (0x2190 <= codePoint && codePoint <= 0x2199) || + (0x21B8 <= codePoint && codePoint <= 0x21B9) || + (0x21D2 == codePoint) || + (0x21D4 == codePoint) || + (0x21E7 == codePoint) || + (0x2200 == codePoint) || + (0x2202 <= codePoint && codePoint <= 0x2203) || + (0x2207 <= codePoint && codePoint <= 0x2208) || + (0x220B == codePoint) || + (0x220F == codePoint) || + (0x2211 == codePoint) || + (0x2215 == codePoint) || + (0x221A == codePoint) || + (0x221D <= codePoint && codePoint <= 0x2220) || + (0x2223 == codePoint) || + (0x2225 == codePoint) || + (0x2227 <= codePoint && codePoint <= 0x222C) || + (0x222E == codePoint) || + (0x2234 <= codePoint && codePoint <= 0x2237) || + (0x223C <= codePoint && codePoint <= 0x223D) || + (0x2248 == codePoint) || + (0x224C == codePoint) || + (0x2252 == codePoint) || + (0x2260 <= codePoint && codePoint <= 0x2261) || + (0x2264 <= codePoint && codePoint <= 0x2267) || + (0x226A <= codePoint && codePoint <= 0x226B) || + (0x226E <= codePoint && codePoint <= 0x226F) || + (0x2282 <= codePoint && codePoint <= 0x2283) || + (0x2286 <= codePoint && codePoint <= 0x2287) || + (0x2295 == codePoint) || + (0x2299 == codePoint) || + (0x22A5 == codePoint) || + (0x22BF == codePoint) || + (0x2312 == codePoint) || + (0x2460 <= codePoint && codePoint <= 0x24E9) || + (0x24EB <= codePoint && codePoint <= 0x254B) || + (0x2550 <= codePoint && codePoint <= 0x2573) || + (0x2580 <= codePoint && codePoint <= 0x258F) || + (0x2592 <= codePoint && codePoint <= 0x2595) || + (0x25A0 <= codePoint && codePoint <= 0x25A1) || + (0x25A3 <= codePoint && codePoint <= 0x25A9) || + (0x25B2 <= codePoint && codePoint <= 0x25B3) || + (0x25B6 <= codePoint && codePoint <= 0x25B7) || + (0x25BC <= codePoint && codePoint <= 0x25BD) || + (0x25C0 <= codePoint && codePoint <= 0x25C1) || + (0x25C6 <= codePoint && codePoint <= 0x25C8) || + (0x25CB == codePoint) || + (0x25CE <= codePoint && codePoint <= 0x25D1) || + (0x25E2 <= codePoint && codePoint <= 0x25E5) || + (0x25EF == codePoint) || + (0x2605 <= codePoint && codePoint <= 0x2606) || + (0x2609 == codePoint) || + (0x260E <= codePoint && codePoint <= 0x260F) || + (0x2614 <= codePoint && codePoint <= 0x2615) || + (0x261C == codePoint) || + (0x261E == codePoint) || + (0x2640 == codePoint) || + (0x2642 == codePoint) || + (0x2660 <= codePoint && codePoint <= 0x2661) || + (0x2663 <= codePoint && codePoint <= 0x2665) || + (0x2667 <= codePoint && codePoint <= 0x266A) || + (0x266C <= codePoint && codePoint <= 0x266D) || + (0x266F == codePoint) || + (0x269E <= codePoint && codePoint <= 0x269F) || + (0x26BE <= codePoint && codePoint <= 0x26BF) || + (0x26C4 <= codePoint && codePoint <= 0x26CD) || + (0x26CF <= codePoint && codePoint <= 0x26E1) || + (0x26E3 == codePoint) || + (0x26E8 <= codePoint && codePoint <= 0x26FF) || + (0x273D == codePoint) || + (0x2757 == codePoint) || + (0x2776 <= codePoint && codePoint <= 0x277F) || + (0x2B55 <= codePoint && codePoint <= 0x2B59) || + (0x3248 <= codePoint && codePoint <= 0x324F) || + (0xE000 <= codePoint && codePoint <= 0xF8FF) || + (0xFE00 <= codePoint && codePoint <= 0xFE0F) || + (0xFFFD == codePoint) || + (0x1F100 <= codePoint && codePoint <= 0x1F10A) || + (0x1F110 <= codePoint && codePoint <= 0x1F12D) || + (0x1F130 <= codePoint && codePoint <= 0x1F169) || + (0x1F170 <= codePoint && codePoint <= 0x1F19A) || + (0xE0100 <= codePoint && codePoint <= 0xE01EF) || + (0xF0000 <= codePoint && codePoint <= 0xFFFFD) || + (0x100000 <= codePoint && codePoint <= 0x10FFFD)) { + return 'A'; + } + + return 'N'; +}; + +eaw.characterLength = function(character) { + var code = this.eastAsianWidth(character); + if (code == 'F' || code == 'W' || code == 'A') { + return 2; + } else { + return 1; + } +}; + +eaw.length = function(string) { + var len = 0; + for (var i = 0; i < string.length; i++) { + len = len + this.characterLength(string.charAt(i)); + } + return len; +}; + +},{}],36:[function(_dereq_,module,exports){ +/* + Copyright (C) 2012-2013 Yusuke Suzuki + Copyright (C) 2012 Ariya Hidayat + + 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 HOLDERS AND CONTRIBUTORS "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 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. +*/ +/*jslint vars:false, bitwise:true*/ +/*jshint indent:4*/ +/*global exports:true, define:true*/ +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // and plain browser loading, + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.estraverse = {})); + } +}(this, function (exports) { + 'use strict'; + + var Syntax, + isArray, + VisitorOption, + VisitorKeys, + objectCreate, + objectKeys, + BREAK, + SKIP, + REMOVE; + + function ignoreJSHintError() { } + + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + + function deepCopy(obj) { + var ret = {}, key, val; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + ret[key] = deepCopy(val); + } else { + ret[key] = val; + } + } + } + return ret; + } + + function shallowCopy(obj) { + var ret = {}, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = obj[key]; + } + } + return ret; + } + ignoreJSHintError(shallowCopy); + + // based on LLVM libc++ upper_bound / lower_bound + // MIT License + + function upperBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + len = diff; + } else { + i = current + 1; + len -= diff + 1; + } + } + return i; + } + + function lowerBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + i = current + 1; + len -= diff + 1; + } else { + len = diff; + } + } + return i; + } + ignoreJSHintError(lowerBound); + + objectCreate = Object.create || (function () { + function F() { } + + return function (o) { + F.prototype = o; + return new F(); + }; + })(); + + objectKeys = Object.keys || function (o) { + var keys = [], key; + for (key in o) { + keys.push(key); + } + return keys; + }; + + function extend(to, from) { + objectKeys(from).forEach(function (key) { + to[key] = from[key]; + }); + return to; + } + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. + ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportBatchSpecifier: 'ExportBatchSpecifier', + ExportDeclaration: 'ExportDeclaration', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', + ImportSpecifier: 'ImportSpecifier', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleSpecifier: 'ModuleSpecifier', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + VisitorKeys = { + AssignmentExpression: ['left', 'right'], + ArrayExpression: ['elements'], + ArrayPattern: ['elements'], + ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'], + BlockStatement: ['body'], + BinaryExpression: ['left', 'right'], + BreakStatement: ['label'], + CallExpression: ['callee', 'arguments'], + CatchClause: ['param', 'body'], + ClassBody: ['body'], + ClassDeclaration: ['id', 'body', 'superClass'], + ClassExpression: ['id', 'body', 'superClass'], + ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. + ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + ConditionalExpression: ['test', 'consequent', 'alternate'], + ContinueStatement: ['label'], + DebuggerStatement: [], + DirectiveStatement: [], + DoWhileStatement: ['body', 'test'], + EmptyStatement: [], + ExportBatchSpecifier: [], + ExportDeclaration: ['declaration', 'specifiers', 'source'], + ExportSpecifier: ['id', 'name'], + ExpressionStatement: ['expression'], + ForStatement: ['init', 'test', 'update', 'body'], + ForInStatement: ['left', 'right', 'body'], + ForOfStatement: ['left', 'right', 'body'], + FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'], + FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], + GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + Identifier: [], + IfStatement: ['test', 'consequent', 'alternate'], + ImportDeclaration: ['specifiers', 'source'], + ImportDefaultSpecifier: ['id'], + ImportNamespaceSpecifier: ['id'], + ImportSpecifier: ['id', 'name'], + Literal: [], + LabeledStatement: ['label', 'body'], + LogicalExpression: ['left', 'right'], + MemberExpression: ['object', 'property'], + MethodDefinition: ['key', 'value'], + ModuleSpecifier: [], + NewExpression: ['callee', 'arguments'], + ObjectExpression: ['properties'], + ObjectPattern: ['properties'], + Program: ['body'], + Property: ['key', 'value'], + ReturnStatement: ['argument'], + SequenceExpression: ['expressions'], + SpreadElement: ['argument'], + SwitchStatement: ['discriminant', 'cases'], + SwitchCase: ['test', 'consequent'], + TaggedTemplateExpression: ['tag', 'quasi'], + TemplateElement: [], + TemplateLiteral: ['quasis', 'expressions'], + ThisExpression: [], + ThrowStatement: ['argument'], + TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], + UnaryExpression: ['argument'], + UpdateExpression: ['argument'], + VariableDeclaration: ['declarations'], + VariableDeclarator: ['id', 'init'], + WhileStatement: ['test', 'body'], + WithStatement: ['object', 'body'], + YieldExpression: ['argument'] + }; + + // unique id + BREAK = {}; + SKIP = {}; + REMOVE = {}; + + VisitorOption = { + Break: BREAK, + Skip: SKIP, + Remove: REMOVE + }; + + function Reference(parent, key) { + this.parent = parent; + this.key = key; + } + + Reference.prototype.replace = function replace(node) { + this.parent[this.key] = node; + }; + + Reference.prototype.remove = function remove() { + if (isArray(this.parent)) { + this.parent.splice(this.key, 1); + return true; + } else { + this.replace(null); + return false; + } + }; + + function Element(node, path, wrap, ref) { + this.node = node; + this.path = path; + this.wrap = wrap; + this.ref = ref; + } + + function Controller() { } + + // API: + // return property path array from root to current node + Controller.prototype.path = function path() { + var i, iz, j, jz, result, element; + + function addToPath(result, path) { + if (isArray(path)) { + for (j = 0, jz = path.length; j < jz; ++j) { + result.push(path[j]); + } + } else { + result.push(path); + } + } + + // root node + if (!this.__current.path) { + return null; + } + + // first node is sentinel, second node is root element + result = []; + for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { + element = this.__leavelist[i]; + addToPath(result, element.path); + } + addToPath(result, this.__current.path); + return result; + }; + + // API: + // return array of parent elements + Controller.prototype.parents = function parents() { + var i, iz, result; + + // first node is sentinel + result = []; + for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { + result.push(this.__leavelist[i].node); + } + + return result; + }; + + // API: + // return current node + Controller.prototype.current = function current() { + return this.__current.node; + }; + + Controller.prototype.__execute = function __execute(callback, element) { + var previous, result; + + result = undefined; + + previous = this.__current; + this.__current = element; + this.__state = null; + if (callback) { + result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); + } + this.__current = previous; + + return result; + }; + + // API: + // notify control skip / break + Controller.prototype.notify = function notify(flag) { + this.__state = flag; + }; + + // API: + // skip child nodes of current node + Controller.prototype.skip = function () { + this.notify(SKIP); + }; + + // API: + // break traversals + Controller.prototype['break'] = function () { + this.notify(BREAK); + }; + + // API: + // remove node + Controller.prototype.remove = function () { + this.notify(REMOVE); + }; + + Controller.prototype.__initialize = function(root, visitor) { + this.visitor = visitor; + this.root = root; + this.__worklist = []; + this.__leavelist = []; + this.__current = null; + this.__state = null; + this.__fallback = visitor.fallback === 'iteration'; + this.__keys = VisitorKeys; + if (visitor.keys) { + this.__keys = extend(objectCreate(this.__keys), visitor.keys); + } + }; + + function isNode(node) { + if (node == null) { + return false; + } + return typeof node === 'object' && typeof node.type === 'string'; + } + + function isProperty(nodeType, key) { + return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; + } + + Controller.prototype.traverse = function traverse(root, visitor) { + var worklist, + leavelist, + element, + node, + nodeType, + ret, + key, + current, + current2, + candidates, + candidate, + sentinel; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + worklist.push(new Element(root, null, null, null)); + leavelist.push(new Element(null, null, null, null)); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + ret = this.__execute(visitor.leave, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + continue; + } + + if (element.node) { + + ret = this.__execute(visitor.enter, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || ret === SKIP) { + continue; + } + + node = element.node; + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', null); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, null); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, null)); + } + } + } + } + }; + + Controller.prototype.replace = function replace(root, visitor) { + function removeElem(element) { + var i, + key, + nextElem, + parent; + + if (element.ref.remove()) { + // When the reference is an element of an array. + key = element.ref.key; + parent = element.ref.parent; + + // If removed from array, then decrease following items' keys. + i = worklist.length; + while (i--) { + nextElem = worklist[i]; + if (nextElem.ref && nextElem.ref.parent === parent) { + if (nextElem.ref.key < key) { + break; + } + --nextElem.ref.key; + } + } + } + } + + var worklist, + leavelist, + node, + nodeType, + target, + element, + current, + current2, + candidates, + candidate, + sentinel, + outer, + key; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + outer = { + root: root + }; + element = new Element(root, null, null, new Reference(outer, 'root')); + worklist.push(element); + leavelist.push(element); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + target = this.__execute(visitor.leave, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + continue; + } + + target = this.__execute(visitor.enter, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + element.node = target; + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + element.node = null; + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + + // node may be null + node = element.node; + if (!node) { + continue; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || target === SKIP) { + continue; + } + + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, new Reference(node, key))); + } + } + } + + return outer.root; + }; + + function traverse(root, visitor) { + var controller = new Controller(); + return controller.traverse(root, visitor); + } + + function replace(root, visitor) { + var controller = new Controller(); + return controller.replace(root, visitor); + } + + function extendCommentRange(comment, tokens) { + var target; + + target = upperBound(tokens, function search(token) { + return token.range[0] > comment.range[0]; + }); + + comment.extendedRange = [comment.range[0], comment.range[1]]; + + if (target !== tokens.length) { + comment.extendedRange[1] = tokens[target].range[0]; + } + + target -= 1; + if (target >= 0) { + comment.extendedRange[0] = tokens[target].range[1]; + } + + return comment; + } + + function attachComments(tree, providedComments, tokens) { + // At first, we should calculate extended comment ranges. + var comments = [], comment, len, i, cursor; + + if (!tree.range) { + throw new Error('attachComments needs range information'); + } + + // tokens array is empty, we attach comments to tree as 'leadingComments' + if (!tokens.length) { + if (providedComments.length) { + for (i = 0, len = providedComments.length; i < len; i += 1) { + comment = deepCopy(providedComments[i]); + comment.extendedRange = [0, tree.range[0]]; + comments.push(comment); + } + tree.leadingComments = comments; + } + return tree; + } + + for (i = 0, len = providedComments.length; i < len; i += 1) { + comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); + } + + // This is based on John Freeman's implementation. + cursor = 0; + traverse(tree, { + enter: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (comment.extendedRange[1] > node.range[0]) { + break; + } + + if (comment.extendedRange[1] === node.range[0]) { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + cursor = 0; + traverse(tree, { + leave: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (node.range[1] < comment.extendedRange[0]) { + break; + } + + if (node.range[1] === comment.extendedRange[0]) { + if (!node.trailingComments) { + node.trailingComments = []; + } + node.trailingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + return tree; + } + + exports.version = '1.7.1'; + exports.Syntax = Syntax; + exports.traverse = traverse; + exports.replace = replace; + exports.attachComments = attachComments; + exports.VisitorKeys = VisitorKeys; + exports.VisitorOption = VisitorOption; + exports.Controller = Controller; +})); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{}],37:[function(_dereq_,module,exports){ +module.exports = _dereq_('./javascript/diff_match_patch_uncompressed.js').diff_match_patch; + +},{"./javascript/diff_match_patch_uncompressed.js":38}],38:[function(_dereq_,module,exports){ +/** + * Diff Match and Patch + * + * Copyright 2006 Google Inc. + * http://code.google.com/p/google-diff-match-patch/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Computes the difference between two texts to create a patch. + * Applies the patch onto another text, allowing for errors. + * @author fraser@google.com (Neil Fraser) + */ + +/** + * Class containing the diff, match and patch methods. + * @constructor + */ +function diff_match_patch() { + + // Defaults. + // Redefine these in your program to override the defaults. + + // Number of seconds to map a diff before giving up (0 for infinity). + this.Diff_Timeout = 1.0; + // Cost of an empty edit operation in terms of edit characters. + this.Diff_EditCost = 4; + // At what point is no match declared (0.0 = perfection, 1.0 = very loose). + this.Match_Threshold = 0.5; + // How far to search for a match (0 = exact location, 1000+ = broad match). + // A match this many characters away from the expected location will add + // 1.0 to the score (0.0 is a perfect match). + this.Match_Distance = 1000; + // When deleting a large block of text (over ~64 characters), how close do + // the contents have to be to match the expected contents. (0.0 = perfection, + // 1.0 = very loose). Note that Match_Threshold controls how closely the + // end points of a delete need to match. + this.Patch_DeleteThreshold = 0.5; + // Chunk size for context length. + this.Patch_Margin = 4; + + // The number of bits in an int. + this.Match_MaxBits = 32; +} + + +// DIFF FUNCTIONS + + +/** + * The data structure representing a diff is an array of tuples: + * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']] + * which means: delete 'Hello', add 'Goodbye' and keep ' world.' + */ +var DIFF_DELETE = -1; +var DIFF_INSERT = 1; +var DIFF_EQUAL = 0; + +/** @typedef {{0: number, 1: string}} */ +diff_match_patch.Diff; + + +/** + * Find the differences between two texts. Simplifies the problem by stripping + * any common prefix or suffix off the texts before diffing. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {boolean=} opt_checklines Optional speedup flag. If present and false, + * then don't run a line-level diff first to identify the changed areas. + * Defaults to true, which does a faster, slightly less optimal diff. + * @param {number} opt_deadline Optional time when the diff should be complete + * by. Used internally for recursive calls. Users should set DiffTimeout + * instead. + * @return {!Array.} Array of diff tuples. + */ +diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines, + opt_deadline) { + // Set a deadline by which time the diff must be complete. + if (typeof opt_deadline == 'undefined') { + if (this.Diff_Timeout <= 0) { + opt_deadline = Number.MAX_VALUE; + } else { + opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000; + } + } + var deadline = opt_deadline; + + // Check for null inputs. + if (text1 == null || text2 == null) { + throw new Error('Null input. (diff_main)'); + } + + // Check for equality (speedup). + if (text1 == text2) { + if (text1) { + return [[DIFF_EQUAL, text1]]; + } + return []; + } + + if (typeof opt_checklines == 'undefined') { + opt_checklines = true; + } + var checklines = opt_checklines; + + // Trim off common prefix (speedup). + var commonlength = this.diff_commonPrefix(text1, text2); + var commonprefix = text1.substring(0, commonlength); + text1 = text1.substring(commonlength); + text2 = text2.substring(commonlength); + + // Trim off common suffix (speedup). + commonlength = this.diff_commonSuffix(text1, text2); + var commonsuffix = text1.substring(text1.length - commonlength); + text1 = text1.substring(0, text1.length - commonlength); + text2 = text2.substring(0, text2.length - commonlength); + + // Compute the diff on the middle block. + var diffs = this.diff_compute_(text1, text2, checklines, deadline); + + // Restore the prefix and suffix. + if (commonprefix) { + diffs.unshift([DIFF_EQUAL, commonprefix]); + } + if (commonsuffix) { + diffs.push([DIFF_EQUAL, commonsuffix]); + } + this.diff_cleanupMerge(diffs); + return diffs; +}; + + +/** + * Find the differences between two texts. Assumes that the texts do not + * have any common prefix or suffix. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {boolean} checklines Speedup flag. If false, then don't run a + * line-level diff first to identify the changed areas. + * If true, then run a faster, slightly less optimal diff. + * @param {number} deadline Time when the diff should be complete by. + * @return {!Array.} Array of diff tuples. + * @private + */ +diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines, + deadline) { + var diffs; + + if (!text1) { + // Just add some text (speedup). + return [[DIFF_INSERT, text2]]; + } + + if (!text2) { + // Just delete some text (speedup). + return [[DIFF_DELETE, text1]]; + } + + var longtext = text1.length > text2.length ? text1 : text2; + var shorttext = text1.length > text2.length ? text2 : text1; + var i = longtext.indexOf(shorttext); + if (i != -1) { + // Shorter text is inside the longer text (speedup). + diffs = [[DIFF_INSERT, longtext.substring(0, i)], + [DIFF_EQUAL, shorttext], + [DIFF_INSERT, longtext.substring(i + shorttext.length)]]; + // Swap insertions for deletions if diff is reversed. + if (text1.length > text2.length) { + diffs[0][0] = diffs[2][0] = DIFF_DELETE; + } + return diffs; + } + + if (shorttext.length == 1) { + // Single character string. + // After the previous speedup, the character can't be an equality. + return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; + } + + // Check to see if the problem can be split in two. + var hm = this.diff_halfMatch_(text1, text2); + if (hm) { + // A half-match was found, sort out the return data. + var text1_a = hm[0]; + var text1_b = hm[1]; + var text2_a = hm[2]; + var text2_b = hm[3]; + var mid_common = hm[4]; + // Send both pairs off for separate processing. + var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline); + var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline); + // Merge the results. + return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b); + } + + if (checklines && text1.length > 100 && text2.length > 100) { + return this.diff_lineMode_(text1, text2, deadline); + } + + return this.diff_bisect_(text1, text2, deadline); +}; + + +/** + * Do a quick line-level diff on both strings, then rediff the parts for + * greater accuracy. + * This speedup can produce non-minimal diffs. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} deadline Time when the diff should be complete by. + * @return {!Array.} Array of diff tuples. + * @private + */ +diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) { + // Scan the text on a line-by-line basis first. + var a = this.diff_linesToChars_(text1, text2); + text1 = a.chars1; + text2 = a.chars2; + var linearray = a.lineArray; + + var diffs = this.diff_main(text1, text2, false, deadline); + + // Convert the diff back to original text. + this.diff_charsToLines_(diffs, linearray); + // Eliminate freak matches (e.g. blank lines) + this.diff_cleanupSemantic(diffs); + + // Rediff any replacement blocks, this time character-by-character. + // Add a dummy entry at the end. + diffs.push([DIFF_EQUAL, '']); + var pointer = 0; + var count_delete = 0; + var count_insert = 0; + var text_delete = ''; + var text_insert = ''; + while (pointer < diffs.length) { + switch (diffs[pointer][0]) { + case DIFF_INSERT: + count_insert++; + text_insert += diffs[pointer][1]; + break; + case DIFF_DELETE: + count_delete++; + text_delete += diffs[pointer][1]; + break; + case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (count_delete >= 1 && count_insert >= 1) { + // Delete the offending records and add the merged ones. + diffs.splice(pointer - count_delete - count_insert, + count_delete + count_insert); + pointer = pointer - count_delete - count_insert; + var a = this.diff_main(text_delete, text_insert, false, deadline); + for (var j = a.length - 1; j >= 0; j--) { + diffs.splice(pointer, 0, a[j]); + } + pointer = pointer + a.length; + } + count_insert = 0; + count_delete = 0; + text_delete = ''; + text_insert = ''; + break; + } + pointer++; + } + diffs.pop(); // Remove the dummy entry at the end. + + return diffs; +}; + + +/** + * Find the 'middle snake' of a diff, split the problem in two + * and return the recursively constructed diff. + * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} deadline Time at which to bail if not yet complete. + * @return {!Array.} Array of diff tuples. + * @private + */ +diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) { + // Cache the text lengths to prevent multiple calls. + var text1_length = text1.length; + var text2_length = text2.length; + var max_d = Math.ceil((text1_length + text2_length) / 2); + var v_offset = max_d; + var v_length = 2 * max_d; + var v1 = new Array(v_length); + var v2 = new Array(v_length); + // Setting all elements to -1 is faster in Chrome & Firefox than mixing + // integers and undefined. + for (var x = 0; x < v_length; x++) { + v1[x] = -1; + v2[x] = -1; + } + v1[v_offset + 1] = 0; + v2[v_offset + 1] = 0; + var delta = text1_length - text2_length; + // If the total number of characters is odd, then the front path will collide + // with the reverse path. + var front = (delta % 2 != 0); + // Offsets for start and end of k loop. + // Prevents mapping of space beyond the grid. + var k1start = 0; + var k1end = 0; + var k2start = 0; + var k2end = 0; + for (var d = 0; d < max_d; d++) { + // Bail out if deadline is reached. + if ((new Date()).getTime() > deadline) { + break; + } + + // Walk the front path one step. + for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { + var k1_offset = v_offset + k1; + var x1; + if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) { + x1 = v1[k1_offset + 1]; + } else { + x1 = v1[k1_offset - 1] + 1; + } + var y1 = x1 - k1; + while (x1 < text1_length && y1 < text2_length && + text1.charAt(x1) == text2.charAt(y1)) { + x1++; + y1++; + } + v1[k1_offset] = x1; + if (x1 > text1_length) { + // Ran off the right of the graph. + k1end += 2; + } else if (y1 > text2_length) { + // Ran off the bottom of the graph. + k1start += 2; + } else if (front) { + var k2_offset = v_offset + delta - k1; + if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) { + // Mirror x2 onto top-left coordinate system. + var x2 = text1_length - v2[k2_offset]; + if (x1 >= x2) { + // Overlap detected. + return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); + } + } + } + } + + // Walk the reverse path one step. + for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { + var k2_offset = v_offset + k2; + var x2; + if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) { + x2 = v2[k2_offset + 1]; + } else { + x2 = v2[k2_offset - 1] + 1; + } + var y2 = x2 - k2; + while (x2 < text1_length && y2 < text2_length && + text1.charAt(text1_length - x2 - 1) == + text2.charAt(text2_length - y2 - 1)) { + x2++; + y2++; + } + v2[k2_offset] = x2; + if (x2 > text1_length) { + // Ran off the left of the graph. + k2end += 2; + } else if (y2 > text2_length) { + // Ran off the top of the graph. + k2start += 2; + } else if (!front) { + var k1_offset = v_offset + delta - k2; + if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) { + var x1 = v1[k1_offset]; + var y1 = v_offset + x1 - k1_offset; + // Mirror x2 onto top-left coordinate system. + x2 = text1_length - x2; + if (x1 >= x2) { + // Overlap detected. + return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); + } + } + } + } + } + // Diff took too long and hit the deadline or + // number of diffs equals number of characters, no commonality at all. + return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; +}; + + +/** + * Given the location of the 'middle snake', split the diff in two parts + * and recurse. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} x Index of split point in text1. + * @param {number} y Index of split point in text2. + * @param {number} deadline Time at which to bail if not yet complete. + * @return {!Array.} Array of diff tuples. + * @private + */ +diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y, + deadline) { + var text1a = text1.substring(0, x); + var text2a = text2.substring(0, y); + var text1b = text1.substring(x); + var text2b = text2.substring(y); + + // Compute both diffs serially. + var diffs = this.diff_main(text1a, text2a, false, deadline); + var diffsb = this.diff_main(text1b, text2b, false, deadline); + + return diffs.concat(diffsb); +}; + + +/** + * Split two texts into an array of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {{chars1: string, chars2: string, lineArray: !Array.}} + * An object containing the encoded text1, the encoded text2 and + * the array of unique strings. + * The zeroth element of the array of unique strings is intentionally blank. + * @private + */ +diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) { + var lineArray = []; // e.g. lineArray[4] == 'Hello\n' + var lineHash = {}; // e.g. lineHash['Hello\n'] == 4 + + // '\x00' is a valid character, but various debuggers don't like it. + // So we'll insert a junk entry to avoid generating a null character. + lineArray[0] = ''; + + /** + * Split a text into an array of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * Modifies linearray and linehash through being a closure. + * @param {string} text String to encode. + * @return {string} Encoded string. + * @private + */ + function diff_linesToCharsMunge_(text) { + var chars = ''; + // Walk the text, pulling out a substring for each line. + // text.split('\n') would would temporarily double our memory footprint. + // Modifying text would create many large strings to garbage collect. + var lineStart = 0; + var lineEnd = -1; + // Keeping our own length variable is faster than looking it up. + var lineArrayLength = lineArray.length; + while (lineEnd < text.length - 1) { + lineEnd = text.indexOf('\n', lineStart); + if (lineEnd == -1) { + lineEnd = text.length - 1; + } + var line = text.substring(lineStart, lineEnd + 1); + lineStart = lineEnd + 1; + + if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : + (lineHash[line] !== undefined)) { + chars += String.fromCharCode(lineHash[line]); + } else { + chars += String.fromCharCode(lineArrayLength); + lineHash[line] = lineArrayLength; + lineArray[lineArrayLength++] = line; + } + } + return chars; + } + + var chars1 = diff_linesToCharsMunge_(text1); + var chars2 = diff_linesToCharsMunge_(text2); + return {chars1: chars1, chars2: chars2, lineArray: lineArray}; +}; + + +/** + * Rehydrate the text in a diff from a string of line hashes to real lines of + * text. + * @param {!Array.} diffs Array of diff tuples. + * @param {!Array.} lineArray Array of unique strings. + * @private + */ +diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) { + for (var x = 0; x < diffs.length; x++) { + var chars = diffs[x][1]; + var text = []; + for (var y = 0; y < chars.length; y++) { + text[y] = lineArray[chars.charCodeAt(y)]; + } + diffs[x][1] = text.join(''); + } +}; + + +/** + * Determine the common prefix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the start of each + * string. + */ +diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) { + // Quick check for common null cases. + if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + var pointermin = 0; + var pointermax = Math.min(text1.length, text2.length); + var pointermid = pointermax; + var pointerstart = 0; + while (pointermin < pointermid) { + if (text1.substring(pointerstart, pointermid) == + text2.substring(pointerstart, pointermid)) { + pointermin = pointermid; + pointerstart = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); + } + return pointermid; +}; + + +/** + * Determine the common suffix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the end of each string. + */ +diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) { + // Quick check for common null cases. + if (!text1 || !text2 || + text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + var pointermin = 0; + var pointermax = Math.min(text1.length, text2.length); + var pointermid = pointermax; + var pointerend = 0; + while (pointermin < pointermid) { + if (text1.substring(text1.length - pointermid, text1.length - pointerend) == + text2.substring(text2.length - pointermid, text2.length - pointerend)) { + pointermin = pointermid; + pointerend = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); + } + return pointermid; +}; + + +/** + * Determine if the suffix of one string is the prefix of another. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the end of the first + * string and the start of the second string. + * @private + */ +diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) { + // Cache the text lengths to prevent multiple calls. + var text1_length = text1.length; + var text2_length = text2.length; + // Eliminate the null case. + if (text1_length == 0 || text2_length == 0) { + return 0; + } + // Truncate the longer string. + if (text1_length > text2_length) { + text1 = text1.substring(text1_length - text2_length); + } else if (text1_length < text2_length) { + text2 = text2.substring(0, text1_length); + } + var text_length = Math.min(text1_length, text2_length); + // Quick check for the worst case. + if (text1 == text2) { + return text_length; + } + + // Start by looking for a single character match + // and increase length until no match is found. + // Performance analysis: http://neil.fraser.name/news/2010/11/04/ + var best = 0; + var length = 1; + while (true) { + var pattern = text1.substring(text_length - length); + var found = text2.indexOf(pattern); + if (found == -1) { + return best; + } + length += found; + if (found == 0 || text1.substring(text_length - length) == + text2.substring(0, length)) { + best = length; + length++; + } + } +}; + + +/** + * Do the two texts share a substring which is at least half the length of the + * longer text? + * This speedup can produce non-minimal diffs. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {Array.} Five element Array, containing the prefix of + * text1, the suffix of text1, the prefix of text2, the suffix of + * text2 and the common middle. Or null if there was no match. + * @private + */ +diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) { + if (this.Diff_Timeout <= 0) { + // Don't risk returning a non-optimal diff if we have unlimited time. + return null; + } + var longtext = text1.length > text2.length ? text1 : text2; + var shorttext = text1.length > text2.length ? text2 : text1; + if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { + return null; // Pointless. + } + var dmp = this; // 'this' becomes 'window' in a closure. + + /** + * Does a substring of shorttext exist within longtext such that the substring + * is at least half the length of longtext? + * Closure, but does not reference any external variables. + * @param {string} longtext Longer string. + * @param {string} shorttext Shorter string. + * @param {number} i Start index of quarter length substring within longtext. + * @return {Array.} Five element Array, containing the prefix of + * longtext, the suffix of longtext, the prefix of shorttext, the suffix + * of shorttext and the common middle. Or null if there was no match. + * @private + */ + function diff_halfMatchI_(longtext, shorttext, i) { + // Start with a 1/4 length substring at position i as a seed. + var seed = longtext.substring(i, i + Math.floor(longtext.length / 4)); + var j = -1; + var best_common = ''; + var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b; + while ((j = shorttext.indexOf(seed, j + 1)) != -1) { + var prefixLength = dmp.diff_commonPrefix(longtext.substring(i), + shorttext.substring(j)); + var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i), + shorttext.substring(0, j)); + if (best_common.length < suffixLength + prefixLength) { + best_common = shorttext.substring(j - suffixLength, j) + + shorttext.substring(j, j + prefixLength); + best_longtext_a = longtext.substring(0, i - suffixLength); + best_longtext_b = longtext.substring(i + prefixLength); + best_shorttext_a = shorttext.substring(0, j - suffixLength); + best_shorttext_b = shorttext.substring(j + prefixLength); + } + } + if (best_common.length * 2 >= longtext.length) { + return [best_longtext_a, best_longtext_b, + best_shorttext_a, best_shorttext_b, best_common]; + } else { + return null; + } + } + + // First check if the second quarter is the seed for a half-match. + var hm1 = diff_halfMatchI_(longtext, shorttext, + Math.ceil(longtext.length / 4)); + // Check again based on the third quarter. + var hm2 = diff_halfMatchI_(longtext, shorttext, + Math.ceil(longtext.length / 2)); + var hm; + if (!hm1 && !hm2) { + return null; + } else if (!hm2) { + hm = hm1; + } else if (!hm1) { + hm = hm2; + } else { + // Both matched. Select the longest. + hm = hm1[4].length > hm2[4].length ? hm1 : hm2; + } + + // A half-match was found, sort out the return data. + var text1_a, text1_b, text2_a, text2_b; + if (text1.length > text2.length) { + text1_a = hm[0]; + text1_b = hm[1]; + text2_a = hm[2]; + text2_b = hm[3]; + } else { + text2_a = hm[0]; + text2_b = hm[1]; + text1_a = hm[2]; + text1_b = hm[3]; + } + var mid_common = hm[4]; + return [text1_a, text1_b, text2_a, text2_b, mid_common]; +}; + + +/** + * Reduce the number of edits by eliminating semantically trivial equalities. + * @param {!Array.} diffs Array of diff tuples. + */ +diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) { + var changes = false; + var equalities = []; // Stack of indices where equalities are found. + var equalitiesLength = 0; // Keeping our own length var is faster in JS. + /** @type {?string} */ + var lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] + var pointer = 0; // Index of current position. + // Number of characters that changed prior to the equality. + var length_insertions1 = 0; + var length_deletions1 = 0; + // Number of characters that changed after the equality. + var length_insertions2 = 0; + var length_deletions2 = 0; + while (pointer < diffs.length) { + if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. + equalities[equalitiesLength++] = pointer; + length_insertions1 = length_insertions2; + length_deletions1 = length_deletions2; + length_insertions2 = 0; + length_deletions2 = 0; + lastequality = diffs[pointer][1]; + } else { // An insertion or deletion. + if (diffs[pointer][0] == DIFF_INSERT) { + length_insertions2 += diffs[pointer][1].length; + } else { + length_deletions2 += diffs[pointer][1].length; + } + // Eliminate an equality that is smaller or equal to the edits on both + // sides of it. + if (lastequality && (lastequality.length <= + Math.max(length_insertions1, length_deletions1)) && + (lastequality.length <= Math.max(length_insertions2, + length_deletions2))) { + // Duplicate record. + diffs.splice(equalities[equalitiesLength - 1], 0, + [DIFF_DELETE, lastequality]); + // Change second copy to insert. + diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; + // Throw away the equality we just deleted. + equalitiesLength--; + // Throw away the previous equality (it needs to be reevaluated). + equalitiesLength--; + pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; + length_insertions1 = 0; // Reset the counters. + length_deletions1 = 0; + length_insertions2 = 0; + length_deletions2 = 0; + lastequality = null; + changes = true; + } + } + pointer++; + } + + // Normalize the diff. + if (changes) { + this.diff_cleanupMerge(diffs); + } + this.diff_cleanupSemanticLossless(diffs); + + // Find any overlaps between deletions and insertions. + // e.g: abcxxxxxxdef + // -> abcxxxdef + // e.g: xxxabcdefxxx + // -> defxxxabc + // Only extract an overlap if it is as big as the edit ahead or behind it. + pointer = 1; + while (pointer < diffs.length) { + if (diffs[pointer - 1][0] == DIFF_DELETE && + diffs[pointer][0] == DIFF_INSERT) { + var deletion = diffs[pointer - 1][1]; + var insertion = diffs[pointer][1]; + var overlap_length1 = this.diff_commonOverlap_(deletion, insertion); + var overlap_length2 = this.diff_commonOverlap_(insertion, deletion); + if (overlap_length1 >= overlap_length2) { + if (overlap_length1 >= deletion.length / 2 || + overlap_length1 >= insertion.length / 2) { + // Overlap found. Insert an equality and trim the surrounding edits. + diffs.splice(pointer, 0, + [DIFF_EQUAL, insertion.substring(0, overlap_length1)]); + diffs[pointer - 1][1] = + deletion.substring(0, deletion.length - overlap_length1); + diffs[pointer + 1][1] = insertion.substring(overlap_length1); + pointer++; + } + } else { + if (overlap_length2 >= deletion.length / 2 || + overlap_length2 >= insertion.length / 2) { + // Reverse overlap found. + // Insert an equality and swap and trim the surrounding edits. + diffs.splice(pointer, 0, + [DIFF_EQUAL, deletion.substring(0, overlap_length2)]); + diffs[pointer - 1][0] = DIFF_INSERT; + diffs[pointer - 1][1] = + insertion.substring(0, insertion.length - overlap_length2); + diffs[pointer + 1][0] = DIFF_DELETE; + diffs[pointer + 1][1] = + deletion.substring(overlap_length2); + pointer++; + } + } + pointer++; + } + pointer++; + } +}; + + +/** + * Look for single edits surrounded on both sides by equalities + * which can be shifted sideways to align the edit to a word boundary. + * e.g: The cat came. -> The cat came. + * @param {!Array.} diffs Array of diff tuples. + */ +diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) { + /** + * Given two strings, compute a score representing whether the internal + * boundary falls on logical boundaries. + * Scores range from 6 (best) to 0 (worst). + * Closure, but does not reference any external variables. + * @param {string} one First string. + * @param {string} two Second string. + * @return {number} The score. + * @private + */ + function diff_cleanupSemanticScore_(one, two) { + if (!one || !two) { + // Edges are the best. + return 6; + } + + // Each port of this function behaves slightly differently due to + // subtle differences in each language's definition of things like + // 'whitespace'. Since this function's purpose is largely cosmetic, + // the choice has been made to use each language's native features + // rather than force total conformity. + var char1 = one.charAt(one.length - 1); + var char2 = two.charAt(0); + var nonAlphaNumeric1 = char1.match(diff_match_patch.nonAlphaNumericRegex_); + var nonAlphaNumeric2 = char2.match(diff_match_patch.nonAlphaNumericRegex_); + var whitespace1 = nonAlphaNumeric1 && + char1.match(diff_match_patch.whitespaceRegex_); + var whitespace2 = nonAlphaNumeric2 && + char2.match(diff_match_patch.whitespaceRegex_); + var lineBreak1 = whitespace1 && + char1.match(diff_match_patch.linebreakRegex_); + var lineBreak2 = whitespace2 && + char2.match(diff_match_patch.linebreakRegex_); + var blankLine1 = lineBreak1 && + one.match(diff_match_patch.blanklineEndRegex_); + var blankLine2 = lineBreak2 && + two.match(diff_match_patch.blanklineStartRegex_); + + if (blankLine1 || blankLine2) { + // Five points for blank lines. + return 5; + } else if (lineBreak1 || lineBreak2) { + // Four points for line breaks. + return 4; + } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) { + // Three points for end of sentences. + return 3; + } else if (whitespace1 || whitespace2) { + // Two points for whitespace. + return 2; + } else if (nonAlphaNumeric1 || nonAlphaNumeric2) { + // One point for non-alphanumeric. + return 1; + } + return 0; + } + + var pointer = 1; + // Intentionally ignore the first and last element (don't need checking). + while (pointer < diffs.length - 1) { + if (diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL) { + // This is a single edit surrounded by equalities. + var equality1 = diffs[pointer - 1][1]; + var edit = diffs[pointer][1]; + var equality2 = diffs[pointer + 1][1]; + + // First, shift the edit as far left as possible. + var commonOffset = this.diff_commonSuffix(equality1, edit); + if (commonOffset) { + var commonString = edit.substring(edit.length - commonOffset); + equality1 = equality1.substring(0, equality1.length - commonOffset); + edit = commonString + edit.substring(0, edit.length - commonOffset); + equality2 = commonString + equality2; + } + + // Second, step character by character right, looking for the best fit. + var bestEquality1 = equality1; + var bestEdit = edit; + var bestEquality2 = equality2; + var bestScore = diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); + while (edit.charAt(0) === equality2.charAt(0)) { + equality1 += edit.charAt(0); + edit = edit.substring(1) + equality2.charAt(0); + equality2 = equality2.substring(1); + var score = diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); + // The >= encourages trailing rather than leading whitespace on edits. + if (score >= bestScore) { + bestScore = score; + bestEquality1 = equality1; + bestEdit = edit; + bestEquality2 = equality2; + } + } + + if (diffs[pointer - 1][1] != bestEquality1) { + // We have an improvement, save it back to the diff. + if (bestEquality1) { + diffs[pointer - 1][1] = bestEquality1; + } else { + diffs.splice(pointer - 1, 1); + pointer--; + } + diffs[pointer][1] = bestEdit; + if (bestEquality2) { + diffs[pointer + 1][1] = bestEquality2; + } else { + diffs.splice(pointer + 1, 1); + pointer--; + } + } + } + pointer++; + } +}; + +// Define some regex patterns for matching boundaries. +diff_match_patch.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/; +diff_match_patch.whitespaceRegex_ = /\s/; +diff_match_patch.linebreakRegex_ = /[\r\n]/; +diff_match_patch.blanklineEndRegex_ = /\n\r?\n$/; +diff_match_patch.blanklineStartRegex_ = /^\r?\n\r?\n/; + +/** + * Reduce the number of edits by eliminating operationally trivial equalities. + * @param {!Array.} diffs Array of diff tuples. + */ +diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) { + var changes = false; + var equalities = []; // Stack of indices where equalities are found. + var equalitiesLength = 0; // Keeping our own length var is faster in JS. + /** @type {?string} */ + var lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] + var pointer = 0; // Index of current position. + // Is there an insertion operation before the last equality. + var pre_ins = false; + // Is there a deletion operation before the last equality. + var pre_del = false; + // Is there an insertion operation after the last equality. + var post_ins = false; + // Is there a deletion operation after the last equality. + var post_del = false; + while (pointer < diffs.length) { + if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. + if (diffs[pointer][1].length < this.Diff_EditCost && + (post_ins || post_del)) { + // Candidate found. + equalities[equalitiesLength++] = pointer; + pre_ins = post_ins; + pre_del = post_del; + lastequality = diffs[pointer][1]; + } else { + // Not a candidate, and can never become one. + equalitiesLength = 0; + lastequality = null; + } + post_ins = post_del = false; + } else { // An insertion or deletion. + if (diffs[pointer][0] == DIFF_DELETE) { + post_del = true; + } else { + post_ins = true; + } + /* + * Five types to be split: + * ABXYCD + * AXCD + * ABXC + * AXCD + * ABXC + */ + if (lastequality && ((pre_ins && pre_del && post_ins && post_del) || + ((lastequality.length < this.Diff_EditCost / 2) && + (pre_ins + pre_del + post_ins + post_del) == 3))) { + // Duplicate record. + diffs.splice(equalities[equalitiesLength - 1], 0, + [DIFF_DELETE, lastequality]); + // Change second copy to insert. + diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; + equalitiesLength--; // Throw away the equality we just deleted; + lastequality = null; + if (pre_ins && pre_del) { + // No changes made which could affect previous entry, keep going. + post_ins = post_del = true; + equalitiesLength = 0; + } else { + equalitiesLength--; // Throw away the previous equality. + pointer = equalitiesLength > 0 ? + equalities[equalitiesLength - 1] : -1; + post_ins = post_del = false; + } + changes = true; + } + } + pointer++; + } + + if (changes) { + this.diff_cleanupMerge(diffs); + } +}; + + +/** + * Reorder and merge like edit sections. Merge equalities. + * Any edit section can move as long as it doesn't cross an equality. + * @param {!Array.} diffs Array of diff tuples. + */ +diff_match_patch.prototype.diff_cleanupMerge = function(diffs) { + diffs.push([DIFF_EQUAL, '']); // Add a dummy entry at the end. + var pointer = 0; + var count_delete = 0; + var count_insert = 0; + var text_delete = ''; + var text_insert = ''; + var commonlength; + while (pointer < diffs.length) { + switch (diffs[pointer][0]) { + case DIFF_INSERT: + count_insert++; + text_insert += diffs[pointer][1]; + pointer++; + break; + case DIFF_DELETE: + count_delete++; + text_delete += diffs[pointer][1]; + pointer++; + break; + case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (count_delete + count_insert > 1) { + if (count_delete !== 0 && count_insert !== 0) { + // Factor out any common prefixies. + commonlength = this.diff_commonPrefix(text_insert, text_delete); + if (commonlength !== 0) { + if ((pointer - count_delete - count_insert) > 0 && + diffs[pointer - count_delete - count_insert - 1][0] == + DIFF_EQUAL) { + diffs[pointer - count_delete - count_insert - 1][1] += + text_insert.substring(0, commonlength); + } else { + diffs.splice(0, 0, [DIFF_EQUAL, + text_insert.substring(0, commonlength)]); + pointer++; + } + text_insert = text_insert.substring(commonlength); + text_delete = text_delete.substring(commonlength); + } + // Factor out any common suffixies. + commonlength = this.diff_commonSuffix(text_insert, text_delete); + if (commonlength !== 0) { + diffs[pointer][1] = text_insert.substring(text_insert.length - + commonlength) + diffs[pointer][1]; + text_insert = text_insert.substring(0, text_insert.length - + commonlength); + text_delete = text_delete.substring(0, text_delete.length - + commonlength); + } + } + // Delete the offending records and add the merged ones. + if (count_delete === 0) { + diffs.splice(pointer - count_insert, + count_delete + count_insert, [DIFF_INSERT, text_insert]); + } else if (count_insert === 0) { + diffs.splice(pointer - count_delete, + count_delete + count_insert, [DIFF_DELETE, text_delete]); + } else { + diffs.splice(pointer - count_delete - count_insert, + count_delete + count_insert, [DIFF_DELETE, text_delete], + [DIFF_INSERT, text_insert]); + } + pointer = pointer - count_delete - count_insert + + (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1; + } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) { + // Merge this equality with the previous one. + diffs[pointer - 1][1] += diffs[pointer][1]; + diffs.splice(pointer, 1); + } else { + pointer++; + } + count_insert = 0; + count_delete = 0; + text_delete = ''; + text_insert = ''; + break; + } + } + if (diffs[diffs.length - 1][1] === '') { + diffs.pop(); // Remove the dummy entry at the end. + } + + // Second pass: look for single edits surrounded on both sides by equalities + // which can be shifted sideways to eliminate an equality. + // e.g: ABAC -> ABAC + var changes = false; + pointer = 1; + // Intentionally ignore the first and last element (don't need checking). + while (pointer < diffs.length - 1) { + if (diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL) { + // This is a single edit surrounded by equalities. + if (diffs[pointer][1].substring(diffs[pointer][1].length - + diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { + // Shift the edit over the previous equality. + diffs[pointer][1] = diffs[pointer - 1][1] + + diffs[pointer][1].substring(0, diffs[pointer][1].length - + diffs[pointer - 1][1].length); + diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; + diffs.splice(pointer - 1, 1); + changes = true; + } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == + diffs[pointer + 1][1]) { + // Shift the edit over the next equality. + diffs[pointer - 1][1] += diffs[pointer + 1][1]; + diffs[pointer][1] = + diffs[pointer][1].substring(diffs[pointer + 1][1].length) + + diffs[pointer + 1][1]; + diffs.splice(pointer + 1, 1); + changes = true; + } + } + pointer++; + } + // If shifts were made, the diff needs reordering and another shift sweep. + if (changes) { + this.diff_cleanupMerge(diffs); + } +}; + + +/** + * loc is a location in text1, compute and return the equivalent location in + * text2. + * e.g. 'The cat' vs 'The big cat', 1->1, 5->8 + * @param {!Array.} diffs Array of diff tuples. + * @param {number} loc Location within text1. + * @return {number} Location within text2. + */ +diff_match_patch.prototype.diff_xIndex = function(diffs, loc) { + var chars1 = 0; + var chars2 = 0; + var last_chars1 = 0; + var last_chars2 = 0; + var x; + for (x = 0; x < diffs.length; x++) { + if (diffs[x][0] !== DIFF_INSERT) { // Equality or deletion. + chars1 += diffs[x][1].length; + } + if (diffs[x][0] !== DIFF_DELETE) { // Equality or insertion. + chars2 += diffs[x][1].length; + } + if (chars1 > loc) { // Overshot the location. + break; + } + last_chars1 = chars1; + last_chars2 = chars2; + } + // Was the location was deleted? + if (diffs.length != x && diffs[x][0] === DIFF_DELETE) { + return last_chars2; + } + // Add the remaining character length. + return last_chars2 + (loc - last_chars1); +}; + + +/** + * Convert a diff array into a pretty HTML report. + * @param {!Array.} diffs Array of diff tuples. + * @return {string} HTML representation. + */ +diff_match_patch.prototype.diff_prettyHtml = function(diffs) { + var html = []; + var pattern_amp = /&/g; + var pattern_lt = //g; + var pattern_para = /\n/g; + for (var x = 0; x < diffs.length; x++) { + var op = diffs[x][0]; // Operation (insert, delete, equal) + var data = diffs[x][1]; // Text of change. + var text = data.replace(pattern_amp, '&').replace(pattern_lt, '<') + .replace(pattern_gt, '>').replace(pattern_para, '¶
'); + switch (op) { + case DIFF_INSERT: + html[x] = '' + text + ''; + break; + case DIFF_DELETE: + html[x] = '' + text + ''; + break; + case DIFF_EQUAL: + html[x] = '' + text + ''; + break; + } + } + return html.join(''); +}; + + +/** + * Compute and return the source text (all equalities and deletions). + * @param {!Array.} diffs Array of diff tuples. + * @return {string} Source text. + */ +diff_match_patch.prototype.diff_text1 = function(diffs) { + var text = []; + for (var x = 0; x < diffs.length; x++) { + if (diffs[x][0] !== DIFF_INSERT) { + text[x] = diffs[x][1]; + } + } + return text.join(''); +}; + + +/** + * Compute and return the destination text (all equalities and insertions). + * @param {!Array.} diffs Array of diff tuples. + * @return {string} Destination text. + */ +diff_match_patch.prototype.diff_text2 = function(diffs) { + var text = []; + for (var x = 0; x < diffs.length; x++) { + if (diffs[x][0] !== DIFF_DELETE) { + text[x] = diffs[x][1]; + } + } + return text.join(''); +}; + + +/** + * Compute the Levenshtein distance; the number of inserted, deleted or + * substituted characters. + * @param {!Array.} diffs Array of diff tuples. + * @return {number} Number of changes. + */ +diff_match_patch.prototype.diff_levenshtein = function(diffs) { + var levenshtein = 0; + var insertions = 0; + var deletions = 0; + for (var x = 0; x < diffs.length; x++) { + var op = diffs[x][0]; + var data = diffs[x][1]; + switch (op) { + case DIFF_INSERT: + insertions += data.length; + break; + case DIFF_DELETE: + deletions += data.length; + break; + case DIFF_EQUAL: + // A deletion and an insertion is one substitution. + levenshtein += Math.max(insertions, deletions); + insertions = 0; + deletions = 0; + break; + } + } + levenshtein += Math.max(insertions, deletions); + return levenshtein; +}; + + +/** + * Crush the diff into an encoded string which describes the operations + * required to transform text1 into text2. + * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'. + * Operations are tab-separated. Inserted text is escaped using %xx notation. + * @param {!Array.} diffs Array of diff tuples. + * @return {string} Delta text. + */ +diff_match_patch.prototype.diff_toDelta = function(diffs) { + var text = []; + for (var x = 0; x < diffs.length; x++) { + switch (diffs[x][0]) { + case DIFF_INSERT: + text[x] = '+' + encodeURI(diffs[x][1]); + break; + case DIFF_DELETE: + text[x] = '-' + diffs[x][1].length; + break; + case DIFF_EQUAL: + text[x] = '=' + diffs[x][1].length; + break; + } + } + return text.join('\t').replace(/%20/g, ' '); +}; + + +/** + * Given the original text1, and an encoded string which describes the + * operations required to transform text1 into text2, compute the full diff. + * @param {string} text1 Source string for the diff. + * @param {string} delta Delta text. + * @return {!Array.} Array of diff tuples. + * @throws {!Error} If invalid input. + */ +diff_match_patch.prototype.diff_fromDelta = function(text1, delta) { + var diffs = []; + var diffsLength = 0; // Keeping our own length var is faster in JS. + var pointer = 0; // Cursor in text1 + var tokens = delta.split(/\t/g); + for (var x = 0; x < tokens.length; x++) { + // Each token begins with a one character parameter which specifies the + // operation of this token (delete, insert, equality). + var param = tokens[x].substring(1); + switch (tokens[x].charAt(0)) { + case '+': + try { + diffs[diffsLength++] = [DIFF_INSERT, decodeURI(param)]; + } catch (ex) { + // Malformed URI sequence. + throw new Error('Illegal escape in diff_fromDelta: ' + param); + } + break; + case '-': + // Fall through. + case '=': + var n = parseInt(param, 10); + if (isNaN(n) || n < 0) { + throw new Error('Invalid number in diff_fromDelta: ' + param); + } + var text = text1.substring(pointer, pointer += n); + if (tokens[x].charAt(0) == '=') { + diffs[diffsLength++] = [DIFF_EQUAL, text]; + } else { + diffs[diffsLength++] = [DIFF_DELETE, text]; + } + break; + default: + // Blank tokens are ok (from a trailing \t). + // Anything else is an error. + if (tokens[x]) { + throw new Error('Invalid diff operation in diff_fromDelta: ' + + tokens[x]); + } + } + } + if (pointer != text1.length) { + throw new Error('Delta length (' + pointer + + ') does not equal source text length (' + text1.length + ').'); + } + return diffs; +}; + + +// MATCH FUNCTIONS + + +/** + * Locate the best instance of 'pattern' in 'text' near 'loc'. + * @param {string} text The text to search. + * @param {string} pattern The pattern to search for. + * @param {number} loc The location to search around. + * @return {number} Best match index or -1. + */ +diff_match_patch.prototype.match_main = function(text, pattern, loc) { + // Check for null inputs. + if (text == null || pattern == null || loc == null) { + throw new Error('Null input. (match_main)'); + } + + loc = Math.max(0, Math.min(loc, text.length)); + if (text == pattern) { + // Shortcut (potentially not guaranteed by the algorithm) + return 0; + } else if (!text.length) { + // Nothing to match. + return -1; + } else if (text.substring(loc, loc + pattern.length) == pattern) { + // Perfect match at the perfect spot! (Includes case of null pattern) + return loc; + } else { + // Do a fuzzy compare. + return this.match_bitap_(text, pattern, loc); + } +}; + + +/** + * Locate the best instance of 'pattern' in 'text' near 'loc' using the + * Bitap algorithm. + * @param {string} text The text to search. + * @param {string} pattern The pattern to search for. + * @param {number} loc The location to search around. + * @return {number} Best match index or -1. + * @private + */ +diff_match_patch.prototype.match_bitap_ = function(text, pattern, loc) { + if (pattern.length > this.Match_MaxBits) { + throw new Error('Pattern too long for this browser.'); + } + + // Initialise the alphabet. + var s = this.match_alphabet_(pattern); + + var dmp = this; // 'this' becomes 'window' in a closure. + + /** + * Compute and return the score for a match with e errors and x location. + * Accesses loc and pattern through being a closure. + * @param {number} e Number of errors in match. + * @param {number} x Location of match. + * @return {number} Overall score for match (0.0 = good, 1.0 = bad). + * @private + */ + function match_bitapScore_(e, x) { + var accuracy = e / pattern.length; + var proximity = Math.abs(loc - x); + if (!dmp.Match_Distance) { + // Dodge divide by zero error. + return proximity ? 1.0 : accuracy; + } + return accuracy + (proximity / dmp.Match_Distance); + } + + // Highest score beyond which we give up. + var score_threshold = this.Match_Threshold; + // Is there a nearby exact match? (speedup) + var best_loc = text.indexOf(pattern, loc); + if (best_loc != -1) { + score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); + // What about in the other direction? (speedup) + best_loc = text.lastIndexOf(pattern, loc + pattern.length); + if (best_loc != -1) { + score_threshold = + Math.min(match_bitapScore_(0, best_loc), score_threshold); + } + } + + // Initialise the bit arrays. + var matchmask = 1 << (pattern.length - 1); + best_loc = -1; + + var bin_min, bin_mid; + var bin_max = pattern.length + text.length; + var last_rd; + for (var d = 0; d < pattern.length; d++) { + // Scan for the best match; each iteration allows for one more error. + // Run a binary search to determine how far from 'loc' we can stray at this + // error level. + bin_min = 0; + bin_mid = bin_max; + while (bin_min < bin_mid) { + if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) { + bin_min = bin_mid; + } else { + bin_max = bin_mid; + } + bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min); + } + // Use the result from this iteration as the maximum for the next. + bin_max = bin_mid; + var start = Math.max(1, loc - bin_mid + 1); + var finish = Math.min(loc + bin_mid, text.length) + pattern.length; + + var rd = Array(finish + 2); + rd[finish + 1] = (1 << d) - 1; + for (var j = finish; j >= start; j--) { + // The alphabet (s) is a sparse hash, so the following line generates + // warnings. + var charMatch = s[text.charAt(j - 1)]; + if (d === 0) { // First pass: exact match. + rd[j] = ((rd[j + 1] << 1) | 1) & charMatch; + } else { // Subsequent passes: fuzzy match. + rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) | + (((last_rd[j + 1] | last_rd[j]) << 1) | 1) | + last_rd[j + 1]; + } + if (rd[j] & matchmask) { + var score = match_bitapScore_(d, j - 1); + // This match will almost certainly be better than any existing match. + // But check anyway. + if (score <= score_threshold) { + // Told you so. + score_threshold = score; + best_loc = j - 1; + if (best_loc > loc) { + // When passing loc, don't exceed our current distance from loc. + start = Math.max(1, 2 * loc - best_loc); + } else { + // Already passed loc, downhill from here on in. + break; + } + } + } + } + // No hope for a (better) match at greater error levels. + if (match_bitapScore_(d + 1, loc) > score_threshold) { + break; + } + last_rd = rd; + } + return best_loc; +}; + + +/** + * Initialise the alphabet for the Bitap algorithm. + * @param {string} pattern The text to encode. + * @return {!Object} Hash of character locations. + * @private + */ +diff_match_patch.prototype.match_alphabet_ = function(pattern) { + var s = {}; + for (var i = 0; i < pattern.length; i++) { + s[pattern.charAt(i)] = 0; + } + for (var i = 0; i < pattern.length; i++) { + s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1); + } + return s; +}; + + +// PATCH FUNCTIONS + + +/** + * Increase the context until it is unique, + * but don't let the pattern expand beyond Match_MaxBits. + * @param {!diff_match_patch.patch_obj} patch The patch to grow. + * @param {string} text Source text. + * @private + */ +diff_match_patch.prototype.patch_addContext_ = function(patch, text) { + if (text.length == 0) { + return; + } + var pattern = text.substring(patch.start2, patch.start2 + patch.length1); + var padding = 0; + + // Look for the first and last matches of pattern in text. If two different + // matches are found, increase the pattern length. + while (text.indexOf(pattern) != text.lastIndexOf(pattern) && + pattern.length < this.Match_MaxBits - this.Patch_Margin - + this.Patch_Margin) { + padding += this.Patch_Margin; + pattern = text.substring(patch.start2 - padding, + patch.start2 + patch.length1 + padding); + } + // Add one chunk for good luck. + padding += this.Patch_Margin; + + // Add the prefix. + var prefix = text.substring(patch.start2 - padding, patch.start2); + if (prefix) { + patch.diffs.unshift([DIFF_EQUAL, prefix]); + } + // Add the suffix. + var suffix = text.substring(patch.start2 + patch.length1, + patch.start2 + patch.length1 + padding); + if (suffix) { + patch.diffs.push([DIFF_EQUAL, suffix]); + } + + // Roll back the start points. + patch.start1 -= prefix.length; + patch.start2 -= prefix.length; + // Extend the lengths. + patch.length1 += prefix.length + suffix.length; + patch.length2 += prefix.length + suffix.length; +}; + + +/** + * Compute a list of patches to turn text1 into text2. + * Use diffs if provided, otherwise compute it ourselves. + * There are four ways to call this function, depending on what data is + * available to the caller: + * Method 1: + * a = text1, b = text2 + * Method 2: + * a = diffs + * Method 3 (optimal): + * a = text1, b = diffs + * Method 4 (deprecated, use method 3): + * a = text1, b = text2, c = diffs + * + * @param {string|!Array.} a text1 (methods 1,3,4) or + * Array of diff tuples for text1 to text2 (method 2). + * @param {string|!Array.} opt_b text2 (methods 1,4) or + * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2). + * @param {string|!Array.} opt_c Array of diff tuples + * for text1 to text2 (method 4) or undefined (methods 1,2,3). + * @return {!Array.} Array of Patch objects. + */ +diff_match_patch.prototype.patch_make = function(a, opt_b, opt_c) { + var text1, diffs; + if (typeof a == 'string' && typeof opt_b == 'string' && + typeof opt_c == 'undefined') { + // Method 1: text1, text2 + // Compute diffs from text1 and text2. + text1 = /** @type {string} */(a); + diffs = this.diff_main(text1, /** @type {string} */(opt_b), true); + if (diffs.length > 2) { + this.diff_cleanupSemantic(diffs); + this.diff_cleanupEfficiency(diffs); + } + } else if (a && typeof a == 'object' && typeof opt_b == 'undefined' && + typeof opt_c == 'undefined') { + // Method 2: diffs + // Compute text1 from diffs. + diffs = /** @type {!Array.} */(a); + text1 = this.diff_text1(diffs); + } else if (typeof a == 'string' && opt_b && typeof opt_b == 'object' && + typeof opt_c == 'undefined') { + // Method 3: text1, diffs + text1 = /** @type {string} */(a); + diffs = /** @type {!Array.} */(opt_b); + } else if (typeof a == 'string' && typeof opt_b == 'string' && + opt_c && typeof opt_c == 'object') { + // Method 4: text1, text2, diffs + // text2 is not used. + text1 = /** @type {string} */(a); + diffs = /** @type {!Array.} */(opt_c); + } else { + throw new Error('Unknown call format to patch_make.'); + } + + if (diffs.length === 0) { + return []; // Get rid of the null case. + } + var patches = []; + var patch = new diff_match_patch.patch_obj(); + var patchDiffLength = 0; // Keeping our own length var is faster in JS. + var char_count1 = 0; // Number of characters into the text1 string. + var char_count2 = 0; // Number of characters into the text2 string. + // Start with text1 (prepatch_text) and apply the diffs until we arrive at + // text2 (postpatch_text). We recreate the patches one by one to determine + // context info. + var prepatch_text = text1; + var postpatch_text = text1; + for (var x = 0; x < diffs.length; x++) { + var diff_type = diffs[x][0]; + var diff_text = diffs[x][1]; + + if (!patchDiffLength && diff_type !== DIFF_EQUAL) { + // A new patch starts here. + patch.start1 = char_count1; + patch.start2 = char_count2; + } + + switch (diff_type) { + case DIFF_INSERT: + patch.diffs[patchDiffLength++] = diffs[x]; + patch.length2 += diff_text.length; + postpatch_text = postpatch_text.substring(0, char_count2) + diff_text + + postpatch_text.substring(char_count2); + break; + case DIFF_DELETE: + patch.length1 += diff_text.length; + patch.diffs[patchDiffLength++] = diffs[x]; + postpatch_text = postpatch_text.substring(0, char_count2) + + postpatch_text.substring(char_count2 + + diff_text.length); + break; + case DIFF_EQUAL: + if (diff_text.length <= 2 * this.Patch_Margin && + patchDiffLength && diffs.length != x + 1) { + // Small equality inside a patch. + patch.diffs[patchDiffLength++] = diffs[x]; + patch.length1 += diff_text.length; + patch.length2 += diff_text.length; + } else if (diff_text.length >= 2 * this.Patch_Margin) { + // Time for a new patch. + if (patchDiffLength) { + this.patch_addContext_(patch, prepatch_text); + patches.push(patch); + patch = new diff_match_patch.patch_obj(); + patchDiffLength = 0; + // Unlike Unidiff, our patch lists have a rolling context. + // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff + // Update prepatch text & pos to reflect the application of the + // just completed patch. + prepatch_text = postpatch_text; + char_count1 = char_count2; + } + } + break; + } + + // Update the current character count. + if (diff_type !== DIFF_INSERT) { + char_count1 += diff_text.length; + } + if (diff_type !== DIFF_DELETE) { + char_count2 += diff_text.length; + } + } + // Pick up the leftover patch if not empty. + if (patchDiffLength) { + this.patch_addContext_(patch, prepatch_text); + patches.push(patch); + } + + return patches; +}; + + +/** + * Given an array of patches, return another array that is identical. + * @param {!Array.} patches Array of Patch objects. + * @return {!Array.} Array of Patch objects. + */ +diff_match_patch.prototype.patch_deepCopy = function(patches) { + // Making deep copies is hard in JavaScript. + var patchesCopy = []; + for (var x = 0; x < patches.length; x++) { + var patch = patches[x]; + var patchCopy = new diff_match_patch.patch_obj(); + patchCopy.diffs = []; + for (var y = 0; y < patch.diffs.length; y++) { + patchCopy.diffs[y] = patch.diffs[y].slice(); + } + patchCopy.start1 = patch.start1; + patchCopy.start2 = patch.start2; + patchCopy.length1 = patch.length1; + patchCopy.length2 = patch.length2; + patchesCopy[x] = patchCopy; + } + return patchesCopy; +}; + + +/** + * Merge a set of patches onto the text. Return a patched text, as well + * as a list of true/false values indicating which patches were applied. + * @param {!Array.} patches Array of Patch objects. + * @param {string} text Old text. + * @return {!Array.>} Two element Array, containing the + * new text and an array of boolean values. + */ +diff_match_patch.prototype.patch_apply = function(patches, text) { + if (patches.length == 0) { + return [text, []]; + } + + // Deep copy the patches so that no changes are made to originals. + patches = this.patch_deepCopy(patches); + + var nullPadding = this.patch_addPadding(patches); + text = nullPadding + text + nullPadding; + + this.patch_splitMax(patches); + // delta keeps track of the offset between the expected and actual location + // of the previous patch. If there are patches expected at positions 10 and + // 20, but the first patch was found at 12, delta is 2 and the second patch + // has an effective expected position of 22. + var delta = 0; + var results = []; + for (var x = 0; x < patches.length; x++) { + var expected_loc = patches[x].start2 + delta; + var text1 = this.diff_text1(patches[x].diffs); + var start_loc; + var end_loc = -1; + if (text1.length > this.Match_MaxBits) { + // patch_splitMax will only provide an oversized pattern in the case of + // a monster delete. + start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits), + expected_loc); + if (start_loc != -1) { + end_loc = this.match_main(text, + text1.substring(text1.length - this.Match_MaxBits), + expected_loc + text1.length - this.Match_MaxBits); + if (end_loc == -1 || start_loc >= end_loc) { + // Can't find valid trailing context. Drop this patch. + start_loc = -1; + } + } + } else { + start_loc = this.match_main(text, text1, expected_loc); + } + if (start_loc == -1) { + // No match found. :( + results[x] = false; + // Subtract the delta for this failed patch from subsequent patches. + delta -= patches[x].length2 - patches[x].length1; + } else { + // Found a match. :) + results[x] = true; + delta = start_loc - expected_loc; + var text2; + if (end_loc == -1) { + text2 = text.substring(start_loc, start_loc + text1.length); + } else { + text2 = text.substring(start_loc, end_loc + this.Match_MaxBits); + } + if (text1 == text2) { + // Perfect match, just shove the replacement text in. + text = text.substring(0, start_loc) + + this.diff_text2(patches[x].diffs) + + text.substring(start_loc + text1.length); + } else { + // Imperfect match. Run a diff to get a framework of equivalent + // indices. + var diffs = this.diff_main(text1, text2, false); + if (text1.length > this.Match_MaxBits && + this.diff_levenshtein(diffs) / text1.length > + this.Patch_DeleteThreshold) { + // The end points match, but the content is unacceptably bad. + results[x] = false; + } else { + this.diff_cleanupSemanticLossless(diffs); + var index1 = 0; + var index2; + for (var y = 0; y < patches[x].diffs.length; y++) { + var mod = patches[x].diffs[y]; + if (mod[0] !== DIFF_EQUAL) { + index2 = this.diff_xIndex(diffs, index1); + } + if (mod[0] === DIFF_INSERT) { // Insertion + text = text.substring(0, start_loc + index2) + mod[1] + + text.substring(start_loc + index2); + } else if (mod[0] === DIFF_DELETE) { // Deletion + text = text.substring(0, start_loc + index2) + + text.substring(start_loc + this.diff_xIndex(diffs, + index1 + mod[1].length)); + } + if (mod[0] !== DIFF_DELETE) { + index1 += mod[1].length; + } + } + } + } + } + } + // Strip the padding off. + text = text.substring(nullPadding.length, text.length - nullPadding.length); + return [text, results]; +}; + + +/** + * Add some padding on text start and end so that edges can match something. + * Intended to be called only from within patch_apply. + * @param {!Array.} patches Array of Patch objects. + * @return {string} The padding string added to each side. + */ +diff_match_patch.prototype.patch_addPadding = function(patches) { + var paddingLength = this.Patch_Margin; + var nullPadding = ''; + for (var x = 1; x <= paddingLength; x++) { + nullPadding += String.fromCharCode(x); + } + + // Bump all the patches forward. + for (var x = 0; x < patches.length; x++) { + patches[x].start1 += paddingLength; + patches[x].start2 += paddingLength; + } + + // Add some padding on start of first diff. + var patch = patches[0]; + var diffs = patch.diffs; + if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) { + // Add nullPadding equality. + diffs.unshift([DIFF_EQUAL, nullPadding]); + patch.start1 -= paddingLength; // Should be 0. + patch.start2 -= paddingLength; // Should be 0. + patch.length1 += paddingLength; + patch.length2 += paddingLength; + } else if (paddingLength > diffs[0][1].length) { + // Grow first equality. + var extraLength = paddingLength - diffs[0][1].length; + diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1]; + patch.start1 -= extraLength; + patch.start2 -= extraLength; + patch.length1 += extraLength; + patch.length2 += extraLength; + } + + // Add some padding on end of last diff. + patch = patches[patches.length - 1]; + diffs = patch.diffs; + if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) { + // Add nullPadding equality. + diffs.push([DIFF_EQUAL, nullPadding]); + patch.length1 += paddingLength; + patch.length2 += paddingLength; + } else if (paddingLength > diffs[diffs.length - 1][1].length) { + // Grow last equality. + var extraLength = paddingLength - diffs[diffs.length - 1][1].length; + diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength); + patch.length1 += extraLength; + patch.length2 += extraLength; + } + + return nullPadding; +}; + + +/** + * Look through the patches and break up any which are longer than the maximum + * limit of the match algorithm. + * Intended to be called only from within patch_apply. + * @param {!Array.} patches Array of Patch objects. + */ +diff_match_patch.prototype.patch_splitMax = function(patches) { + var patch_size = this.Match_MaxBits; + for (var x = 0; x < patches.length; x++) { + if (patches[x].length1 <= patch_size) { + continue; + } + var bigpatch = patches[x]; + // Remove the big old patch. + patches.splice(x--, 1); + var start1 = bigpatch.start1; + var start2 = bigpatch.start2; + var precontext = ''; + while (bigpatch.diffs.length !== 0) { + // Create one of several smaller patches. + var patch = new diff_match_patch.patch_obj(); + var empty = true; + patch.start1 = start1 - precontext.length; + patch.start2 = start2 - precontext.length; + if (precontext !== '') { + patch.length1 = patch.length2 = precontext.length; + patch.diffs.push([DIFF_EQUAL, precontext]); + } + while (bigpatch.diffs.length !== 0 && + patch.length1 < patch_size - this.Patch_Margin) { + var diff_type = bigpatch.diffs[0][0]; + var diff_text = bigpatch.diffs[0][1]; + if (diff_type === DIFF_INSERT) { + // Insertions are harmless. + patch.length2 += diff_text.length; + start2 += diff_text.length; + patch.diffs.push(bigpatch.diffs.shift()); + empty = false; + } else if (diff_type === DIFF_DELETE && patch.diffs.length == 1 && + patch.diffs[0][0] == DIFF_EQUAL && + diff_text.length > 2 * patch_size) { + // This is a large deletion. Let it pass in one chunk. + patch.length1 += diff_text.length; + start1 += diff_text.length; + empty = false; + patch.diffs.push([diff_type, diff_text]); + bigpatch.diffs.shift(); + } else { + // Deletion or equality. Only take as much as we can stomach. + diff_text = diff_text.substring(0, + patch_size - patch.length1 - this.Patch_Margin); + patch.length1 += diff_text.length; + start1 += diff_text.length; + if (diff_type === DIFF_EQUAL) { + patch.length2 += diff_text.length; + start2 += diff_text.length; + } else { + empty = false; + } + patch.diffs.push([diff_type, diff_text]); + if (diff_text == bigpatch.diffs[0][1]) { + bigpatch.diffs.shift(); + } else { + bigpatch.diffs[0][1] = + bigpatch.diffs[0][1].substring(diff_text.length); + } + } + } + // Compute the head context for the next patch. + precontext = this.diff_text2(patch.diffs); + precontext = + precontext.substring(precontext.length - this.Patch_Margin); + // Append the end context for this patch. + var postcontext = this.diff_text1(bigpatch.diffs) + .substring(0, this.Patch_Margin); + if (postcontext !== '') { + patch.length1 += postcontext.length; + patch.length2 += postcontext.length; + if (patch.diffs.length !== 0 && + patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL) { + patch.diffs[patch.diffs.length - 1][1] += postcontext; + } else { + patch.diffs.push([DIFF_EQUAL, postcontext]); + } + } + if (!empty) { + patches.splice(++x, 0, patch); + } + } + } +}; + + +/** + * Take a list of patches and return a textual representation. + * @param {!Array.} patches Array of Patch objects. + * @return {string} Text representation of patches. + */ +diff_match_patch.prototype.patch_toText = function(patches) { + var text = []; + for (var x = 0; x < patches.length; x++) { + text[x] = patches[x]; + } + return text.join(''); +}; + + +/** + * Parse a textual representation of patches and return a list of Patch objects. + * @param {string} textline Text representation of patches. + * @return {!Array.} Array of Patch objects. + * @throws {!Error} If invalid input. + */ +diff_match_patch.prototype.patch_fromText = function(textline) { + var patches = []; + if (!textline) { + return patches; + } + var text = textline.split('\n'); + var textPointer = 0; + var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/; + while (textPointer < text.length) { + var m = text[textPointer].match(patchHeader); + if (!m) { + throw new Error('Invalid patch string: ' + text[textPointer]); + } + var patch = new diff_match_patch.patch_obj(); + patches.push(patch); + patch.start1 = parseInt(m[1], 10); + if (m[2] === '') { + patch.start1--; + patch.length1 = 1; + } else if (m[2] == '0') { + patch.length1 = 0; + } else { + patch.start1--; + patch.length1 = parseInt(m[2], 10); + } + + patch.start2 = parseInt(m[3], 10); + if (m[4] === '') { + patch.start2--; + patch.length2 = 1; + } else if (m[4] == '0') { + patch.length2 = 0; + } else { + patch.start2--; + patch.length2 = parseInt(m[4], 10); + } + textPointer++; + + while (textPointer < text.length) { + var sign = text[textPointer].charAt(0); + try { + var line = decodeURI(text[textPointer].substring(1)); + } catch (ex) { + // Malformed URI sequence. + throw new Error('Illegal escape in patch_fromText: ' + line); + } + if (sign == '-') { + // Deletion. + patch.diffs.push([DIFF_DELETE, line]); + } else if (sign == '+') { + // Insertion. + patch.diffs.push([DIFF_INSERT, line]); + } else if (sign == ' ') { + // Minor equality. + patch.diffs.push([DIFF_EQUAL, line]); + } else if (sign == '@') { + // Start of next patch. + break; + } else if (sign === '') { + // Blank line? Whatever. + } else { + // WTF? + throw new Error('Invalid patch mode "' + sign + '" in: ' + line); + } + textPointer++; + } + } + return patches; +}; + + +/** + * Class representing one patch operation. + * @constructor + */ +diff_match_patch.patch_obj = function() { + /** @type {!Array.} */ + this.diffs = []; + /** @type {?number} */ + this.start1 = null; + /** @type {?number} */ + this.start2 = null; + /** @type {number} */ + this.length1 = 0; + /** @type {number} */ + this.length2 = 0; +}; + + +/** + * Emmulate GNU diff's format. + * Header: @@ -382,8 +481,9 @@ + * Indicies are printed as 1-based, not 0-based. + * @return {string} The GNU diff string. + */ +diff_match_patch.patch_obj.prototype.toString = function() { + var coords1, coords2; + if (this.length1 === 0) { + coords1 = this.start1 + ',0'; + } else if (this.length1 == 1) { + coords1 = this.start1 + 1; + } else { + coords1 = (this.start1 + 1) + ',' + this.length1; + } + if (this.length2 === 0) { + coords2 = this.start2 + ',0'; + } else if (this.length2 == 1) { + coords2 = this.start2 + 1; + } else { + coords2 = (this.start2 + 1) + ',' + this.length2; + } + var text = ['@@ -' + coords1 + ' +' + coords2 + ' @@\n']; + var op; + // Escape the body of the patch with %xx notation. + for (var x = 0; x < this.diffs.length; x++) { + switch (this.diffs[x][0]) { + case DIFF_INSERT: + op = '+'; + break; + case DIFF_DELETE: + op = '-'; + break; + case DIFF_EQUAL: + op = ' '; + break; + } + text[x + 1] = op + encodeURI(this.diffs[x][1]) + '\n'; + } + return text.join('').replace(/%20/g, ' '); +}; + + +// Export these global variables so that they survive Google's JS compiler. +// In a browser, 'this' will be 'window'. +// Users of node.js should 'require' the uncompressed version since Google's +// JS compiler may break the following exports for non-browser environments. +this['diff_match_patch'] = diff_match_patch; +this['DIFF_DELETE'] = DIFF_DELETE; +this['DIFF_INSERT'] = DIFF_INSERT; +this['DIFF_EQUAL'] = DIFF_EQUAL; + +},{}],39:[function(_dereq_,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var isArgs = _dereq_('./isArguments'); +var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'); +var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var ctor = object.constructor; + var skipConstructor = ctor && ctor.prototype === object; + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (!Object.keys) { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"./isArguments":40}],40:[function(_dereq_,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' + && value !== null + && typeof value === 'object' + && typeof value.length === 'number' + && value.length >= 0 + && toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],41:[function(_dereq_,module,exports){ +/** + * stringifier + * + * https://github.com/twada/stringifier + * + * Copyright (c) 2014-2015 Takuto Wada + * Licensed under the MIT license. + * http://twada.mit-license.org/2014-2015 + */ +'use strict'; + +var traverse = _dereq_('traverse'), + typeName = _dereq_('type-name'), + extend = _dereq_('xtend'), + s = _dereq_('./strategies'); + +function defaultHandlers () { + return { + 'null': s.always('null'), + 'undefined': s.always('undefined'), + 'function': s.prune(), + 'string': s.json(), + 'boolean': s.json(), + 'number': s.number(), + 'RegExp': s.toStr(), + 'String': s.newLike(), + 'Boolean': s.newLike(), + 'Number': s.newLike(), + 'Date': s.newLike(), + 'Array': s.array(), + 'Object': s.object(), + '@default': s.object() + }; +} + +function defaultOptions () { + return { + maxDepth: null, + indent: null, + anonymous: '@Anonymous', + circular: '#@Circular#', + snip: '..(snip)', + lineSeparator: '\n', + typeFun: typeName + }; +} + +function createStringifier (customOptions) { + var options = extend(defaultOptions(), customOptions), + handlers = extend(defaultHandlers(), options.handlers); + return function stringifyAny (push, x) { + var context = this, + handler = handlerFor(context.node, options, handlers), + currentPath = '/' + context.path.join('/'), + customization = handlers[currentPath], + acc = { + context: context, + options: options, + handlers: handlers, + push: push + }; + if (typeName(customization) === 'function') { + handler = customization; + } else if (typeName(customization) === 'number') { + handler = s.flow.compose(s.filters.truncate(customization),handler); + } + handler(acc, x); + return push; + }; +} + +function handlerFor (val, options, handlers) { + var tname = options.typeFun(val); + if (typeName(handlers[tname]) === 'function') { + return handlers[tname]; + } + return handlers['@default']; +} + +function walk (val, reducer) { + var buffer = [], + push = function (str) { + buffer.push(str); + }; + traverse(val).reduce(reducer, push); + return buffer.join(''); +} + +function stringify (val, options) { + return walk(val, createStringifier(options)); +} + +function stringifier (options) { + return function (val) { + return walk(val, createStringifier(options)); + }; +} + +stringifier.stringify = stringify; +stringifier.strategies = s; +stringifier.defaultOptions = defaultOptions; +stringifier.defaultHandlers = defaultHandlers; +module.exports = stringifier; + +},{"./strategies":42,"traverse":44,"type-name":43,"xtend":45}],42:[function(_dereq_,module,exports){ +'use strict'; + +var typeName = _dereq_('type-name'), + slice = Array.prototype.slice, + END = {}, + ITERATE = {}; + +// arguments should end with end or iterate +function compose () { + var filters = slice.apply(arguments); + return filters.reduceRight(function(right, left) { + return left(right); + }); +} + +// skip children +function end () { + return function (acc, x) { + acc.context.keys = []; + return END; + }; +} + +// iterate children +function iterate () { + return function (acc, x) { + return ITERATE; + }; +} + +function filter (predicate) { + return function (next) { + return function (acc, x) { + var toBeIterated, + isIteratingArray = (typeName(x) === 'Array'); + if (typeName(predicate) === 'function') { + toBeIterated = []; + acc.context.keys.forEach(function (key) { + var indexOrKey = isIteratingArray ? parseInt(key, 10) : key, + kvp = { + key: indexOrKey, + value: x[key] + }, + decision = predicate(kvp); + if (decision) { + toBeIterated.push(key); + } + if (typeName(decision) === 'number') { + truncateByKey(decision, key, acc); + } + if (typeName(decision) === 'function') { + customizeStrategyForKey(decision, key, acc); + } + }); + acc.context.keys = toBeIterated; + } + return next(acc, x); + }; + }; +} + +function customizeStrategyForKey (strategy, key, acc) { + acc.handlers[currentPath(key, acc)] = strategy; +} + +function truncateByKey (size, key, acc) { + acc.handlers[currentPath(key, acc)] = size; +} + +function currentPath (key, acc) { + var pathToCurrentNode = [''].concat(acc.context.path); + if (typeName(key) !== 'undefined') { + pathToCurrentNode.push(key); + } + return pathToCurrentNode.join('/'); +} + +function allowedKeys (orderedWhiteList) { + return function (next) { + return function (acc, x) { + var isIteratingArray = (typeName(x) === 'Array'); + if (!isIteratingArray && typeName(orderedWhiteList) === 'Array') { + acc.context.keys = orderedWhiteList.filter(function (propKey) { + return acc.context.keys.indexOf(propKey) !== -1; + }); + } + return next(acc, x); + }; + }; +} + +function safeKeys () { + return function (next) { + return function (acc, x) { + if (typeName(x) !== 'Array') { + acc.context.keys = acc.context.keys.filter(function (propKey) { + // Error handling for unsafe property access. + // For example, on PhantomJS, + // accessing HTMLInputElement.selectionEnd causes TypeError + try { + var val = x[propKey]; + return true; + } catch (e) { + // skip unsafe key + return false; + } + }); + } + return next(acc, x); + }; + }; +} + +function when (guard, then) { + return function (next) { + return function (acc, x) { + var kvp = { + key: acc.context.key, + value: x + }; + if (guard(kvp, acc)) { + return then(acc, x); + } + return next(acc, x); + }; + }; +} + +function truncate (size) { + return function (next) { + return function (acc, x) { + var orig = acc.push, ret; + acc.push = function (str) { + var savings = str.length - size, + truncated; + if (savings <= size) { + orig.call(acc, str); + } else { + truncated = str.substring(0, size); + orig.call(acc, truncated + acc.options.snip); + } + }; + ret = next(acc, x); + acc.push = orig; + return ret; + }; + }; +} + +function constructorName () { + return function (next) { + return function (acc, x) { + var name = acc.options.typeFun(x); + if (name === '') { + name = acc.options.anonymous; + } + acc.push(name); + return next(acc, x); + }; + }; +} + +function always (str) { + return function (next) { + return function (acc, x) { + acc.push(str); + return next(acc, x); + }; + }; +} + +function optionValue (key) { + return function (next) { + return function (acc, x) { + acc.push(acc.options[key]); + return next(acc, x); + }; + }; +} + +function json (replacer) { + return function (next) { + return function (acc, x) { + acc.push(JSON.stringify(x, replacer)); + return next(acc, x); + }; + }; +} + +function toStr () { + return function (next) { + return function (acc, x) { + acc.push(x.toString()); + return next(acc, x); + }; + }; +} + +function decorateArray () { + return function (next) { + return function (acc, x) { + acc.context.before(function (node) { + acc.push('['); + }); + acc.context.after(function (node) { + afterAllChildren(this, acc.push, acc.options); + acc.push(']'); + }); + acc.context.pre(function (val, key) { + beforeEachChild(this, acc.push, acc.options); + }); + acc.context.post(function (childContext) { + afterEachChild(childContext, acc.push); + }); + return next(acc, x); + }; + }; +} + +function decorateObject () { + return function (next) { + return function (acc, x) { + acc.context.before(function (node) { + acc.push('{'); + }); + acc.context.after(function (node) { + afterAllChildren(this, acc.push, acc.options); + acc.push('}'); + }); + acc.context.pre(function (val, key) { + beforeEachChild(this, acc.push, acc.options); + acc.push(sanitizeKey(key) + (acc.options.indent ? ': ' : ':')); + }); + acc.context.post(function (childContext) { + afterEachChild(childContext, acc.push); + }); + return next(acc, x); + }; + }; +} + +function sanitizeKey (key) { + return /^[A-Za-z_]+$/.test(key) ? key : JSON.stringify(key); +} + +function afterAllChildren (context, push, options) { + if (options.indent && 0 < context.keys.length) { + push(options.lineSeparator); + for(var i = 0; i < context.level; i += 1) { // indent level - 1 + push(options.indent); + } + } +} + +function beforeEachChild (context, push, options) { + if (options.indent) { + push(options.lineSeparator); + for(var i = 0; i <= context.level; i += 1) { + push(options.indent); + } + } +} + +function afterEachChild (childContext, push) { + if (!childContext.isLast) { + push(','); + } +} + +function nan (kvp, acc) { + return kvp.value !== kvp.value; +} + +function positiveInfinity (kvp, acc) { + return !isFinite(kvp.value) && kvp.value === Infinity; +} + +function negativeInfinity (kvp, acc) { + return !isFinite(kvp.value) && kvp.value !== Infinity; +} + +function circular (kvp, acc) { + return acc.context.circular; +} + +function maxDepth (kvp, acc) { + return (acc.options.maxDepth && acc.options.maxDepth <= acc.context.level); +} + +var prune = compose( + always('#'), + constructorName(), + always('#'), + end() +); +var omitNaN = when(nan, compose( + always('NaN'), + end() +)); +var omitPositiveInfinity = when(positiveInfinity, compose( + always('Infinity'), + end() +)); +var omitNegativeInfinity = when(negativeInfinity, compose( + always('-Infinity'), + end() +)); +var omitCircular = when(circular, compose( + optionValue('circular'), + end() +)); +var omitMaxDepth = when(maxDepth, prune); + +module.exports = { + filters: { + always: always, + constructorName: constructorName, + json: json, + toStr: toStr, + prune: prune, + truncate: truncate, + decorateArray: decorateArray, + decorateObject: decorateObject + }, + flow: { + compose: compose, + when: when, + allowedKeys: allowedKeys, + safeKeys: safeKeys, + filter: filter, + iterate: iterate, + end: end + }, + symbols: { + END: END, + ITERATE: ITERATE + }, + always: function (str) { + return compose(always(str), end()); + }, + json: function () { + return compose(json(), end()); + }, + toStr: function () { + return compose(toStr(), end()); + }, + prune: function () { + return prune; + }, + number: function () { + return compose( + omitNaN, + omitPositiveInfinity, + omitNegativeInfinity, + json(), + end() + ); + }, + newLike: function () { + return compose( + always('new '), + constructorName(), + always('('), + json(), + always(')'), + end() + ); + }, + array: function (predicate) { + return compose( + omitCircular, + omitMaxDepth, + decorateArray(), + filter(predicate), + iterate() + ); + }, + object: function (predicate, orderedWhiteList) { + return compose( + omitCircular, + omitMaxDepth, + constructorName(), + decorateObject(), + allowedKeys(orderedWhiteList), + safeKeys(), + filter(predicate), + iterate() + ); + } +}; + +},{"type-name":43}],43:[function(_dereq_,module,exports){ +/** + * type-name - Just a reasonable typeof + * + * https://github.com/twada/type-name + * + * Copyright (c) 2014 Takuto Wada + * Licensed under the MIT license. + * http://twada.mit-license.org/ + */ +'use strict'; + +var toStr = Object.prototype.toString; + +function funcName (f) { + return f.name ? f.name : /^\s*function\s*([^\(]*)/im.exec(f.toString())[1]; +} + +function ctorName (obj) { + var strName = toStr.call(obj).slice(8, -1); + if (strName === 'Object' && obj.constructor) { + return funcName(obj.constructor); + } + return strName; +} + +function typeName (val) { + var type; + if (val === null) { + return 'null'; + } + type = typeof(val); + if (type === 'object') { + return ctorName(val); + } + return type; +} + +module.exports = typeName; + +},{}],44:[function(_dereq_,module,exports){ +var traverse = module.exports = function (obj) { + return new Traverse(obj); +}; + +function Traverse (obj) { + this.value = obj; +} + +Traverse.prototype.get = function (ps) { + var node = this.value; + for (var i = 0; i < ps.length; i ++) { + var key = ps[i]; + if (!node || !hasOwnProperty.call(node, key)) { + node = undefined; + break; + } + node = node[key]; + } + return node; +}; + +Traverse.prototype.has = function (ps) { + var node = this.value; + for (var i = 0; i < ps.length; i ++) { + var key = ps[i]; + if (!node || !hasOwnProperty.call(node, key)) { + return false; + } + node = node[key]; + } + return true; +}; + +Traverse.prototype.set = function (ps, value) { + var node = this.value; + for (var i = 0; i < ps.length - 1; i ++) { + var key = ps[i]; + if (!hasOwnProperty.call(node, key)) node[key] = {}; + node = node[key]; + } + node[ps[i]] = value; + return value; +}; + +Traverse.prototype.map = function (cb) { + return walk(this.value, cb, true); +}; + +Traverse.prototype.forEach = function (cb) { + this.value = walk(this.value, cb, false); + return this.value; +}; + +Traverse.prototype.reduce = function (cb, init) { + var skip = arguments.length === 1; + var acc = skip ? this.value : init; + this.forEach(function (x) { + if (!this.isRoot || !skip) { + acc = cb.call(this, acc, x); + } + }); + return acc; +}; + +Traverse.prototype.paths = function () { + var acc = []; + this.forEach(function (x) { + acc.push(this.path); + }); + return acc; +}; + +Traverse.prototype.nodes = function () { + var acc = []; + this.forEach(function (x) { + acc.push(this.node); + }); + return acc; +}; + +Traverse.prototype.clone = function () { + var parents = [], nodes = []; + + return (function clone (src) { + for (var i = 0; i < parents.length; i++) { + if (parents[i] === src) { + return nodes[i]; + } + } + + if (typeof src === 'object' && src !== null) { + var dst = copy(src); + + parents.push(src); + nodes.push(dst); + + forEach(objectKeys(src), function (key) { + dst[key] = clone(src[key]); + }); + + parents.pop(); + nodes.pop(); + return dst; + } + else { + return src; + } + })(this.value); +}; + +function walk (root, cb, immutable) { + var path = []; + var parents = []; + var alive = true; + + return (function walker (node_) { + var node = immutable ? copy(node_) : node_; + var modifiers = {}; + + var keepGoing = true; + + var state = { + node : node, + node_ : node_, + path : [].concat(path), + parent : parents[parents.length - 1], + parents : parents, + key : path.slice(-1)[0], + isRoot : path.length === 0, + level : path.length, + circular : null, + update : function (x, stopHere) { + if (!state.isRoot) { + state.parent.node[state.key] = x; + } + state.node = x; + if (stopHere) keepGoing = false; + }, + 'delete' : function (stopHere) { + delete state.parent.node[state.key]; + if (stopHere) keepGoing = false; + }, + remove : function (stopHere) { + if (isArray(state.parent.node)) { + state.parent.node.splice(state.key, 1); + } + else { + delete state.parent.node[state.key]; + } + if (stopHere) keepGoing = false; + }, + keys : null, + before : function (f) { modifiers.before = f }, + after : function (f) { modifiers.after = f }, + pre : function (f) { modifiers.pre = f }, + post : function (f) { modifiers.post = f }, + stop : function () { alive = false }, + block : function () { keepGoing = false } + }; + + if (!alive) return state; + + function updateState() { + if (typeof state.node === 'object' && state.node !== null) { + if (!state.keys || state.node_ !== state.node) { + state.keys = objectKeys(state.node) + } + + state.isLeaf = state.keys.length == 0; + + for (var i = 0; i < parents.length; i++) { + if (parents[i].node_ === node_) { + state.circular = parents[i]; + break; + } + } + } + else { + state.isLeaf = true; + state.keys = null; + } + + state.notLeaf = !state.isLeaf; + state.notRoot = !state.isRoot; + } + + updateState(); + + // use return values to update if defined + var ret = cb.call(state, state.node); + if (ret !== undefined && state.update) state.update(ret); + + if (modifiers.before) modifiers.before.call(state, state.node); + + if (!keepGoing) return state; + + if (typeof state.node == 'object' + && state.node !== null && !state.circular) { + parents.push(state); + + updateState(); + + forEach(state.keys, function (key, i) { + path.push(key); + + if (modifiers.pre) modifiers.pre.call(state, state.node[key], key); + + var child = walker(state.node[key]); + if (immutable && hasOwnProperty.call(state.node, key)) { + state.node[key] = child.node; + } + + child.isLast = i == state.keys.length - 1; + child.isFirst = i == 0; + + if (modifiers.post) modifiers.post.call(state, child); + + path.pop(); + }); + parents.pop(); + } + + if (modifiers.after) modifiers.after.call(state, state.node); + + return state; + })(root).node; +} + +function copy (src) { + if (typeof src === 'object' && src !== null) { + var dst; + + if (isArray(src)) { + dst = []; + } + else if (isDate(src)) { + dst = new Date(src.getTime ? src.getTime() : src); + } + else if (isRegExp(src)) { + dst = new RegExp(src); + } + else if (isError(src)) { + dst = { message: src.message }; + } + else if (isBoolean(src)) { + dst = new Boolean(src); + } + else if (isNumber(src)) { + dst = new Number(src); + } + else if (isString(src)) { + dst = new String(src); + } + else if (Object.create && Object.getPrototypeOf) { + dst = Object.create(Object.getPrototypeOf(src)); + } + else if (src.constructor === Object) { + dst = {}; + } + else { + var proto = + (src.constructor && src.constructor.prototype) + || src.__proto__ + || {} + ; + var T = function () {}; + T.prototype = proto; + dst = new T; + } + + forEach(objectKeys(src), function (key) { + dst[key] = src[key]; + }); + return dst; + } + else return src; +} + +var objectKeys = Object.keys || function keys (obj) { + var res = []; + for (var key in obj) res.push(key) + return res; +}; + +function toS (obj) { return Object.prototype.toString.call(obj) } +function isDate (obj) { return toS(obj) === '[object Date]' } +function isRegExp (obj) { return toS(obj) === '[object RegExp]' } +function isError (obj) { return toS(obj) === '[object Error]' } +function isBoolean (obj) { return toS(obj) === '[object Boolean]' } +function isNumber (obj) { return toS(obj) === '[object Number]' } +function isString (obj) { return toS(obj) === '[object String]' } + +var isArray = Array.isArray || function isArray (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +var forEach = function (xs, fn) { + if (xs.forEach) return xs.forEach(fn) + else for (var i = 0; i < xs.length; i++) { + fn(xs[i], i, xs); + } +}; + +forEach(objectKeys(Traverse.prototype), function (key) { + traverse[key] = function (obj) { + var args = [].slice.call(arguments, 1); + var t = new Traverse(obj); + return t[key].apply(t, args); + }; +}); + +var hasOwnProperty = Object.hasOwnProperty || function (obj, key) { + return key in obj; +}; + +},{}],45:[function(_dereq_,module,exports){ +module.exports = extend + +function extend() { + var target = {} + + for (var i = 0; i < arguments.length; i++) { + var source = arguments[i] + + for (var key in source) { + if (source.hasOwnProperty(key)) { + target[key] = source[key] + } + } + } + + return target +} + +},{}],46:[function(_dereq_,module,exports){ +module.exports = extend + +function extend(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] + + for (var key in source) { + if (source.hasOwnProperty(key)) { + target[key] = source[key] + } + } + } + + return target +} + +},{}]},{},[7])(7) +}); + diff --git a/packages/planner/node_modules/deepcopy/deepcopy.js b/packages/planner/node_modules/deepcopy/deepcopy.js new file mode 100644 index 00000000..cb66bc6a --- /dev/null +++ b/packages/planner/node_modules/deepcopy/deepcopy.js @@ -0,0 +1,229 @@ +/*! + * @license deepcopy.js Copyright(c) 2013 sasa+1 + * https://github.com/sasaplus1/deepcopy.js + * Released under the MIT license. + */ + + +/** + * export to AMD/CommonJS/global. + * + * @param {Object} global global object. + * @param {Function} factory factory method. + */ +(function(global, factory) { + 'use strict'; + + if (typeof define === 'function' && !!define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + global.deepcopy = factory(); + } +}(this, function() { + 'use strict'; + + var isNode, util, isBuffer, getKeys, getSymbols, indexOfArray; + + // is node.js/io.js? + isNode = (typeof process !== 'undefined' && typeof require !== 'undefined'); + + // fallback util module for browser. + util = (isNode) ? require('util') : (function() { + function isArray(value) { + return (typeof value === 'object' && + Object.prototype.toString.call(value) === '[object Array]'); + } + + function isDate(value) { + return (typeof value === 'object' && + Object.prototype.toString.call(value) === '[object Date]'); + } + + function isRegExp(value) { + return (typeof value === 'object' && + Object.prototype.toString.call(value) === '[object RegExp]'); + } + + function isSymbol(value) { + return (typeof value === 'symbol'); + } + + return { + isArray: (typeof Array.isArray === 'function') ? + function(obj) { + return Array.isArray(obj); + } : isArray, + isDate: isDate, + isRegExp: isRegExp, + isSymbol: (typeof Symbol === 'function') ? + isSymbol : + function() { + // always return false when Symbol is not supported. + return false; + } + }; + }()); + + // fallback Buffer.isBuffer + isBuffer = (isNode) ? + function(obj) { + return Buffer.isBuffer(obj); + } : + function() { + // if browser, always return false + return false; + }; + + // fallback Object.keys for old browsers. + getKeys = (typeof Object.keys === 'function') ? + function(obj) { + return Object.keys(obj); + } : + function(obj) { + var keys = [], + key; + + if (obj === null || typeof obj !== 'object') { + throw new TypeError('obj is not an Object'); + } + + for (key in obj) { + obj.hasOwnProperty(key) && keys.push(key); + } + + return keys; + }; + + // get symbols in object. + getSymbols = (typeof Symbol === 'function') ? + function(obj) { + return Object.getOwnPropertySymbols(obj); + } : + function() { + // always return empty array when Symbol is not supported. + return []; + }; + + // fallback Array#indexOf for old browsers. + indexOfArray = (typeof Array.prototype.indexOf === 'function') ? + function(array, searchElement) { + return array.indexOf(searchElement); + } : + function(array, searchElement) { + var i, len; + + if (!util.isArray(array)) { + throw new TypeError('array is not an Array'); + } + + for (i = 0, len = array.length; i < len; ++i) { + if (array[i] === searchElement) { + return i; + } + } + + return -1; + }; + + /** + * recursive deep copy for value. + * + * @private + * @param {*} value copy target. + * @param {*} clone + * @param {Array} visited + * @param {Array} reference + * @return {*} copied value. + */ + function copyValue_(value, clone, visited, reference) { + var str, pos, buf, keys, i, len, key, val, idx, obj, ref; + + // number, string, boolean, null, undefined, function and symbol. + if (value === null || typeof value !== 'object') { + return value; + } + + // Date. + if (util.isDate(value)) { + // Firefox need to convert to Number + // + // Firefox: + // var date = new Date; + // +date; // 1420909365967 + // +new Date(date); // 1420909365000 + // +new Date(+date); // 1420909365967 + // Chrome: + // var date = new Date; + // +date; // 1420909757913 + // +new Date(date); // 1420909757913 + // +new Date(+date); // 1420909757913 + return new Date(+value); + } + + // RegExp. + if (util.isRegExp(value)) { + // Chrome, Safari: + // (new RegExp).source => "(?:)" + // Firefox: + // (new RegExp).source => "" + // Chrome, Safari, Firefox + // String(new RegExp) => "/(?:)/" + str = String(value); + pos = str.lastIndexOf('/'); + + return new RegExp(str.slice(1, pos), str.slice(pos + 1)); + } + + // Buffer, node.js only. + if (isBuffer(value)) { + buf = new Buffer(value.length); + value.copy(buf); + + return buf; + } + + // Object or Array. + keys = getKeys(value).concat(getSymbols(value)); + + for (i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + val = value[key]; + + if (val !== null && typeof val === 'object') { + idx = indexOfArray(visited, val); + + if (idx === -1) { + // not circular reference + obj = (util.isArray(val)) ? [] : {}; + + visited.push(val); + reference.push(obj); + } else { + // circular reference + ref = reference[idx]; + } + } + + clone[key] = ref || copyValue_(val, obj, visited, reference); + } + + return clone; + } + + /** + * deep copy for value. + * + * @param {*} value copy target. + */ + function deepcopy(value) { + var clone = (util.isArray(value)) ? [] : {}, + visited = [value], + reference = [clone]; + + return copyValue_(value, clone, visited, reference); + } + + return deepcopy; +})); diff --git a/packages/planner/node_modules/deepcopy/package.json b/packages/planner/node_modules/deepcopy/package.json new file mode 100644 index 00000000..17cbb745 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/package.json @@ -0,0 +1,69 @@ +{ + "name": "deepcopy", + "version": "0.5.0", + "author": { + "name": "sasa+1", + "email": "sasaplus1@gmail.com" + }, + "contributors": [ + { + "name": "kjirou", + "email": "kjirou.web@gmail.com" + } + ], + "description": "deep copy for any data", + "main": "./deepcopy.js", + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/sasaplus1/deepcopy.js.git" + }, + "directories": { + "test": "test/" + }, + "scripts": { + "bower": "bower install", + "fix": "fixjsstyle --flagfile .closurelinter -r .", + "lint": "gjslint --flagfile .closurelinter -r .", + "minify": "uglifyjs ./deepcopy.js --comments '@license' -cm -r deepcopy -o ./deepcopy.min.js", + "power": "espower ./test/test.js > ./test/test.pwr.js", + "test": "mocha ./test/test.js", + "testem": "testem", + "travis": "testem ci --launch Firefox,PhantomJS" + }, + "devDependencies": { + "bower": "~1.4", + "espower-cli": "~0.2", + "intelli-espower-loader": "~0.6", + "mocha": "~2.2", + "power-assert": "~0.10", + "testem": "~0.7", + "uglify-js": "~2.4" + }, + "gitHead": "6fffac0b35e82d5ae67b756f6955f28d10f0fac1", + "bugs": { + "url": "https://github.com/sasaplus1/deepcopy.js/issues" + }, + "homepage": "https://github.com/sasaplus1/deepcopy.js", + "_id": "deepcopy@0.5.0", + "_shasum": "d2ca34335c2d31f54c1b4f13745e001977d491a2", + "_from": "deepcopy@*", + "_npmVersion": "2.7.5", + "_nodeVersion": "1.6.4", + "_npmUser": { + "name": "sasaplus1", + "email": "sasaplus1@gmail.com" + }, + "maintainers": [ + { + "name": "sasaplus1", + "email": "sasaplus1@gmail.com" + } + ], + "dist": { + "shasum": "d2ca34335c2d31f54c1b4f13745e001977d491a2", + "tarball": "http://registry.npmjs.org/deepcopy/-/deepcopy-0.5.0.tgz" + }, + "_resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-0.5.0.tgz", + "readme": "ERROR: No README data found!" +} diff --git a/packages/planner/node_modules/deepcopy/testem.json b/packages/planner/node_modules/deepcopy/testem.json new file mode 100644 index 00000000..d49cd811 --- /dev/null +++ b/packages/planner/node_modules/deepcopy/testem.json @@ -0,0 +1,5 @@ +{ + "before_tests": "npm run power", + "on_exit": "rm ./test/test.pwr.js", + "test_page": "./test/index.html" +} From 8c26c2e917f95403fc291a3f1e303ddd9e16b2a9 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Wed, 26 Aug 2015 20:53:48 +0200 Subject: [PATCH 08/18] Finally something works --- packages/planner/planner.js | 205 ++++++++++++++++++++++++++++------- packages/planner/testtest.js | 18 +++ 2 files changed, 186 insertions(+), 37 deletions(-) create mode 100755 packages/planner/testtest.js diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 275b272d..0da3e518 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -4,16 +4,22 @@ * @module planner */ +var deepcopy=require("deepcopy"); + var assert = function (val) { if (!val) throw new Error("AssertionError: false == true"); }; +function subjectGrade(subjid){ + return Math.random()*9+1; //TODO:: Get average grade of student for this subject +} + HomeworkDescription=function(){ - if(!(this instanceof HomeworkDescription))return new HomeworkDescription; + if(!(this instanceof HomeworkDescription))return new HomeworkDescription(arguments[0],arguments[1],arguments[2]); //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type - // and unique and fixed, i.e. there is only one identifier per subject and only one subject per identifier. - this.subject=null; + // and unique and fixed, i.e. there is only one identifier per subject and only one subject per identifier. + this.subject=arguments.length>0?arguments[0]:null; //Items in `location` can be multiple things, e.g. //- [chapter,paragraph,exercise] @@ -21,14 +27,22 @@ HomeworkDescription=function(){ //- [chapter,exercise] //- [bookid,page] //In general, anything that can be expressed in a sequence of integers that specifies the location. + // (Actually, they should be index paths — think NSIndexPath) //The `location` property contains an array of those, because homework can be multiple exercises, for example. //Please make the array contiguous, though; don't mix indexing conventions! (!) (!!) - this.location=[]; -} + this.location=arguments.length>1?arguments[1]:[]; + + //A Date indicating when this homework is due + this.duedate=arguments.length>2?arguments[2]:null; +}; Planner=function(){ - if(!(this instanceof Planner))return new Planner; + if(!(this instanceof Planner))return new Planner(arguments[0]); + this.isPlannerObject=true; + + //PREV: Object[subject id][location index path item][value of the loc. idxp. item][samples of time taken] + //Object[subject id][loc item 0][loc item 1]...[loc item n] = time taken for that index path var subjects={}; //The Cache //`timetaken` in any unit you find convenient; but please be consistent. Suggestion: seconds. @@ -39,40 +53,144 @@ Planner=function(){ loc=hwdesc.location; assert(loc.length!=0); if(!subjects[subj]){ - subjects[subj]=new Array(loc[0].length); - for(i=0;i Date: Thu, 27 Aug 2015 21:47:41 +0200 Subject: [PATCH 09/18] deepcopy -> lodash We already have lodash included in the app, so that means less code needed to be included. --- packages/planner/.gitignore | 1 + .../planner/node_modules/deepcopy/.npmignore | 4 - .../planner/node_modules/deepcopy/HISTORY.md | 46 - .../planner/node_modules/deepcopy/LICENSE | 21 - .../planner/node_modules/deepcopy/README.md | 156 - .../planner/node_modules/deepcopy/bower.json | 14 - .../bower_components/es5-shim/.bower.json | 43 - .../bower_components/es5-shim/CHANGES | 176 - .../bower_components/es5-shim/CONTRIBUTORS.md | 27 - .../bower_components/es5-shim/LICENSE | 22 - .../bower_components/es5-shim/Makefile | 23 - .../bower_components/es5-shim/README.md | 167 - .../bower_components/es5-shim/bower.json | 34 - .../bower_components/es5-shim/component.json | 19 - .../bower_components/es5-shim/es5-sham.js | 496 - .../bower_components/es5-shim/es5-sham.map | 1 - .../bower_components/es5-shim/es5-sham.min.js | 7 - .../bower_components/es5-shim/es5-shim.js | 1435 -- .../bower_components/es5-shim/es5-shim.map | 1 - .../bower_components/es5-shim/es5-shim.min.js | 7 - .../bower_components/es5-shim/package.json | 74 - .../bower_components/es5-shim/shims.json | 7 - .../bower_components/mocha/.bower.json | 56 - .../bower_components/mocha/.editorconfig | 18 - .../deepcopy/bower_components/mocha/.mailmap | 1 - .../bower_components/mocha/CONTRIBUTING.md | 49 - .../bower_components/mocha/HISTORY.md | 801 -- .../deepcopy/bower_components/mocha/LICENSE | 22 - .../deepcopy/bower_components/mocha/README.md | 226 - .../bower_components/mocha/bower.json | 47 - .../bower_components/mocha/media/logo.svg | 7 - .../deepcopy/bower_components/mocha/mocha.css | 270 - .../deepcopy/bower_components/mocha/mocha.js | 6298 --------- .../bower_components/power-assert/.bower.json | 56 - .../power-assert/CHANGELOG.md | 217 - .../power-assert/MIT-LICENSE.txt | 20 - .../bower_components/power-assert/README.md | 982 -- .../bower_components/power-assert/bower.json | 46 - .../power-assert/build/power-assert.js | 11647 ---------------- .../planner/node_modules/deepcopy/deepcopy.js | 229 - .../node_modules/deepcopy/package.json | 69 - .../planner/node_modules/deepcopy/testem.json | 5 - packages/planner/package.js | 8 +- packages/planner/package.json | 14 + packages/planner/planner.js | 10 +- 45 files changed, 25 insertions(+), 23854 deletions(-) create mode 100644 packages/planner/.gitignore delete mode 100644 packages/planner/node_modules/deepcopy/.npmignore delete mode 100644 packages/planner/node_modules/deepcopy/HISTORY.md delete mode 100644 packages/planner/node_modules/deepcopy/LICENSE delete mode 100644 packages/planner/node_modules/deepcopy/README.md delete mode 100644 packages/planner/node_modules/deepcopy/bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/CONTRIBUTORS.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/LICENSE delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/Makefile delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/README.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/component.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.js delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.map delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-sham.min.js delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.js delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.map delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/es5-shim.min.js delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/package.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/es5-shim/shims.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.editorconfig delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/.mailmap delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/CONTRIBUTING.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/HISTORY.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/LICENSE delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/README.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/media/logo.svg delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/mocha.css delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/mocha/mocha.js delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/.bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/CHANGELOG.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/MIT-LICENSE.txt delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/README.md delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json delete mode 100644 packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js delete mode 100644 packages/planner/node_modules/deepcopy/deepcopy.js delete mode 100644 packages/planner/node_modules/deepcopy/package.json delete mode 100644 packages/planner/node_modules/deepcopy/testem.json create mode 100644 packages/planner/package.json diff --git a/packages/planner/.gitignore b/packages/planner/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/packages/planner/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/planner/node_modules/deepcopy/.npmignore b/packages/planner/node_modules/deepcopy/.npmignore deleted file mode 100644 index 7cd09eab..00000000 --- a/packages/planner/node_modules/deepcopy/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -deepcopy.min.js -.closurelinter -.travis.yml -test/ diff --git a/packages/planner/node_modules/deepcopy/HISTORY.md b/packages/planner/node_modules/deepcopy/HISTORY.md deleted file mode 100644 index ab2105d3..00000000 --- a/packages/planner/node_modules/deepcopy/HISTORY.md +++ /dev/null @@ -1,46 +0,0 @@ -# 0.5.0 / 2015-04-11 - - - supported for Symbol - -# 0.4.0 / 2015-01-10 - - - refactored - - bugfix for Firefox - - supported for Buffer (node.js only) - - changed to use power-assert from expect.js - -# 0.3.3 / 2013-12-03 - - - bugfix - - thanks to @kjirou - -# 0.3.2 / 2013-09-08 - - - more compressed deepcopy.min.js - - changed from chai to expect.js - -# 0.3.1 / 2013-06-12 - - - changed from Array#indexOf to indexOfArray - -# 0.3.0 / 2013-06-01 - - - added support for browser - - changed repository name to deepcopy.js from deepcopy - -# 0.2.0 / 2013-05-26 - - - added support for circular reference - - rewrote README.md - -# 0.1.2 / 2013-03-29 - - - added support for node.js 0.10 - -# 0.1.1 / 2013-01-28 - - - rewrote README.md - -# 0.1.0 / 2013-01-26 - - - initial release diff --git a/packages/planner/node_modules/deepcopy/LICENSE b/packages/planner/node_modules/deepcopy/LICENSE deleted file mode 100644 index 95dccda6..00000000 --- a/packages/planner/node_modules/deepcopy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -(The MIT LICENSE) - -Copyright (c) 2013 sasa+1 - -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 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. diff --git a/packages/planner/node_modules/deepcopy/README.md b/packages/planner/node_modules/deepcopy/README.md deleted file mode 100644 index f2ea14aa..00000000 --- a/packages/planner/node_modules/deepcopy/README.md +++ /dev/null @@ -1,156 +0,0 @@ -# deepcopy.js - -[![Build Status](https://travis-ci.org/sasaplus1/deepcopy.js.svg)](https://travis-ci.org/sasaplus1/deepcopy.js) -[![Dependency Status](https://gemnasium.com/sasaplus1/deepcopy.js.svg)](https://gemnasium.com/sasaplus1/deepcopy.js) -[![NPM version](https://badge.fury.io/js/deepcopy.svg)](http://badge.fury.io/js/deepcopy) -[![Bower version](https://badge.fury.io/bo/deepcopy.svg)](http://badge.fury.io/bo/deepcopy) - -deep copy for any data - -## Installation - -### npm - -```sh -$ npm install deepcopy -``` - -### bower - -```sh -$ bower install deepcopy -``` - -## Usage - -### node.js - -```js -var deepcopy = require('deepcopy'); -``` - -### browser - -```html - -``` - -define `deepcopy` by `define()` if using AMD loader. - -otherwise `deepcopy` export to global. - -### Example - -```js -var data, shallow, deep; - -data = { - objects: { - array: [ - null, undefined, new Date, /deepcopy/ig - ], - object: { - number: NaN, - string: 'A', - boolean: true - }, - to: null - } -}; - -// circular reference -data.objects.to = data; - -// shallow copy and deep copy -shallow = data; -deep = deepcopy(data); - -// remove entry -delete data.objects; - -// results -console.log(data); -// {} -console.log(shallow); -// {} -console.log(require('util').inspect(deep, { depth: null })); -// { objects: -// { array: -// [ null, -// undefined, -// Sat Jan 10 2015 03:18:32 GMT+0900 (JST), -// /deepcopy/gi ], -// object: { number: NaN, string: 'A', boolean: true }, -// to: [Circular] } } -``` - -```js -var data, deep; - -data = { object: {} }; -data.object[Symbol.for('sym')] = 123; - -deep = deepcopy(data); - -delete data.object; - -console.log(data.object); -// undefined -console.log(deep.object[Symbol.for('sym')]); -// 123 -``` - -## Functions - -### deepcopy(value) - -* `value` - * `*` - copy target value -* `return` - * `*` - deep copied value - -return deep copied value. - -supported types are below: - -* Number -* String -* Boolean -* Null -* Undefined -* Function (shallow copy) -* Date -* RegExp -* Array - * recursive copy - * also can copy if it has circular reference -* Object - * recursive copy - * also can copy if it has circular reference -* Buffer (node.js only) -* Symbol - -## Test - -### node.js - -```sh -$ npm install -$ npm test -``` - -### browser - -```sh -$ npm install -$ npm run bower -$ npm run testem -``` - -## Contributors - -* [kjirou](https://github.com/kjirou) - -## License - -The MIT license. Please see LICENSE file. diff --git a/packages/planner/node_modules/deepcopy/bower.json b/packages/planner/node_modules/deepcopy/bower.json deleted file mode 100644 index 8cc555c6..00000000 --- a/packages/planner/node_modules/deepcopy/bower.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "deepcopy", - "main": "./deepcopy.min.js", - "ignore": [ - "**/.*", - "node_modules", - "bower_components" - ], - "devDependencies": { - "es5-shim": "~4.0", - "mocha": "~2.1", - "power-assert": "~0.10" - } -} diff --git a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json deleted file mode 100644 index a856b1f8..00000000 --- a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/.bower.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "es5-shim", - "version": "4.0.6", - "main": "es5-shim.js", - "repository": { - "type": "git", - "url": "git://github.com/es-shims/es5-shim" - }, - "homepage": "https://github.com/es-shims/es5-shim", - "authors": [ - "Kris Kowal (http://github.com/kriskowal/)", - "Sami Samhuri (http://samhuri.net/)", - "Florian Schäfer (http://github.com/fschaefer)", - "Irakli Gozalishvili (http://jeditoolkit.com)", - "Kit Cambridge (http://kitcambridge.github.com)", - "Jordan Harband (https://github.com/ljharb/)" - ], - "description": "ECMAScript 5 compatibility shims for legacy JavaScript engines", - "keywords": [ - "shim", - "es5", - "es5 shim", - "javascript", - "ecmascript", - "polyfill" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "tests" - ], - "_release": "4.0.6", - "_resolution": { - "type": "version", - "tag": "v4.0.6", - "commit": "aeb6b1cc477d1f452f0badff4631aba9ba501562" - }, - "_source": "git://github.com/es-shims/es5-shim.git", - "_target": "~4.0", - "_originalSource": "es5-shim" -} \ No newline at end of file diff --git a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES b/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES deleted file mode 100644 index d5480c48..00000000 --- a/packages/planner/node_modules/deepcopy/bower_components/es5-shim/CHANGES +++ /dev/null @@ -1,176 +0,0 @@ -4.0.6 - - Update `jscs`, `uglify-js`, add `eslint` - - es5-sham: fix Object.defineProperty to not check for own properties (#211) - - Fix Array#splice bug in Safari 5 (#284) - - Fix `Object.keys` issue with boxed primitives with extra properties in older browsers. (#242, #285) - -4.0.5 - - Update `jscs` so tests pass - -4.0.4 - - Style/indentation/whitespace cleanups. - - README tweaks - -4.0.3 - - Fix keywords (#268) - - add some Date tests - - Note in README that the es5-sham requires the es5-shim (https://github.com/es-shims/es5-shim/issues/256#issuecomment-52875710) - -4.0.2 - - Start including version numbers in minified files (#267) - -4.0.1 - - Fix legacy arguments object detection in Object.keys (#260) - -4.0.0 - - No longer shim the ES5-spec behavior of splice when `deleteCount` is omitted - since no engines implement it, and ES6 changes it. (#255) - - Use Object.defineProperty where available, so that polyfills are non-enumerable when possible (#250) - - lots of internal refactoring - - Fixed a bug referencing String#indexOf and String#lastIndexOf before polyfilling it (#253, #254) - -3.4.0 - - Removed nonstandard SpiderMonkey extension to Array#splice - when `deleteCount` is omitted, it's now treated as 0. (#192, #239) - - Fix Object.keys with Arguments objects in Safari 5.0 - - Now shimming String#split in Opera 10.6 - - Avoid using "toString" as a variable name, since that breaks Opera - - Internal implementation and test cleanups - -3.3.2 - - Remove an internal "bind" call, which should make the shim a bit faster - - Fix a bug with object boxing in Array#reduceRight that was failing a test in IE 6 - -3.3.1 - - Fixing an Array#splice bug in IE 6/7 - - cleaning up Array#splice tests - -3.3.0 - - Fix Array#reduceRight in node 0.6 and older browsers (#238) - -3.2.0 - - Fix es5-sham UMD definition to work properly with AMD (#237) - - Ensure that Array methods do not autobox context in strict mode (#233) - -3.1.1 - - Update minified files (#231) - -3.1.0 - - Fix String#replace in Firefox up through 29 (#228) - -3.0.2 - - Fix `Function#bind` in IE 7 and 8 (#224, #225, #226) - -3.0.1 - - Version bump to ensure npm has newest minified assets - -3.0.0 - - es5-sham: fix `Object.getPrototypeOf` and `Object.getOwnPropertyDescriptor` for Opera Mini - - Better override noncompliant native ES5 methods: `Array#forEach`, `Array#map`, `Array#filter`, `Array#every`, `Array#some`, `Array#reduce`, `Date.parse`, `String#trim` - - Added spec-compliant shim for `parseInt` - - Ensure `Object.keys` handles more edge cases with `arguments` objects and boxed primitives - - Improve minification of builds - -2.3.0 - - parseInt is now properly shimmed in ES3 browsers to default the radix - - update URLs to point to the new organization - -2.2.0 - - Function.prototype.bind shim now reports correct length on a bound function - - fix node 0.6.x v8 bug in Array#forEach - - test improvements - -2.1.0 - - Object.create fixes - - tweaks to the Object.defineProperties shim - -2.0.0 - - Separate reliable shims from dubious shims (shams). - -1.2.10 - - Group-effort Style Cleanup - - Took a stab at fixing Object.defineProperty on IE8 without - bad side-effects. (@hax) - - Object.isExtensible no longer fakes it. (@xavierm) - - Date.prototype.toISOString no longer deals with partial - ISO dates, per spec (@kitcambridge) - - More (mostly from @bryanforbes) - -1.2.9 - - Corrections to toISOString by @kitcambridge - - Fixed three bugs in array methods revealed by Jasmine tests. - - Cleaned up Function.prototype.bind with more fixes and tests from - @bryanforbes. - -1.2.8 - - Actually fixed problems with Function.prototype.bind, and regressions - from 1.2.7 (@bryanforbes, @jdalton #36) - -1.2.7 - REGRESSED - - Fixed problems with Function.prototype.bind when called as a constructor. - (@jdalton #36) - -1.2.6 - - Revised Date.parse to match ES 5.1 (kitcambridge) - -1.2.5 - - Fixed a bug for padding it Date..toISOString (tadfisher issue #33) - -1.2.4 - - Fixed a descriptor bug in Object.defineProperty (raynos) - -1.2.3 - - Cleaned up RequireJS and - -Then, generate espowered code. - - $ espower test/your_test.js > powered/your_test.js - -Lastly, run your test in your way. For example, - - $ mocha-phantomjs path/to/test.html - - - -### using `grunt-espower` - -On the browser side and you are not using [browserify](http://browserify.org/) but [bower](http://bower.io/) and [Grunt](http://gruntjs.com/), you can use `power-assert` via bower, with generated code by `grunt-espower` - -First, install `power-assert` via bower and `grunt-espower` via npm. This means that you run grunt (on Node), then run tests on browser. - - $ bower install --save-dev power-assert - $ npm install --save-dev grunt-espower - -Second, require `build/power-assert.js` (all-in-one build for browsers) in your test html. - - - -Third, configure `grunt-espower` task to generate espowered code. - -```javascript -grunt.initConfig({ - - . . . - - espower: { - test: { - files: [ - { - expand: true, // Enable dynamic expansion. - cwd: 'test/', // Src matches are relative to this path. - src: ['**/*.js'], // Actual pattern(s) to match. - dest: 'espowered/', // Destination path prefix. - ext: '.js' // Dest filepaths will have this extension. - } - ] - }, - }, - - . . . - -}) -``` - -Then, generate espowered code using `espower` task. - - $ grunt espower:test - -Lastly, run your test in your way. For example, - - $ grunt test - - - - -### using `gulp-espower` - -On the browser side and you are not using [browserify](http://browserify.org/) but [bower](http://bower.io/) and [gulp](http://gulpjs.com/), you can use `power-assert` via bower, with generated code by `gulp-espower` - -First, install `power-assert` via bower and `gulp-espower` via npm. This means that you run gulp (on Node), then run tests on browser. - - $ bower install --save-dev power-assert - $ npm install --save-dev gulp-espower - -Second, require `build/power-assert.js` (all-in-one build for browsers) in your test html. - - - -Third, configure `gulp-espower` task to generate espowered code. - -```javascript -var gulp = require('gulp'), - espower = require('gulp-espower'); - . . . -gulp.task('espower', function() { - return gulp - .src('test/**/*_test.js', {base: './test/'}) - .pipe(espower()) - .pipe(gulp.dest('espowered')); -}); - . . . -}) -``` - -Then, generate espowered code (in this example, using `espower` task). - - $ gulp espower - -Lastly, run your test in your way. For example, - - $ gulp test - - - - -CUSTOMIZATION API ---------------------------------------- - -`power-assert` provides an API for customization. - -### var assert = assert.customize(options) - -Through this API, you can customize power-assert by changing some options. - -```javascript -var assert = require('power-assert').customize({ - output: { - maxDepth: 2 - } -}); -``` - -### options - -`options` has two top-level keys. `assertion` and `output`. - -#### options.assertion - -customization options for [empower](http://github.com/twada/empower) module. See [empower API documentation](https://github.com/twada/empower#api) for details. Note that some default values are different from `empower`'s (`modifyMessageOnRethrow: true` and `saveContextOnRethrow: true`). - -#### options.output - -customization options for [power-assert-formatter](http://github.com/twada/power-assert-formatter) module. See [power-assert-formatter API documentation](https://github.com/twada/power-assert-formatter#api) for details. - -#### default values - -customizable properties and their default values are as follows. - -``` -var assert = require('power-assert').customize({ - assertion: { - destructive: false, - modifyMessageOnRethrow: true, - saveContextOnRethrow: true, - patterns: [ - 'assert(value, [message])', - 'assert.ok(value, [message])', - 'assert.equal(actual, expected, [message])', - 'assert.notEqual(actual, expected, [message])', - 'assert.strictEqual(actual, expected, [message])', - 'assert.notStrictEqual(actual, expected, [message])', - 'assert.deepEqual(actual, expected, [message])', - 'assert.notDeepEqual(actual, expected, [message])' - ] - }, - output: { - lineDiffThreshold: 5, - maxDepth: 1, - anonymous: 'Object', - circular: '#@Circular#', - lineSeparator: '\n', - ambiguousEastAsianCharWidth: 2, - widthOf: (Function to calculate width of string. Please see power-assert-formatter's documentation) - stringify: (Function to stringify any target value. Please see power-assert-formatter's documentation) - diff: (Function to create diff string between two strings. Please see power-assert-formatter's documentation) - writerClass: (Constructor Function for output writer class. Please see power-assert-formatter's documentation) - renderers: [ - './built-in/file', - './built-in/assertion', - './built-in/diagram', - './built-in/binary-expression' - ] - } -}); -``` - - -INTERNAL DESIGN ---------------------------------------- - -`power-assert` family provides 1 main module, 4 core modules and many more instrumentors. - - -Main (facade) module is, - -| module | description | -|:-------|:------------| -| [power-assert](http://github.com/twada/power-assert) | Standard `assert` function on top of `empower` and `power-assert-formatter` | - -core modules are, - -| module | description | -|:-------|:------------| -| [empower](http://github.com/twada/empower) | Power Assert feature enhancer for assert function/object. | -| [power-assert-formatter](http://github.com/twada/power-assert-formatter) | Power Assert output formatter. | -| [espower](http://github.com/twada/espower) | Power Assert feature instrumentor core based on the [Mozilla JavaScript AST](https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API). | -| [espower-source](http://github.com/twada/espower-source) | Power Assert instrumentor from source to source, with source-map. (Thin wrapper of `espower`). | - -and instrumentors are, - -| module | description | -|:-------|:------------| -| [espower-cli](http://github.com/twada/espower-cli) | Command line tool for power-assert. | -| [espower-loader](http://github.com/twada/espower-loader) | Node module loader to apply `espower` on the fly. | -| [intelli-espower-loader](https://github.com/azu/intelli-espower-loader) | configure `espower-loader` with ease. | -| [espowerify](http://github.com/twada/espowerify) | [Browserify](http://browserify.org/) transform to apply `espower` to target files. | -| [webpack-espower-loader](https://github.com/zoncoen/webpack-espower-loader) | Power Assert instrumentor module for [webpack](http://webpack.github.io/). | -| [grunt-espower](http://github.com/twada/grunt-espower) | Grunt task to apply `espower` to target files. | -| [gulp-espower](http://github.com/twada/gulp-espower) | Gulp plugin to apply `espower` to target files. | -| [karma-espower-preprocessor](https://github.com/vvakame/karma-espower-preprocessor) | karma-preprocessor for power-assert. | -| [espower-coffee](http://github.com/twada/espower-coffee) | power-assert instrumentor for CoffeeScript. | -| [espower-traceur](https://github.com/yosuke-furukawa/espower-traceur) | power-assert instrumentor for ES6 using [Traceur Compiler](https://github.com/google/traceur-compiler/). | -| [espower-babel](https://github.com/azu/espower-babel) | power-assert instrumentor for ES6 using [Babel](https://babeljs.io/). | - - -`power-assert` provides standard [assert](http://nodejs.org/api/assert.html) compatible function with Power Assert feature. -(Best fit with [Mocha](http://visionmedia.github.io/mocha/). If you use assert-like objects provided by various testing frameworks such as [QUnit](http://qunitjs.com/) or [nodeunit](https://github.com/caolan/nodeunit). Please use [empower](http://github.com/twada/empower) and [power-assert-formatter](http://github.com/twada/power-assert-formatter) modules directly). - - -Internally, `power-assert` uses [empower](http://github.com/twada/empower) module to enhance power assert feature into the standard [assert](http://nodejs.org/api/assert.html) module, to run with the power assert feature added code by [espower](http://github.com/twada/espower) module, and prettify output using [power-assert-formatter](http://github.com/twada/power-assert-formatter). - - -See [power-assert-demo](http://github.com/twada/power-assert-demo) project for power-assert Demo running with mocha. - - -TESTED FRAMEWORKS ---------------------------------------- -* [Mocha](http://visionmedia.github.io/mocha/) -* [QUnit](http://qunitjs.com/) -* [nodeunit](https://github.com/caolan/nodeunit) -* [buster-assertions](http://docs.busterjs.org/en/latest/modules/buster-assertions/) - - -TESTED ENVIRONMENTS ---------------------------------------- -* [Node.js](http://nodejs.org/) -* [Rhino](https://developer.mozilla.org/en/Rhino) -* [PhantomJS](http://phantomjs.org/) -* [RequireJS](http://requirejs.org/) -* [Browserify](http://browserify.org/) - - -AUTHOR ---------------------------------------- -* [Takuto Wada](http://github.com/twada) - - -CONTRIBUTORS ---------------------------------------- -* [azu](https://github.com/azu) -* [vvakame](https://github.com/vvakame) - - -LICENSE ---------------------------------------- -Licensed under the [MIT](https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt) license. - - - -MORE OUTPUT EXAMPLES ---------------------------------------- - -### Target test code (using QUnit in this example) - -```javascript -var q = require('qunitjs'); - -(function () { - var empower = require('empower'), - formatter = require('power-assert-formatter'), - qunitTap = require("qunit-tap"); - empower(q.assert, formatter(), {destructive: true}); - qunitTap(q, require('util').puts, {showSourceOnFailure: false}); - q.config.autorun = false; -})(); - -q.test('spike', function (assert) { - assert.ok(true); - - var hoge = 'foo'; - var fuga = 'bar'; - assert.ok(hoge === fuga, 'comment'); - - var piyo = 3; - assert.ok(fuga === piyo); - - var longString = 'very very loooooooooooooooooooooooooooooooooooooooooooooooooooong message'; - var anotherLongString = 'yet another loooooooooooooooooooooooooooooooooooooooooooooooooooong message'; - assert.ok(longString === anotherLongString); - - assert.ok(4 === piyo); - - assert.ok(4 !== 4); - - var falsyStr = ''; - assert.ok(falsyStr); - - var falsyNum = 0; - assert.ok(falsyNum); - - var ary1 = ['foo', 'bar']; - var ary2 = ['aaa', 'bbb', 'ccc']; - assert.ok(ary1.length === ary2.length); - assert.deepEqual(ary1, ary2); - - var actual = 16; - assert.ok(5 < actual && actual < 13); - - actual = 4; - assert.ok(5 < actual && actual < 13); - - actual = 10; - assert.ok(actual < 5 || 13 < actual); - - - var propName = 'bar', - foo = { - bar: { - baz: false - } - }; - - assert.ok(foo.bar.baz); - assert.ok(foo['bar'].baz); - assert.ok(foo[propName]['baz']); - - - var truth = true; - assert.ok(!truth); - - - var func = function () { return false; }; - assert.ok(func()); - - - var obj = { - age: function () { - return 0; - } - }; - assert.ok(obj.age()); - - - var isFalsy = function (arg) { - return !(arg); - }; - var positiveInt = 50; - assert.ok(isFalsy(positiveInt)); - - - var sum = function () { - var result = 0; - for (var i = 0; i < arguments.length; i += 1) { - result += arguments[i]; - } - return result; - }; - var one = 1, two = 2, three = 3, seven = 7, ten = 10; - assert.ok(sum(one, two, three) === seven); - assert.ok(sum(sum(one, two), three) === sum(sum(two, three), seven)); - assert.ok((three * (seven * ten)) === three); - - - var math = { - calc: { - sum: function () { - var result = 0; - for (var i = 0; i < arguments.length; i += 1) { - result += arguments[i]; - } - return result; - } - } - }; - assert.ok(math.calc.sum(one, two, three) === seven); -}); - -q.load(); -``` - - -### `espower` code above then running under Node.js - -``` -# module: undefined -# test: spike -ok 1 - okay -not ok 2 - comment # /path/to/examples/qunit_node.js:17 -# -# assert.ok(hoge === fuga, 'comment') -# | | | -# | | "bar" -# | false -# "foo" -# -# --- [string] fuga -# +++ [string] hoge -# @@ -1,3 +1,3 @@ -# -bar -# +foo -# -# , test: spike -not ok 3 - # /path/to/examples/qunit_node.js:20 -# -# assert.ok(fuga === piyo) -# | | | -# | | 3 -# | false -# "bar" -# -# [number] piyo -# => 3 -# [string] fuga -# => "bar" - -# , test: spike -not ok 4 - # /path/to/examples/qunit_node.js:24 -# -# assert.ok(longString === anotherLongString) -# | | | -# | | "yet another loooooooooooooooooooooooooooooooooooooooooooooooooooong message" -# | false -# "very very loooooooooooooooooooooooooooooooooooooooooooooooooooong message" -# -# --- [string] anotherLongString -# +++ [string] longString -# @@ -1,15 +1,13 @@ -# -yet anoth -# +very v -# er -# +y -# loo -# -# , test: spike -not ok 5 - # /path/to/examples/qunit_node.js:26 -# -# assert.ok(4 === piyo) -# | | -# | 3 -# false -# -# [number] piyo -# => 3 -# [number] 4 -# => 4 -# , test: spike -not ok 6 - # /path/to/examples/qunit_node.js:28 -# -# assert.ok(4 !== 4) -# | -# false -# , test: spike -not ok 7 - # /path/to/examples/qunit_node.js:31 -# -# assert.ok(falsyStr) -# | -# "" -# , test: spike -not ok 8 - # /path/to/examples/qunit_node.js:34 -# -# assert.ok(falsyNum) -# | -# 0 -# , test: spike -not ok 9 - # /path/to/examples/qunit_node.js:38 -# -# assert.ok(ary1.length === ary2.length) -# | | | | | -# | | | | 3 -# | | | ["aaa","bbb","ccc"] -# | 2 false -# ["foo","bar"] -# -# [number] ary2.length -# => 3 -# [number] ary1.length -# => 2 -# , test: spike -not ok 10 - # /path/to/examples/qunit_node.js:39 -# -# assert.deepEqual(ary1, ary2) -# | | -# | ["aaa","bbb","ccc"] -# ["foo","bar"] -# , expected: [ -# "aaa", -# "bbb", -# "ccc" -# ], got: [ -# "foo", -# "bar" -# ], test: spike -not ok 11 - # /path/to/examples/qunit_node.js:42 -# -# assert.ok(5 < actual && actual < 13) -# | | | | | -# | | | 16 false -# | 16 false -# true -# , test: spike -not ok 12 - # /path/to/examples/qunit_node.js:45 -# -# assert.ok(5 < actual && actual < 13) -# | | | -# | 4 false -# false -# , test: spike -not ok 13 - # /path/to/examples/qunit_node.js:48 -# -# assert.ok(actual < 5 || 13 < actual) -# | | | | | -# | | | | 10 -# | | false false -# 10 false -# , test: spike -not ok 14 - # /path/to/examples/qunit_node.js:58 -# -# assert.ok(foo.bar.baz) -# | | | -# | | false -# | Object{baz:false} -# Object{bar:#Object#} -# , test: spike -not ok 15 - # /path/to/examples/qunit_node.js:59 -# -# assert.ok(foo['bar'].baz) -# | | | -# | | false -# | Object{baz:false} -# Object{bar:#Object#} -# , test: spike -not ok 16 - # /path/to/examples/qunit_node.js:60 -# -# assert.ok(foo[propName]['baz']) -# | || | -# | |"bar" false -# | Object{baz:false} -# Object{bar:#Object#} -# , test: spike -not ok 17 - # /path/to/examples/qunit_node.js:64 -# -# assert.ok(!truth) -# || -# |true -# false -# , test: spike -not ok 18 - # /path/to/examples/qunit_node.js:68 -# -# assert.ok(func()) -# | -# false -# , test: spike -not ok 19 - # /path/to/examples/qunit_node.js:76 -# -# assert.ok(obj.age()) -# | | -# | 0 -# Object{age:#function#} -# , test: spike -not ok 20 - # /path/to/examples/qunit_node.js:83 -# -# assert.ok(isFalsy(positiveInt)) -# | | -# false 50 -# , test: spike -not ok 21 - # /path/to/examples/qunit_node.js:94 -# -# assert.ok(sum(one, two, three) === seven) -# | | | | | | -# | | | | | 7 -# 6 1 2 3 false -# -# [number] seven -# => 7 -# [number] sum(one, two, three) -# => 6 -# , test: spike -not ok 22 - # /path/to/examples/qunit_node.js:95 -# -# assert.ok(sum(sum(one, two), three) === sum(sum(two, three), seven)) -# | | | | | | | | | | | -# | | | | | | 12 5 2 3 7 -# 6 3 1 2 3 false -# -# [number] sum(sum(two, three), seven) -# => 12 -# [number] sum(sum(one, two), three) -# => 6 -# , test: spike -not ok 23 - # /path/to/examples/qunit_node.js:96 -# -# assert.ok(three * (seven * ten) === three) -# | | | | | | | -# | | | | | | 3 -# | | | | 10 false -# | | 7 70 -# 3 210 -# -# [number] three -# => 3 -# [number] three * (seven * ten) -# => 210 -# , test: spike -not ok 24 - # /path/to/examples/qunit_node.js:110 -# -# assert.ok(math.calc.sum(one, two, three) === seven) -# | | | | | | | | -# | | | | | | | 7 -# | | 6 1 2 3 false -# | Object{sum:#function#} -# Object{calc:#Object#} -# -# [number] seven -# => 7 -# [number] math.calc.sum(one, two, three) -# => 6 -# , test: spike -1..24 -``` - -Have fun! - - -[npm-url]: https://npmjs.org/package/power-assert -[npm-image]: https://badge.fury.io/js/power-assert.svg - -[bower-url]: http://badge.fury.io/bo/power-assert -[bower-image]: https://badge.fury.io/bo/power-assert.svg - -[travis-url]: http://travis-ci.org/twada/power-assert -[travis-image]: https://secure.travis-ci.org/twada/power-assert.svg?branch=master - -[depstat-url]: https://gemnasium.com/twada/power-assert -[depstat-image]: https://gemnasium.com/twada/power-assert.svg - -[license-url]: https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt -[license-image]: http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat diff --git a/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json b/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json deleted file mode 100644 index 5cf8cdf8..00000000 --- a/packages/planner/node_modules/deepcopy/bower_components/power-assert/bower.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "power-assert", - "description": "Power Assert in JavaScript", - "main": "build/power-assert.js", - "license": "MIT", - "ignore": [ - "**/.*", - "package.json", - "index.js", - "test", - "enable_power_assert.js" - ], - "keywords": [ - "power-assert", - "test", - "assert", - "testing", - "ecmascript", - "ast" - ], - "authors": [ - { - "name": "Takuto Wada", - "email": "takuto.wada@gmail.com", - "homepage": "https://github.com/twada" - }, - { - "name": "azu", - "url": "https://github.com/azu" - }, - { - "name": "vvakame", - "url": "https://github.com/vvakame" - } - ], - "homepage": "https://github.com/twada/power-assert", - "repository": { - "type": "git", - "url": "git://github.com/twada/power-assert.git" - }, - "devDependencies": { - "expect": "~0.3.1", - "mocha": "~2.1.0", - "requirejs": "~2.1.15" - } -} diff --git a/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js b/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js deleted file mode 100644 index 113289bb..00000000 --- a/packages/planner/node_modules/deepcopy/bower_components/power-assert/build/power-assert.js +++ /dev/null @@ -1,11647 +0,0 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.assert=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -// -// 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 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 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. - -// when used in node, this will actually load the util module we depend on -// versus loading the builtin util module as happens otherwise -// this is a bug in node module loading as far as I am concerned -var util = _dereq_('util/'); - -var pSlice = Array.prototype.slice; -var hasOwn = Object.prototype.hasOwnProperty; - -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; - } - var stackStartFunction = options.stackStartFunction || fail; - - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } - else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; - - // try to strip useless frames - var fn_name = stackStartFunction.name; - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); - } - - this.stack = out; - } - } -}; - -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); - -function replacer(key, value) { - if (util.isUndefined(value)) { - return '' + value; - } - if (util.isNumber(value) && !isFinite(value)) { - return value.toString(); - } - if (util.isFunction(value) || util.isRegExp(value)) { - return value.toString(); - } - return value; -} - -function truncate(s, n) { - if (util.isString(s)) { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} - -function getMessage(self) { - return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + - self.operator + ' ' + - truncate(JSON.stringify(self.expected, replacer), 128); -} - -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. - -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. - -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} - -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; - -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. - -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; - -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); - -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; - -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); - -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; - -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); - -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; - -function _deepEqual(actual, expected) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (util.isBuffer(actual) && util.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } - - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); - - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; - - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (!util.isObject(actual) && !util.isObject(expected)) { - return actual == expected; - - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected); - } -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b) { - if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) - return false; - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) { - return a === b; - } - var aIsArgs = isArguments(a), - bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b); - } - var ka = objectKeys(a), - kb = objectKeys(b), - key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key])) return false; - } - return true; -} - -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; - -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } -}; - -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; - -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } - - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } else if (actual instanceof expected) { - return true; - } else if (expected.call({}, actual) === true) { - return true; - } - - return false; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (util.isString(expected)) { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); - - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); - } - - if (!shouldThrow && expectedException(actual, expected)) { - fail(actual, expected, 'Got unwanted exception' + message); - } - - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} - -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); - -assert["throws"] = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [true].concat(pSlice.call(arguments))); -}; - -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/message) { - _throws.apply(this, [false].concat(pSlice.call(arguments))); -}; - -assert.ifError = function(err) { if (err) {throw err;}}; - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); - } - return keys; -}; - -},{"util/":6}],2:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 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. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}],3:[function(_dereq_,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} - -},{}],4:[function(_dereq_,module,exports){ -// shim for using process in browser - -var process = module.exports = {}; -var queue = []; -var draining = false; - -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; - } - draining = false; -} -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } -}; - -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}],5:[function(_dereq_,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],6:[function(_dereq_,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 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. - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; - - -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -}; - - -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; - - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; -} - - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = _dereq_('./support/isBuffer'); - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = _dereq_('inherits'); - -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":5,"_process":4,"inherits":3}],7:[function(_dereq_,module,exports){ -/** - * power-assert.js - Power Assert in JavaScript. - * - * https://github.com/twada/power-assert - * - * Copyright (c) 2013-2015 Takuto Wada - * Licensed under the MIT license. - * https://github.com/twada/power-assert/blob/master/MIT-LICENSE.txt - */ -'use strict'; - -var baseAssert = _dereq_('assert'), - empower = _dereq_('empower'), - formatter = _dereq_('power-assert-formatter'), - extend = _dereq_('xtend'), - empowerOptions = {modifyMessageOnRethrow: true, saveContextOnRethrow: true}; - -function customize (customOptions) { - var options = customOptions || {}; - var poweredAssert = empower( - baseAssert, - formatter(options.output), - extend(empowerOptions, options.assertion) - ); - poweredAssert.customize = customize; - return poweredAssert; -} - -module.exports = customize(); - -},{"assert":1,"empower":8,"power-assert-formatter":22,"xtend":45}],8:[function(_dereq_,module,exports){ -/** - * empower - Power Assert feature enhancer for assert function/object. - * - * https://github.com/twada/empower - * - * Copyright (c) 2013-2014 Takuto Wada - * Licensed under the MIT license. - * https://github.com/twada/empower/blob/master/MIT-LICENSE.txt - */ -var defaultOptions = _dereq_('./lib/default-options'), - Decorator = _dereq_('./lib/decorator'), - slice = Array.prototype.slice, - extend = _dereq_('xtend/mutable'); - -/** - * Enhance Power Assert feature to assert function/object. - * @param assert target assert function or object to enhance - * @param formatter power assert format function - * @param options enhancement options - * @return enhanced assert function/object - */ -function empower (assert, formatter, options) { - var typeOfAssert = (typeof assert), - config; - if ((typeOfAssert !== 'object' && typeOfAssert !== 'function') || assert === null) { - throw new TypeError('empower argument should be a function or object.'); - } - if (isEmpowered(assert)) { - return assert; - } - config = extend(defaultOptions(), options); - switch (typeOfAssert) { - case 'function': - return empowerAssertFunction(assert, formatter, config); - case 'object': - return empowerAssertObject(assert, formatter, config); - default: - throw new Error('Cannot be here'); - } -} - -function empowerAssertObject (assertObject, formatter, config) { - var target = config.destructive ? assertObject : Object.create(assertObject); - var decorator = new Decorator(target, formatter, config); - return extend(target, decorator.enhancement()); -} - -function empowerAssertFunction (assertFunction, formatter, config) { - if (config.destructive) { - throw new Error('cannot use destructive:true to function.'); - } - var decorator = new Decorator(assertFunction, formatter, config); - var enhancement = decorator.enhancement(); - var powerAssert; - if (typeof enhancement === 'function') { - powerAssert = function powerAssert () { - return enhancement.apply(null, slice.apply(arguments)); - }; - } else { - powerAssert = function powerAssert () { - return assertFunction.apply(null, slice.apply(arguments)); - }; - } - extend(powerAssert, assertFunction); - return extend(powerAssert, enhancement); -} - -function isEmpowered (assertObjectOrFunction) { - return (typeof assertObjectOrFunction._capt === 'function') && (typeof assertObjectOrFunction._expr === 'function'); -} - -empower.defaultOptions = defaultOptions; -module.exports = empower; - -},{"./lib/decorator":11,"./lib/default-options":12,"xtend/mutable":46}],9:[function(_dereq_,module,exports){ -'use strict'; - -module.exports = function capturable () { - var events = []; - - function _capt (value, espath) { - events.push({value: value, espath: espath}); - return value; - } - - function _expr (value, args) { - var captured = events; - events = []; - return { - powerAssertContext: { - value: value, - events: captured - }, - source: { - content: args.content, - filepath: args.filepath, - line: args.line - } - }; - } - - return { - _capt: _capt, - _expr: _expr - }; -}; - -},{}],10:[function(_dereq_,module,exports){ -'use strict'; - -var slice = Array.prototype.slice; - -function decorate (callSpec, decorator) { - var func = callSpec.func, - thisObj = callSpec.thisObj, - numArgsToCapture = callSpec.numArgsToCapture; - - return function decoratedAssert () { - var context, message, args = slice.apply(arguments); - - if (args.every(isNotCaptured)) { - return func.apply(thisObj, args); - } - - var values = args.slice(0, numArgsToCapture).map(function (arg) { - if (isNotCaptured(arg)) { - return arg; - } - if (!context) { - context = { - source: arg.source, - args: [] - }; - } - context.args.push({ - value: arg.powerAssertContext.value, - events: arg.powerAssertContext.events - }); - return arg.powerAssertContext.value; - }); - - if (numArgsToCapture === (args.length - 1)) { - message = args[args.length - 1]; - } - - var invocation = { - thisObj: thisObj, - func: func, - values: values, - message: message - }; - return decorator.concreteAssert(invocation, context); - }; -} - -function isNotCaptured (value) { - return !isCaptured(value); -} - -function isCaptured (value) { - return (typeof value === 'object') && - (value !== null) && - (typeof value.powerAssertContext !== 'undefined'); -} - -module.exports = decorate; - -},{}],11:[function(_dereq_,module,exports){ -'use strict'; - -var escallmatch = _dereq_('escallmatch'), - extend = _dereq_('xtend/mutable'), - capturable = _dereq_('./capturable'), - decorate = _dereq_('./decorate'); - - -function Decorator (receiver, formatter, config) { - this.receiver = receiver; - this.formatter = formatter; - this.config = config; - this.matchers = config.patterns.map(escallmatch); - this.eagerEvaluation = !(config.modifyMessageOnRethrow || config.saveContextOnRethrow); -} - -Decorator.prototype.enhancement = function () { - var that = this; - var container = this.container(); - this.matchers.filter(methodCall).forEach(function (matcher) { - var methodName = detectMethodName(matcher.calleeAst()); - if (typeof that.receiver[methodName] === 'function') { - var callSpec = { - thisObj: that.receiver, - func: that.receiver[methodName], - numArgsToCapture: numberOfArgumentsToCapture(matcher) - }; - container[methodName] = decorate(callSpec, that); - } - }); - extend(container, capturable()); - return container; -}; - -Decorator.prototype.container = function () { - var basement = {}; - if (typeof this.receiver === 'function') { - var candidates = this.matchers.filter(functionCall); - if (candidates.length === 1) { - var callSpec = { - thisObj: null, - func: this.receiver, - numArgsToCapture: numberOfArgumentsToCapture(candidates[0]) - }; - basement = decorate(callSpec, this); - } - } - return basement; -}; - -Decorator.prototype.concreteAssert = function (invocation, context) { - var func = invocation.func, - thisObj = invocation.thisObj, - args = invocation.values, - message = invocation.message; - if (this.eagerEvaluation) { - var poweredMessage = this.buildPowerAssertText(message, context); - return func.apply(thisObj, args.concat(poweredMessage)); - } - try { - return func.apply(thisObj, args.concat(message)); - } catch (e) { - throw this.errorToRethrow(e, message, context); - } -}; - -Decorator.prototype.errorToRethrow = function (e, originalMessage, context) { - if (e.name !== 'AssertionError') { - return e; - } - if (typeof this.receiver.AssertionError !== 'function') { - return e; - } - var f = new this.receiver.AssertionError({ - actual: e.actual, - expected: e.expected, - operator: e.operator, - message: this.config.modifyMessageOnRethrow ? this.buildPowerAssertText(originalMessage, context) : e.message, - stackStartFunction: Decorator.prototype.concreteAssert - }); - if (this.config.saveContextOnRethrow) { - f.powerAssertContext = context; - } - return f; -}; - -Decorator.prototype.buildPowerAssertText = function (message, context) { - var powerAssertText = this.formatter(context); - return message ? message + ' ' + powerAssertText : powerAssertText; -}; - - -function numberOfArgumentsToCapture (matcher) { - var argSpecs = matcher.argumentSignatures(), - len = argSpecs.length, - lastArg; - if (0 < len) { - lastArg = argSpecs[len - 1]; - if (lastArg.name === 'message' && lastArg.kind === 'optional') { - len -= 1; - } - } - return len; -} - - -function detectMethodName (node) { - if (node.type === 'MemberExpression') { - return node.property.name; - } - return null; -} - - -function functionCall (matcher) { - return matcher.calleeAst().type === 'Identifier'; -} - - -function methodCall (matcher) { - return matcher.calleeAst().type === 'MemberExpression'; -} - - -module.exports = Decorator; - -},{"./capturable":9,"./decorate":10,"escallmatch":13,"xtend/mutable":46}],12:[function(_dereq_,module,exports){ -'use strict'; - -module.exports = function defaultOptions () { - return { - destructive: false, - modifyMessageOnRethrow: false, - saveContextOnRethrow: false, - patterns: [ - 'assert(value, [message])', - 'assert.ok(value, [message])', - 'assert.equal(actual, expected, [message])', - 'assert.notEqual(actual, expected, [message])', - 'assert.strictEqual(actual, expected, [message])', - 'assert.notStrictEqual(actual, expected, [message])', - 'assert.deepEqual(actual, expected, [message])', - 'assert.notDeepEqual(actual, expected, [message])' - ] - }; -}; - -},{}],13:[function(_dereq_,module,exports){ -/** - * escallmatch: - * ECMAScript CallExpression matcher made from function/method signature - * - * https://github.com/twada/escallmatch - * - * Copyright (c) 2014 Takuto Wada - * Licensed under the MIT license. - * http://twada.mit-license.org/ - */ -'use strict'; -/* jshint -W024 */ - -var esprima = _dereq_('esprima'), - estraverse = _dereq_('estraverse'), - espurify = _dereq_('espurify'), - syntax = estraverse.Syntax, - hasOwn = Object.prototype.hasOwnProperty, - deepEqual = _dereq_('deep-equal'), - notCallExprMessage = 'Argument should be in the form of CallExpression', - duplicatedArgMessage = 'Duplicate argument name: ', - invalidFormMessage = 'Argument should be in the form of `name` or `[name]`'; - -function createMatcher (signatureStr) { - var ast = extractExpressionFrom(esprima.parse(signatureStr)); - return new Matcher(ast); -} - -function Matcher (signatureAst) { - this.signatureAst = signatureAst; - this.signatureCalleeDepth = astDepth(signatureAst.callee); - this.numMaxArgs = this.signatureAst.arguments.length; - this.numMinArgs = this.signatureAst.arguments.filter(identifiers).length; -} - -Matcher.prototype.test = function (currentNode) { - var calleeMatched = isCalleeMatched(this.signatureAst, this.signatureCalleeDepth, currentNode), - numArgs; - if (calleeMatched) { - numArgs = currentNode.arguments.length; - return this.numMinArgs <= numArgs && numArgs <= this.numMaxArgs; - } - return false; -}; - -Matcher.prototype.matchArgument = function (currentNode, parentNode) { - if (isCalleeOfParent(currentNode, parentNode)) { - return null; - } - if (this.test(parentNode)) { - var indexOfCurrentArg = parentNode.arguments.indexOf(currentNode); - var numOptional = parentNode.arguments.length - this.numMinArgs; - var matchedSignatures = this.argumentSignatures().reduce(function (accum, argSig) { - if (argSig.kind === 'mandatory') { - accum.push(argSig); - } - if (argSig.kind === 'optional' && 0 < numOptional) { - numOptional -= 1; - accum.push(argSig); - } - return accum; - }, []); - return matchedSignatures[indexOfCurrentArg]; - } - return null; -}; - -Matcher.prototype.calleeAst = function () { - return espurify(this.signatureAst.callee); -}; - -Matcher.prototype.argumentSignatures = function () { - return this.signatureAst.arguments.map(toArgumentSignature); -}; - -function toArgumentSignature (argSignatureNode) { - switch(argSignatureNode.type) { - case syntax.Identifier: - return { - name: argSignatureNode.name, - kind: 'mandatory' - }; - case syntax.ArrayExpression: - return { - name: argSignatureNode.elements[0].name, - kind: 'optional' - }; - default: - return null; - } -} - -function isCalleeMatched(callSignature, signatureCalleeDepth, node) { - if (!isCallExpression(node)) { - return false; - } - if (!isSameAstDepth(node.callee, signatureCalleeDepth)) { - return false; - } - return deepEqual(espurify(callSignature.callee), espurify(node.callee)); -} - -function isSameAstDepth (ast, depth) { - var currentDepth = 0; - estraverse.traverse(ast, { - enter: function (currentNode, parentNode) { - var path = this.path(), - pathDepth = path ? path.length : 0; - if (currentDepth < pathDepth) { - currentDepth = pathDepth; - } - if (depth < currentDepth) { - this['break'](); - } - } - }); - return (depth === currentDepth); -} - -function astDepth (ast) { - var maxDepth = 0; - estraverse.traverse(ast, { - enter: function (currentNode, parentNode) { - var path = this.path(), - pathDepth = path ? path.length : 0; - if (maxDepth < pathDepth) { - maxDepth = pathDepth; - } - } - }); - return maxDepth; -} - -function isCallExpression (node) { - return node && node.type === syntax.CallExpression; -} - -function isCalleeOfParent(currentNode, parentNode) { - return parentNode && currentNode && - parentNode.type === syntax.CallExpression && - parentNode.callee === currentNode; -} - -function identifiers (node) { - return node.type === syntax.Identifier; -} - -function validateApiExpression (callExpression) { - if (callExpression.type !== syntax.CallExpression) { - throw new Error(notCallExprMessage); - } - var names = {}; - callExpression.arguments.forEach(function (arg) { - var name = validateArg(arg); - if (hasOwn.call(names, name)) { - throw new Error(duplicatedArgMessage + name); - } else { - names[name] = name; - } - }); -} - -function validateArg (arg) { - var inner; - switch(arg.type) { - case syntax.Identifier: - return arg.name; - case syntax.ArrayExpression: - if (arg.elements.length !== 1) { - throw new Error(invalidFormMessage); - } - inner = arg.elements[0]; - if (inner.type !== syntax.Identifier) { - throw new Error(invalidFormMessage); - } - return inner.name; - default: - throw new Error(invalidFormMessage); - } -} - -function extractExpressionFrom (tree) { - var statement, expression; - statement = tree.body[0]; - if (statement.type !== syntax.ExpressionStatement) { - throw new Error(notCallExprMessage); - } - expression = statement.expression; - validateApiExpression(expression); - return expression; -} - -module.exports = createMatcher; - -},{"deep-equal":14,"esprima":21,"espurify":17,"estraverse":20}],14:[function(_dereq_,module,exports){ -var pSlice = Array.prototype.slice; -var objectKeys = _dereq_('./lib/keys.js'); -var isArguments = _dereq_('./lib/is_arguments.js'); - -var deepEqual = module.exports = function (actual, expected, opts) { - if (!opts) opts = {}; - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (actual instanceof Date && expected instanceof Date) { - return actual.getTime() === expected.getTime(); - - // 7.3. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (typeof actual != 'object' && typeof expected != 'object') { - return opts.strict ? actual === expected : actual == expected; - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected, opts); - } -} - -function isUndefinedOrNull(value) { - return value === null || value === undefined; -} - -function isBuffer (x) { - if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false; - if (typeof x.copy !== 'function' || typeof x.slice !== 'function') { - return false; - } - if (x.length > 0 && typeof x[0] !== 'number') return false; - return true; -} - -function objEquiv(a, b, opts) { - var i, key; - if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) - return false; - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - //~~~I've managed to break Object.keys through screwy arguments passing. - // Converting to array solves the problem. - if (isArguments(a)) { - if (!isArguments(b)) { - return false; - } - a = pSlice.call(a); - b = pSlice.call(b); - return deepEqual(a, b, opts); - } - if (isBuffer(a)) { - if (!isBuffer(b)) { - return false; - } - if (a.length !== b.length) return false; - for (i = 0; i < a.length; i++) { - if (a[i] !== b[i]) return false; - } - return true; - } - try { - var ka = objectKeys(a), - kb = objectKeys(b); - } catch (e) {//happens when one is a string literal and the other isn't - return false; - } - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!deepEqual(a[key], b[key], opts)) return false; - } - return typeof a === typeof b; -} - -},{"./lib/is_arguments.js":15,"./lib/keys.js":16}],15:[function(_dereq_,module,exports){ -var supportsArgumentsClass = (function(){ - return Object.prototype.toString.call(arguments) -})() == '[object Arguments]'; - -exports = module.exports = supportsArgumentsClass ? supported : unsupported; - -exports.supported = supported; -function supported(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -}; - -exports.unsupported = unsupported; -function unsupported(object){ - return object && - typeof object == 'object' && - typeof object.length == 'number' && - Object.prototype.hasOwnProperty.call(object, 'callee') && - !Object.prototype.propertyIsEnumerable.call(object, 'callee') || - false; -}; - -},{}],16:[function(_dereq_,module,exports){ -exports = module.exports = typeof Object.keys === 'function' - ? Object.keys : shim; - -exports.shim = shim; -function shim (obj) { - var keys = []; - for (var key in obj) keys.push(key); - return keys; -} - -},{}],17:[function(_dereq_,module,exports){ -/** - * espurify - Clone new AST without extra properties - * - * https://github.com/twada/espurify - * - * Copyright (c) 2014 Takuto Wada - * Licensed under the MIT license. - * http://twada.mit-license.org/ - */ -'use strict'; - -var traverse = _dereq_('traverse'), - deepCopy = _dereq_('./lib/ast-deepcopy'), - astProps = _dereq_('./lib/ast-properties'), - hasOwn = Object.prototype.hasOwnProperty; - -function espurify (node) { - var result = deepCopy(node); - traverse(result).forEach(function (x) { - if (this.parent && - this.parent.node && - this.parent.node.type && - isSupportedNodeType(this.parent.node.type) && - !isSupportedKey(this.parent.node.type, this.key)) - { - this.remove(true); - } - }); - return result; -} - -function isSupportedNodeType (type) { - return hasOwn.call(astProps, type); -} - -function isSupportedKey (type, key) { - return astProps[type].indexOf(key) !== -1; -} - -module.exports = espurify; - -},{"./lib/ast-deepcopy":18,"./lib/ast-properties":19,"traverse":44}],18:[function(_dereq_,module,exports){ -/** - * Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors. - * Released under the BSD license. - * https://github.com/Constellation/esmangle/blob/master/LICENSE.BSD - */ -'use strict'; - -var isArray = Array.isArray || function isArray (array) { - return Object.prototype.toString.call(array) === '[object Array]'; -}; - -function deepCopyInternal (obj, result) { - var key, val; - for (key in obj) { - if (key.lastIndexOf('__', 0) === 0) { - continue; - } - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - if (val instanceof RegExp) { - val = new RegExp(val); - } else { - val = deepCopyInternal(val, isArray(val) ? [] : {}); - } - } - result[key] = val; - } - } - return result; -} - -function deepCopy (obj) { - return deepCopyInternal(obj, isArray(obj) ? [] : {}); -} - -module.exports = deepCopy; - -},{}],19:[function(_dereq_,module,exports){ -module.exports = { - AssignmentExpression: ['type', 'operator', 'left', 'right'], - ArrayExpression: ['type', 'elements'], - ArrayPattern: ['type', 'elements'], - // ArrowFunctionExpression: ['type', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], - BlockStatement: ['type', 'body'], - BinaryExpression: ['type', 'operator', 'left', 'right'], - BreakStatement: ['type', 'label'], - CallExpression: ['type', 'callee', 'arguments'], - CatchClause: ['type', 'param', 'guard', 'body'], - // ClassBody: ['type', 'body'], - // ClassDeclaration: ['type', 'id', 'body', 'superClass'], - // ClassExpression: ['type', 'id', 'body', 'superClass'], - ConditionalExpression: ['type', 'test', 'consequent', 'alternate'], - ContinueStatement: ['type', 'label'], - DebuggerStatement: ['type'], - // DirectiveStatement: ['type'], - DoWhileStatement: ['type', 'body', 'test'], - EmptyStatement: ['type'], - ExpressionStatement: ['type', 'expression'], - ForStatement: ['type', 'init', 'test', 'update', 'body'], - ForInStatement: ['type', 'left', 'right', 'body', 'each'], - FunctionDeclaration: ['type', 'id', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], - FunctionExpression: ['type', 'id', 'params', 'defaults', 'rest', 'body', 'generator', 'expression'], - Identifier: ['type', 'name'], - IfStatement: ['type', 'test', 'consequent', 'alternate'], - Literal: ['type', 'value'], - LabeledStatement: ['type', 'label', 'body'], - LogicalExpression: ['type', 'operator', 'left', 'right'], - MemberExpression: ['type', 'object', 'property', 'computed'], - // MethodDefinition: ['type', 'key', 'value'], - NewExpression: ['type', 'callee', 'arguments'], - ObjectExpression: ['type', 'properties'], - ObjectPattern: ['type', 'properties'], - Program: ['type', 'body'], - Property: ['type', 'key', 'value', 'kind'], - ReturnStatement: ['type', 'argument'], - SequenceExpression: ['type', 'expressions'], - SwitchStatement: ['type', 'discriminant', 'cases', 'lexical'], - SwitchCase: ['type', 'test', 'consequent'], - ThisExpression: ['type'], - ThrowStatement: ['type', 'argument'], - TryStatement: ['type', 'block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], - UnaryExpression: ['type', 'operator', 'prefix', 'argument'], - UpdateExpression: ['type', 'operator', 'argument', 'prefix'], - VariableDeclaration: ['type', 'declarations', 'kind'], - VariableDeclarator: ['type', 'id', 'init'], - WhileStatement: ['type', 'test', 'body'], - WithStatement: ['type', 'object', 'body'], - YieldExpression: ['type', 'argument'] -}; - -},{}],20:[function(_dereq_,module,exports){ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012 Ariya Hidayat - - 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 HOLDERS AND CONTRIBUTORS "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 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. -*/ -/*jslint vars:false, bitwise:true*/ -/*jshint indent:4*/ -/*global exports:true, define:true*/ -(function (root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // and plain browser loading, - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.estraverse = {})); - } -}(this, function (exports) { - 'use strict'; - - var Syntax, - isArray, - VisitorOption, - VisitorKeys, - objectCreate, - objectKeys, - BREAK, - SKIP, - REMOVE; - - function ignoreJSHintError() { } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - - // based on LLVM libc++ upper_bound / lower_bound - // MIT License - - function upperBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - - function lowerBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - - objectCreate = Object.create || (function () { - function F() { } - - return function (o) { - F.prototype = o; - return new F(); - }; - })(); - - objectKeys = Object.keys || function (o) { - var keys = [], key; - for (key in o) { - keys.push(key); - } - return keys; - }; - - function extend(to, from) { - objectKeys(from).forEach(function (key) { - to[key] = from[key]; - }); - return to; - } - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ClassBody: 'ClassBody', - ClassDeclaration: 'ClassDeclaration', - ClassExpression: 'ClassExpression', - ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. - ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExportBatchSpecifier: 'ExportBatchSpecifier', - ExportDeclaration: 'ExportDeclaration', - ExportSpecifier: 'ExportSpecifier', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - ForOfStatement: 'ForOfStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. - Identifier: 'Identifier', - IfStatement: 'IfStatement', - ImportDeclaration: 'ImportDeclaration', - ImportDefaultSpecifier: 'ImportDefaultSpecifier', - ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', - ImportSpecifier: 'ImportSpecifier', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - MethodDefinition: 'MethodDefinition', - ModuleSpecifier: 'ModuleSpecifier', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SpreadElement: 'SpreadElement', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - TaggedTemplateExpression: 'TaggedTemplateExpression', - TemplateElement: 'TemplateElement', - TemplateLiteral: 'TemplateLiteral', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - - VisitorKeys = { - AssignmentExpression: ['left', 'right'], - ArrayExpression: ['elements'], - ArrayPattern: ['elements'], - ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'], - BlockStatement: ['body'], - BinaryExpression: ['left', 'right'], - BreakStatement: ['label'], - CallExpression: ['callee', 'arguments'], - CatchClause: ['param', 'body'], - ClassBody: ['body'], - ClassDeclaration: ['id', 'body', 'superClass'], - ClassExpression: ['id', 'body', 'superClass'], - ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. - ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. - ConditionalExpression: ['test', 'consequent', 'alternate'], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: ['body', 'test'], - EmptyStatement: [], - ExportBatchSpecifier: [], - ExportDeclaration: ['declaration', 'specifiers', 'source'], - ExportSpecifier: ['id', 'name'], - ExpressionStatement: ['expression'], - ForStatement: ['init', 'test', 'update', 'body'], - ForInStatement: ['left', 'right', 'body'], - ForOfStatement: ['left', 'right', 'body'], - FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'], - FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], - GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. - Identifier: [], - IfStatement: ['test', 'consequent', 'alternate'], - ImportDeclaration: ['specifiers', 'source'], - ImportDefaultSpecifier: ['id'], - ImportNamespaceSpecifier: ['id'], - ImportSpecifier: ['id', 'name'], - Literal: [], - LabeledStatement: ['label', 'body'], - LogicalExpression: ['left', 'right'], - MemberExpression: ['object', 'property'], - MethodDefinition: ['key', 'value'], - ModuleSpecifier: [], - NewExpression: ['callee', 'arguments'], - ObjectExpression: ['properties'], - ObjectPattern: ['properties'], - Program: ['body'], - Property: ['key', 'value'], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SpreadElement: ['argument'], - SwitchStatement: ['discriminant', 'cases'], - SwitchCase: ['test', 'consequent'], - TaggedTemplateExpression: ['tag', 'quasi'], - TemplateElement: [], - TemplateLiteral: ['quasis', 'expressions'], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: ['id', 'init'], - WhileStatement: ['test', 'body'], - WithStatement: ['object', 'body'], - YieldExpression: ['argument'] - }; - - // unique id - BREAK = {}; - SKIP = {}; - REMOVE = {}; - - VisitorOption = { - Break: BREAK, - Skip: SKIP, - Remove: REMOVE - }; - - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - - Reference.prototype.remove = function remove() { - if (isArray(this.parent)) { - this.parent.splice(this.key, 1); - return true; - } else { - this.replace(null); - return false; - } - }; - - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - - function Controller() { } - - // API: - // return property path array from root to current node - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - - // root node - if (!this.__current.path) { - return null; - } - - // first node is sentinel, second node is root element - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - - // API: - // return type of current node - Controller.prototype.type = function () { - var node = this.current(); - return node.type || this.__current.wrap; - }; - - // API: - // return array of parent elements - Controller.prototype.parents = function parents() { - var i, iz, result; - - // first node is sentinel - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - - return result; - }; - - // API: - // return current node - Controller.prototype.current = function current() { - return this.__current.node; - }; - - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - - result = undefined; - - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - - return result; - }; - - // API: - // notify control skip / break - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - - // API: - // skip child nodes of current node - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - - // API: - // break traversals - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - - // API: - // remove node - Controller.prototype.remove = function () { - this.notify(REMOVE); - }; - - Controller.prototype.__initialize = function(root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - this.__fallback = visitor.fallback === 'iteration'; - this.__keys = VisitorKeys; - if (visitor.keys) { - this.__keys = extend(objectCreate(this.__keys), visitor.keys); - } - }; - - function isNode(node) { - if (node == null) { - return false; - } - return typeof node === 'object' && typeof node.type === 'string'; - } - - function isProperty(nodeType, key) { - return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; - } - - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, - leavelist, - element, - node, - nodeType, - ret, - key, - current, - current2, - candidates, - candidate, - sentinel; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - ret = this.__execute(visitor.leave, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - - if (element.node) { - - ret = this.__execute(visitor.enter, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || ret === SKIP) { - continue; - } - - node = element.node; - nodeType = element.wrap || node.type; - candidates = this.__keys[nodeType]; - if (!candidates) { - if (this.__fallback) { - candidates = objectKeys(node); - } else { - throw new Error('Unknown node type ' + nodeType + '.'); - } - } - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (isArray(candidate)) { - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (isProperty(nodeType, candidates[current])) { - element = new Element(candidate[current2], [key, current2], 'Property', null); - } else if (isNode(candidate[current2])) { - element = new Element(candidate[current2], [key, current2], null, null); - } else { - continue; - } - worklist.push(element); - } - } else if (isNode(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - } - } - } - } - }; - - Controller.prototype.replace = function replace(root, visitor) { - function removeElem(element) { - var i, - key, - nextElem, - parent; - - if (element.ref.remove()) { - // When the reference is an element of an array. - key = element.ref.key; - parent = element.ref.parent; - - // If removed from array, then decrease following items' keys. - i = worklist.length; - while (i--) { - nextElem = worklist[i]; - if (nextElem.ref && nextElem.ref.parent === parent) { - if (nextElem.ref.key < key) { - break; - } - --nextElem.ref.key; - } - } - } - } - - var worklist, - leavelist, - node, - nodeType, - target, - element, - current, - current2, - candidates, - candidate, - sentinel, - outer, - key; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - outer = { - root: root - }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - target = this.__execute(visitor.leave, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { - // replace - element.ref.replace(target); - } - - if (this.__state === REMOVE || target === REMOVE) { - removeElem(element); - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - - target = this.__execute(visitor.enter, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { - // replace - element.ref.replace(target); - element.node = target; - } - - if (this.__state === REMOVE || target === REMOVE) { - removeElem(element); - element.node = null; - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - - // node may be null - node = element.node; - if (!node) { - continue; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || target === SKIP) { - continue; - } - - nodeType = element.wrap || node.type; - candidates = this.__keys[nodeType]; - if (!candidates) { - if (this.__fallback) { - candidates = objectKeys(node); - } else { - throw new Error('Unknown node type ' + nodeType + '.'); - } - } - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (isArray(candidate)) { - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (isProperty(nodeType, candidates[current])) { - element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); - } else if (isNode(candidate[current2])) { - element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); - } else { - continue; - } - worklist.push(element); - } - } else if (isNode(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - } - } - } - - return outer.root; - }; - - function traverse(root, visitor) { - var controller = new Controller(); - return controller.traverse(root, visitor); - } - - function replace(root, visitor) { - var controller = new Controller(); - return controller.replace(root, visitor); - } - - function extendCommentRange(comment, tokens) { - var target; - - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - - comment.extendedRange = [comment.range[0], comment.range[1]]; - - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - - target -= 1; - if (target >= 0) { - comment.extendedRange[0] = tokens[target].range[1]; - } - - return comment; - } - - function attachComments(tree, providedComments, tokens) { - // At first, we should calculate extended comment ranges. - var comments = [], comment, len, i, cursor; - - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - - // tokens array is empty, we attach comments to tree as 'leadingComments' - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [0, tree.range[0]]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - - // This is based on John Freeman's implementation. - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - return tree; - } - - exports.version = '1.8.0'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; -})); -/* vim: set sw=4 ts=4 et tw=80 : */ - -},{}],21:[function(_dereq_,module,exports){ -/* - Copyright (C) 2013 Ariya Hidayat - Copyright (C) 2013 Thaddee Tyl - Copyright (C) 2013 Mathias Bynens - Copyright (C) 2012 Ariya Hidayat - Copyright (C) 2012 Mathias Bynens - Copyright (C) 2012 Joost-Wim Boekesteijn - Copyright (C) 2012 Kris Kowal - Copyright (C) 2012 Yusuke Suzuki - Copyright (C) 2012 Arpad Borsos - Copyright (C) 2011 Ariya Hidayat - - 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 HOLDERS AND CONTRIBUTORS "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 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. -*/ - -/*jslint bitwise:true plusplus:true */ -/*global esprima:true, define:true, exports:true, window: true, -throwErrorTolerant: true, -throwError: true, generateStatement: true, peek: true, -parseAssignmentExpression: true, parseBlock: true, parseExpression: true, -parseFunctionDeclaration: true, parseFunctionExpression: true, -parseFunctionSourceElements: true, parseVariableIdentifier: true, -parseLeftHandSideExpression: true, -parseUnaryExpression: true, -parseStatement: true, parseSourceElement: true */ - -(function (root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // Rhino, and plain browser loading. - - /* istanbul ignore next */ - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.esprima = {})); - } -}(this, function (exports) { - 'use strict'; - - var Token, - TokenName, - FnExprTokens, - Syntax, - PropertyKind, - Messages, - Regex, - SyntaxTreeDelegate, - source, - strict, - index, - lineNumber, - lineStart, - length, - delegate, - lookahead, - state, - extra; - - Token = { - BooleanLiteral: 1, - EOF: 2, - Identifier: 3, - Keyword: 4, - NullLiteral: 5, - NumericLiteral: 6, - Punctuator: 7, - StringLiteral: 8, - RegularExpression: 9 - }; - - TokenName = {}; - TokenName[Token.BooleanLiteral] = 'Boolean'; - TokenName[Token.EOF] = ''; - TokenName[Token.Identifier] = 'Identifier'; - TokenName[Token.Keyword] = 'Keyword'; - TokenName[Token.NullLiteral] = 'Null'; - TokenName[Token.NumericLiteral] = 'Numeric'; - TokenName[Token.Punctuator] = 'Punctuator'; - TokenName[Token.StringLiteral] = 'String'; - TokenName[Token.RegularExpression] = 'RegularExpression'; - - // A function following one of those tokens is an expression. - FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', - 'return', 'case', 'delete', 'throw', 'void', - // assignment operators - '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', - '&=', '|=', '^=', ',', - // binary/unary operators - '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', - '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', - '<=', '<', '>', '!=', '!==']; - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement' - }; - - PropertyKind = { - Data: 1, - Get: 2, - Set: 4 - }; - - // Error messages should be identical to V8. - Messages = { - UnexpectedToken: 'Unexpected token %0', - UnexpectedNumber: 'Unexpected number', - UnexpectedString: 'Unexpected string', - UnexpectedIdentifier: 'Unexpected identifier', - UnexpectedReserved: 'Unexpected reserved word', - UnexpectedEOS: 'Unexpected end of input', - NewlineAfterThrow: 'Illegal newline after throw', - InvalidRegExp: 'Invalid regular expression', - UnterminatedRegExp: 'Invalid regular expression: missing /', - InvalidLHSInAssignment: 'Invalid left-hand side in assignment', - InvalidLHSInForIn: 'Invalid left-hand side in for-in', - MultipleDefaultsInSwitch: 'More than one default clause in switch statement', - NoCatchOrFinally: 'Missing catch or finally after try', - UnknownLabel: 'Undefined label \'%0\'', - Redeclaration: '%0 \'%1\' has already been declared', - IllegalContinue: 'Illegal continue statement', - IllegalBreak: 'Illegal break statement', - IllegalReturn: 'Illegal return statement', - StrictModeWith: 'Strict mode code may not include a with statement', - StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', - StrictVarName: 'Variable name may not be eval or arguments in strict mode', - StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', - StrictParamDupe: 'Strict mode function may not have duplicate parameter names', - StrictFunctionName: 'Function name may not be eval or arguments in strict mode', - StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', - StrictDelete: 'Delete of an unqualified identifier in strict mode.', - StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', - AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', - AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', - StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', - StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', - StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', - StrictReservedWord: 'Use of future reserved word in strict mode' - }; - - // See also tools/generate-unicode-regex.py. - Regex = { - NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\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]'), - NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\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\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\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\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\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-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\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-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') - }; - - // Ensure the condition is true, otherwise throw an error. - // This is only to have a better contract semantic, i.e. another safety net - // to catch a logic error. The condition shall be fulfilled in normal case. - // Do NOT use this to enforce a certain condition on any user input. - - function assert(condition, message) { - /* istanbul ignore if */ - if (!condition) { - throw new Error('ASSERT: ' + message); - } - } - - function isDecimalDigit(ch) { - return (ch >= 48 && ch <= 57); // 0..9 - } - - function isHexDigit(ch) { - return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; - } - - function isOctalDigit(ch) { - return '01234567'.indexOf(ch) >= 0; - } - - - // 7.2 White Space - - function isWhiteSpace(ch) { - return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || - (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); - } - - // 7.3 Line Terminators - - function isLineTerminator(ch) { - return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); - } - - // 7.6 Identifier Names and Identifiers - - function isIdentifierStart(ch) { - return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) - (ch >= 0x41 && ch <= 0x5A) || // A..Z - (ch >= 0x61 && ch <= 0x7A) || // a..z - (ch === 0x5C) || // \ (backslash) - ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); - } - - function isIdentifierPart(ch) { - return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) - (ch >= 0x41 && ch <= 0x5A) || // A..Z - (ch >= 0x61 && ch <= 0x7A) || // a..z - (ch >= 0x30 && ch <= 0x39) || // 0..9 - (ch === 0x5C) || // \ (backslash) - ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); - } - - // 7.6.1.2 Future Reserved Words - - function isFutureReservedWord(id) { - switch (id) { - case 'class': - case 'enum': - case 'export': - case 'extends': - case 'import': - case 'super': - return true; - default: - return false; - } - } - - function isStrictModeReservedWord(id) { - switch (id) { - case 'implements': - case 'interface': - case 'package': - case 'private': - case 'protected': - case 'public': - case 'static': - case 'yield': - case 'let': - return true; - default: - return false; - } - } - - function isRestrictedWord(id) { - return id === 'eval' || id === 'arguments'; - } - - // 7.6.1.1 Keywords - - function isKeyword(id) { - if (strict && isStrictModeReservedWord(id)) { - return true; - } - - // 'const' is specialized as Keyword in V8. - // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. - // Some others are from future reserved words. - - switch (id.length) { - case 2: - return (id === 'if') || (id === 'in') || (id === 'do'); - case 3: - return (id === 'var') || (id === 'for') || (id === 'new') || - (id === 'try') || (id === 'let'); - case 4: - return (id === 'this') || (id === 'else') || (id === 'case') || - (id === 'void') || (id === 'with') || (id === 'enum'); - case 5: - return (id === 'while') || (id === 'break') || (id === 'catch') || - (id === 'throw') || (id === 'const') || (id === 'yield') || - (id === 'class') || (id === 'super'); - case 6: - return (id === 'return') || (id === 'typeof') || (id === 'delete') || - (id === 'switch') || (id === 'export') || (id === 'import'); - case 7: - return (id === 'default') || (id === 'finally') || (id === 'extends'); - case 8: - return (id === 'function') || (id === 'continue') || (id === 'debugger'); - case 10: - return (id === 'instanceof'); - default: - return false; - } - } - - // 7.4 Comments - - function addComment(type, value, start, end, loc) { - var comment, attacher; - - assert(typeof start === 'number', 'Comment must have valid position'); - - // Because the way the actual token is scanned, often the comments - // (if any) are skipped twice during the lexical analysis. - // Thus, we need to skip adding a comment if the comment array already - // handled it. - if (state.lastCommentStart >= start) { - return; - } - state.lastCommentStart = start; - - comment = { - type: type, - value: value - }; - if (extra.range) { - comment.range = [start, end]; - } - if (extra.loc) { - comment.loc = loc; - } - extra.comments.push(comment); - if (extra.attachComment) { - extra.leadingComments.push(comment); - extra.trailingComments.push(comment); - } - } - - function skipSingleLineComment(offset) { - var start, loc, ch, comment; - - start = index - offset; - loc = { - start: { - line: lineNumber, - column: index - lineStart - offset - } - }; - - while (index < length) { - ch = source.charCodeAt(index); - ++index; - if (isLineTerminator(ch)) { - if (extra.comments) { - comment = source.slice(start + offset, index - 1); - loc.end = { - line: lineNumber, - column: index - lineStart - 1 - }; - addComment('Line', comment, start, index - 1, loc); - } - if (ch === 13 && source.charCodeAt(index) === 10) { - ++index; - } - ++lineNumber; - lineStart = index; - return; - } - } - - if (extra.comments) { - comment = source.slice(start + offset, index); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - addComment('Line', comment, start, index, loc); - } - } - - function skipMultiLineComment() { - var start, loc, ch, comment; - - if (extra.comments) { - start = index - 2; - loc = { - start: { - line: lineNumber, - column: index - lineStart - 2 - } - }; - } - - while (index < length) { - ch = source.charCodeAt(index); - if (isLineTerminator(ch)) { - if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { - ++index; - } - ++lineNumber; - ++index; - lineStart = index; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else if (ch === 0x2A) { - // Block comment ends with '*/'. - if (source.charCodeAt(index + 1) === 0x2F) { - ++index; - ++index; - if (extra.comments) { - comment = source.slice(start + 2, index - 2); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - addComment('Block', comment, start, index, loc); - } - return; - } - ++index; - } else { - ++index; - } - } - - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - function skipComment() { - var ch, start; - - start = (index === 0); - while (index < length) { - ch = source.charCodeAt(index); - - if (isWhiteSpace(ch)) { - ++index; - } else if (isLineTerminator(ch)) { - ++index; - if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { - ++index; - } - ++lineNumber; - lineStart = index; - start = true; - } else if (ch === 0x2F) { // U+002F is '/' - ch = source.charCodeAt(index + 1); - if (ch === 0x2F) { - ++index; - ++index; - skipSingleLineComment(2); - start = true; - } else if (ch === 0x2A) { // U+002A is '*' - ++index; - ++index; - skipMultiLineComment(); - } else { - break; - } - } else if (start && ch === 0x2D) { // U+002D is '-' - // U+003E is '>' - if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { - // '-->' is a single-line comment - index += 3; - skipSingleLineComment(3); - } else { - break; - } - } else if (ch === 0x3C) { // U+003C is '<' - if (source.slice(index + 1, index + 4) === '!--') { - ++index; // `<` - ++index; // `!` - ++index; // `-` - ++index; // `-` - skipSingleLineComment(4); - } else { - break; - } - } else { - break; - } - } - } - - function scanHexEscape(prefix) { - var i, len, ch, code = 0; - - len = (prefix === 'u') ? 4 : 2; - for (i = 0; i < len; ++i) { - if (index < length && isHexDigit(source[index])) { - ch = source[index++]; - code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); - } else { - return ''; - } - } - return String.fromCharCode(code); - } - - function getEscapedIdentifier() { - var ch, id; - - ch = source.charCodeAt(index++); - id = String.fromCharCode(ch); - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (ch === 0x5C) { - if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - ++index; - ch = scanHexEscape('u'); - if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - id = ch; - } - - while (index < length) { - ch = source.charCodeAt(index); - if (!isIdentifierPart(ch)) { - break; - } - ++index; - id += String.fromCharCode(ch); - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (ch === 0x5C) { - id = id.substr(0, id.length - 1); - if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - ++index; - ch = scanHexEscape('u'); - if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - id += ch; - } - } - - return id; - } - - function getIdentifier() { - var start, ch; - - start = index++; - while (index < length) { - ch = source.charCodeAt(index); - if (ch === 0x5C) { - // Blackslash (U+005C) marks Unicode escape sequence. - index = start; - return getEscapedIdentifier(); - } - if (isIdentifierPart(ch)) { - ++index; - } else { - break; - } - } - - return source.slice(start, index); - } - - function scanIdentifier() { - var start, id, type; - - start = index; - - // Backslash (U+005C) starts an escaped character. - id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); - - // There is no keyword or literal with only one character. - // Thus, it must be an identifier. - if (id.length === 1) { - type = Token.Identifier; - } else if (isKeyword(id)) { - type = Token.Keyword; - } else if (id === 'null') { - type = Token.NullLiteral; - } else if (id === 'true' || id === 'false') { - type = Token.BooleanLiteral; - } else { - type = Token.Identifier; - } - - return { - type: type, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - - // 7.7 Punctuators - - function scanPunctuator() { - var start = index, - code = source.charCodeAt(index), - code2, - ch1 = source[index], - ch2, - ch3, - ch4; - - switch (code) { - - // Check for most common single-character punctuators. - case 0x2E: // . dot - case 0x28: // ( open bracket - case 0x29: // ) close bracket - case 0x3B: // ; semicolon - case 0x2C: // , comma - case 0x7B: // { open curly brace - case 0x7D: // } close curly brace - case 0x5B: // [ - case 0x5D: // ] - case 0x3A: // : - case 0x3F: // ? - case 0x7E: // ~ - ++index; - if (extra.tokenize) { - if (code === 0x28) { - extra.openParenToken = extra.tokens.length; - } else if (code === 0x7B) { - extra.openCurlyToken = extra.tokens.length; - } - } - return { - type: Token.Punctuator, - value: String.fromCharCode(code), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - - default: - code2 = source.charCodeAt(index + 1); - - // '=' (U+003D) marks an assignment or comparison operator. - if (code2 === 0x3D) { - switch (code) { - case 0x2B: // + - case 0x2D: // - - case 0x2F: // / - case 0x3C: // < - case 0x3E: // > - case 0x5E: // ^ - case 0x7C: // | - case 0x25: // % - case 0x26: // & - case 0x2A: // * - index += 2; - return { - type: Token.Punctuator, - value: String.fromCharCode(code) + String.fromCharCode(code2), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - - case 0x21: // ! - case 0x3D: // = - index += 2; - - // !== and === - if (source.charCodeAt(index) === 0x3D) { - ++index; - } - return { - type: Token.Punctuator, - value: source.slice(start, index), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - } - } - - // 4-character punctuator: >>>= - - ch4 = source.substr(index, 4); - - if (ch4 === '>>>=') { - index += 4; - return { - type: Token.Punctuator, - value: ch4, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // 3-character punctuators: === !== >>> <<= >>= - - ch3 = ch4.substr(0, 3); - - if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { - index += 3; - return { - type: Token.Punctuator, - value: ch3, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // Other 2-character punctuators: ++ -- << >> && || - ch2 = ch3.substr(0, 2); - - if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { - index += 2; - return { - type: Token.Punctuator, - value: ch2, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // 1-character punctuators: < > = ! + - * % & | ^ / - if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { - ++index; - return { - type: Token.Punctuator, - value: ch1, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - // 7.8.3 Numeric Literals - - function scanHexLiteral(start) { - var number = ''; - - while (index < length) { - if (!isHexDigit(source[index])) { - break; - } - number += source[index++]; - } - - if (number.length === 0) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseInt('0x' + number, 16), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function scanOctalLiteral(start) { - var number = '0' + source[index++]; - while (index < length) { - if (!isOctalDigit(source[index])) { - break; - } - number += source[index++]; - } - - if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseInt(number, 8), - octal: true, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function scanNumericLiteral() { - var number, start, ch; - - ch = source[index]; - assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), - 'Numeric literal must start with a decimal digit or a decimal point'); - - start = index; - number = ''; - if (ch !== '.') { - number = source[index++]; - ch = source[index]; - - // Hex number starts with '0x'. - // Octal number starts with '0'. - if (number === '0') { - if (ch === 'x' || ch === 'X') { - ++index; - return scanHexLiteral(start); - } - if (isOctalDigit(ch)) { - return scanOctalLiteral(start); - } - - // decimal number starts with '0' such as '09' is illegal. - if (ch && isDecimalDigit(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === '.') { - number += source[index++]; - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === 'e' || ch === 'E') { - number += source[index++]; - - ch = source[index]; - if (ch === '+' || ch === '-') { - number += source[index++]; - } - if (isDecimalDigit(source.charCodeAt(index))) { - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - } else { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseFloat(number), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // 7.8.4 String Literals - - function scanStringLiteral() { - var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; - startLineNumber = lineNumber; - startLineStart = lineStart; - - quote = source[index]; - assert((quote === '\'' || quote === '"'), - 'String literal must starts with a quote'); - - start = index; - ++index; - - while (index < length) { - ch = source[index++]; - - if (ch === quote) { - quote = ''; - break; - } else if (ch === '\\') { - ch = source[index++]; - if (!ch || !isLineTerminator(ch.charCodeAt(0))) { - switch (ch) { - case 'u': - case 'x': - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - str += unescaped; - } else { - index = restore; - str += ch; - } - break; - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case 'v': - str += '\x0B'; - break; - - default: - if (isOctalDigit(ch)) { - code = '01234567'.indexOf(ch); - - // \0 is not octal escape sequence - if (code !== 0) { - octal = true; - } - - if (index < length && isOctalDigit(source[index])) { - octal = true; - code = code * 8 + '01234567'.indexOf(source[index++]); - - // 3 digits are only allowed when string starts - // with 0, 1, 2, 3 - if ('0123'.indexOf(ch) >= 0 && - index < length && - isOctalDigit(source[index])) { - code = code * 8 + '01234567'.indexOf(source[index++]); - } - } - str += String.fromCharCode(code); - } else { - str += ch; - } - break; - } - } else { - ++lineNumber; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - lineStart = index; - } - } else if (isLineTerminator(ch.charCodeAt(0))) { - break; - } else { - str += ch; - } - } - - if (quote !== '') { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.StringLiteral, - value: str, - octal: octal, - startLineNumber: startLineNumber, - startLineStart: startLineStart, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function testRegExp(pattern, flags) { - var value; - try { - value = new RegExp(pattern, flags); - } catch (e) { - throwError({}, Messages.InvalidRegExp); - } - return value; - } - - function scanRegExpBody() { - var ch, str, classMarker, terminated, body; - - ch = source[index]; - assert(ch === '/', 'Regular expression literal must start with a slash'); - str = source[index++]; - - classMarker = false; - terminated = false; - while (index < length) { - ch = source[index++]; - str += ch; - if (ch === '\\') { - ch = source[index++]; - // ECMA-262 7.8.5 - if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); - } - str += ch; - } else if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); - } else if (classMarker) { - if (ch === ']') { - classMarker = false; - } - } else { - if (ch === '/') { - terminated = true; - break; - } else if (ch === '[') { - classMarker = true; - } - } - } - - if (!terminated) { - throwError({}, Messages.UnterminatedRegExp); - } - - // Exclude leading and trailing slash. - body = str.substr(1, str.length - 2); - return { - value: body, - literal: str - }; - } - - function scanRegExpFlags() { - var ch, str, flags, restore; - - str = ''; - flags = ''; - while (index < length) { - ch = source[index]; - if (!isIdentifierPart(ch.charCodeAt(0))) { - break; - } - - ++index; - if (ch === '\\' && index < length) { - ch = source[index]; - if (ch === 'u') { - ++index; - restore = index; - ch = scanHexEscape('u'); - if (ch) { - flags += ch; - for (str += '\\u'; restore < index; ++restore) { - str += source[restore]; - } - } else { - index = restore; - flags += 'u'; - str += '\\u'; - } - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); - } else { - str += '\\'; - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - flags += ch; - str += ch; - } - } - - return { - value: flags, - literal: str - }; - } - - function scanRegExp() { - var start, body, flags, pattern, value; - - lookahead = null; - skipComment(); - start = index; - - body = scanRegExpBody(); - flags = scanRegExpFlags(); - value = testRegExp(body.value, flags.value); - - if (extra.tokenize) { - return { - type: Token.RegularExpression, - value: value, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - return { - literal: body.literal + flags.literal, - value: value, - start: start, - end: index - }; - } - - function collectRegex() { - var pos, loc, regex, token; - - skipComment(); - - pos = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - regex = scanRegExp(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - /* istanbul ignore next */ - if (!extra.tokenize) { - // Pop the previous token, which is likely '/' or '/=' - if (extra.tokens.length > 0) { - token = extra.tokens[extra.tokens.length - 1]; - if (token.range[0] === pos && token.type === 'Punctuator') { - if (token.value === '/' || token.value === '/=') { - extra.tokens.pop(); - } - } - } - - extra.tokens.push({ - type: 'RegularExpression', - value: regex.literal, - range: [pos, index], - loc: loc - }); - } - - return regex; - } - - function isIdentifierName(token) { - return token.type === Token.Identifier || - token.type === Token.Keyword || - token.type === Token.BooleanLiteral || - token.type === Token.NullLiteral; - } - - function advanceSlash() { - var prevToken, - checkToken; - // Using the following algorithm: - // https://github.com/mozilla/sweet.js/wiki/design - prevToken = extra.tokens[extra.tokens.length - 1]; - if (!prevToken) { - // Nothing before that: it cannot be a division. - return collectRegex(); - } - if (prevToken.type === 'Punctuator') { - if (prevToken.value === ']') { - return scanPunctuator(); - } - if (prevToken.value === ')') { - checkToken = extra.tokens[extra.openParenToken - 1]; - if (checkToken && - checkToken.type === 'Keyword' && - (checkToken.value === 'if' || - checkToken.value === 'while' || - checkToken.value === 'for' || - checkToken.value === 'with')) { - return collectRegex(); - } - return scanPunctuator(); - } - if (prevToken.value === '}') { - // Dividing a function by anything makes little sense, - // but we have to check for that. - if (extra.tokens[extra.openCurlyToken - 3] && - extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { - // Anonymous function. - checkToken = extra.tokens[extra.openCurlyToken - 4]; - if (!checkToken) { - return scanPunctuator(); - } - } else if (extra.tokens[extra.openCurlyToken - 4] && - extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { - // Named function. - checkToken = extra.tokens[extra.openCurlyToken - 5]; - if (!checkToken) { - return collectRegex(); - } - } else { - return scanPunctuator(); - } - // checkToken determines whether the function is - // a declaration or an expression. - if (FnExprTokens.indexOf(checkToken.value) >= 0) { - // It is an expression. - return scanPunctuator(); - } - // It is a declaration. - return collectRegex(); - } - return collectRegex(); - } - if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { - return collectRegex(); - } - return scanPunctuator(); - } - - function advance() { - var ch; - - skipComment(); - - if (index >= length) { - return { - type: Token.EOF, - lineNumber: lineNumber, - lineStart: lineStart, - start: index, - end: index - }; - } - - ch = source.charCodeAt(index); - - if (isIdentifierStart(ch)) { - return scanIdentifier(); - } - - // Very common: ( and ) and ; - if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { - return scanPunctuator(); - } - - // String literal starts with single quote (U+0027) or double quote (U+0022). - if (ch === 0x27 || ch === 0x22) { - return scanStringLiteral(); - } - - - // Dot (.) U+002E can also start a floating-point number, hence the need - // to check the next character. - if (ch === 0x2E) { - if (isDecimalDigit(source.charCodeAt(index + 1))) { - return scanNumericLiteral(); - } - return scanPunctuator(); - } - - if (isDecimalDigit(ch)) { - return scanNumericLiteral(); - } - - // Slash (/) U+002F can also start a regex. - if (extra.tokenize && ch === 0x2F) { - return advanceSlash(); - } - - return scanPunctuator(); - } - - function collectToken() { - var loc, token, range, value; - - skipComment(); - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - token = advance(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - if (token.type !== Token.EOF) { - value = source.slice(token.start, token.end); - extra.tokens.push({ - type: TokenName[token.type], - value: value, - range: [token.start, token.end], - loc: loc - }); - } - - return token; - } - - function lex() { - var token; - - token = lookahead; - index = token.end; - lineNumber = token.lineNumber; - lineStart = token.lineStart; - - lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); - - index = token.end; - lineNumber = token.lineNumber; - lineStart = token.lineStart; - - return token; - } - - function peek() { - var pos, line, start; - - pos = index; - line = lineNumber; - start = lineStart; - lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); - index = pos; - lineNumber = line; - lineStart = start; - } - - function Position(line, column) { - this.line = line; - this.column = column; - } - - function SourceLocation(startLine, startColumn, line, column) { - this.start = new Position(startLine, startColumn); - this.end = new Position(line, column); - } - - SyntaxTreeDelegate = { - - name: 'SyntaxTree', - - processComment: function (node) { - var lastChild, trailingComments; - - if (node.type === Syntax.Program) { - if (node.body.length > 0) { - return; - } - } - - if (extra.trailingComments.length > 0) { - if (extra.trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.trailingComments; - extra.trailingComments = []; - } else { - extra.trailingComments.length = 0; - } - } else { - if (extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - } - } - - // Eating the stack. - while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { - lastChild = extra.bottomRightStack.pop(); - } - - if (lastChild) { - if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = lastChild.leadingComments; - delete lastChild.leadingComments; - } - } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = extra.leadingComments; - extra.leadingComments = []; - } - - - if (trailingComments) { - node.trailingComments = trailingComments; - } - - extra.bottomRightStack.push(node); - }, - - markEnd: function (node, startToken) { - if (extra.range) { - node.range = [startToken.start, index]; - } - if (extra.loc) { - node.loc = new SourceLocation( - startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, - startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), - lineNumber, - index - lineStart - ); - this.postProcess(node); - } - - if (extra.attachComment) { - this.processComment(node); - } - return node; - }, - - postProcess: function (node) { - if (extra.source) { - node.loc.source = extra.source; - } - return node; - }, - - createArrayExpression: function (elements) { - return { - type: Syntax.ArrayExpression, - elements: elements - }; - }, - - createAssignmentExpression: function (operator, left, right) { - return { - type: Syntax.AssignmentExpression, - operator: operator, - left: left, - right: right - }; - }, - - createBinaryExpression: function (operator, left, right) { - var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : - Syntax.BinaryExpression; - return { - type: type, - operator: operator, - left: left, - right: right - }; - }, - - createBlockStatement: function (body) { - return { - type: Syntax.BlockStatement, - body: body - }; - }, - - createBreakStatement: function (label) { - return { - type: Syntax.BreakStatement, - label: label - }; - }, - - createCallExpression: function (callee, args) { - return { - type: Syntax.CallExpression, - callee: callee, - 'arguments': args - }; - }, - - createCatchClause: function (param, body) { - return { - type: Syntax.CatchClause, - param: param, - body: body - }; - }, - - createConditionalExpression: function (test, consequent, alternate) { - return { - type: Syntax.ConditionalExpression, - test: test, - consequent: consequent, - alternate: alternate - }; - }, - - createContinueStatement: function (label) { - return { - type: Syntax.ContinueStatement, - label: label - }; - }, - - createDebuggerStatement: function () { - return { - type: Syntax.DebuggerStatement - }; - }, - - createDoWhileStatement: function (body, test) { - return { - type: Syntax.DoWhileStatement, - body: body, - test: test - }; - }, - - createEmptyStatement: function () { - return { - type: Syntax.EmptyStatement - }; - }, - - createExpressionStatement: function (expression) { - return { - type: Syntax.ExpressionStatement, - expression: expression - }; - }, - - createForStatement: function (init, test, update, body) { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body - }; - }, - - createForInStatement: function (left, right, body) { - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false - }; - }, - - createFunctionDeclaration: function (id, params, defaults, body) { - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; - }, - - createFunctionExpression: function (id, params, defaults, body) { - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; - }, - - createIdentifier: function (name) { - return { - type: Syntax.Identifier, - name: name - }; - }, - - createIfStatement: function (test, consequent, alternate) { - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate - }; - }, - - createLabeledStatement: function (label, body) { - return { - type: Syntax.LabeledStatement, - label: label, - body: body - }; - }, - - createLiteral: function (token) { - return { - type: Syntax.Literal, - value: token.value, - raw: source.slice(token.start, token.end) - }; - }, - - createMemberExpression: function (accessor, object, property) { - return { - type: Syntax.MemberExpression, - computed: accessor === '[', - object: object, - property: property - }; - }, - - createNewExpression: function (callee, args) { - return { - type: Syntax.NewExpression, - callee: callee, - 'arguments': args - }; - }, - - createObjectExpression: function (properties) { - return { - type: Syntax.ObjectExpression, - properties: properties - }; - }, - - createPostfixExpression: function (operator, argument) { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: false - }; - }, - - createProgram: function (body) { - return { - type: Syntax.Program, - body: body - }; - }, - - createProperty: function (kind, key, value) { - return { - type: Syntax.Property, - key: key, - value: value, - kind: kind - }; - }, - - createReturnStatement: function (argument) { - return { - type: Syntax.ReturnStatement, - argument: argument - }; - }, - - createSequenceExpression: function (expressions) { - return { - type: Syntax.SequenceExpression, - expressions: expressions - }; - }, - - createSwitchCase: function (test, consequent) { - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent - }; - }, - - createSwitchStatement: function (discriminant, cases) { - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; - }, - - createThisExpression: function () { - return { - type: Syntax.ThisExpression - }; - }, - - createThrowStatement: function (argument) { - return { - type: Syntax.ThrowStatement, - argument: argument - }; - }, - - createTryStatement: function (block, guardedHandlers, handlers, finalizer) { - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: guardedHandlers, - handlers: handlers, - finalizer: finalizer - }; - }, - - createUnaryExpression: function (operator, argument) { - if (operator === '++' || operator === '--') { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: true - }; - } - return { - type: Syntax.UnaryExpression, - operator: operator, - argument: argument, - prefix: true - }; - }, - - createVariableDeclaration: function (declarations, kind) { - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind - }; - }, - - createVariableDeclarator: function (id, init) { - return { - type: Syntax.VariableDeclarator, - id: id, - init: init - }; - }, - - createWhileStatement: function (test, body) { - return { - type: Syntax.WhileStatement, - test: test, - body: body - }; - }, - - createWithStatement: function (object, body) { - return { - type: Syntax.WithStatement, - object: object, - body: body - }; - } - }; - - // Return true if there is a line terminator before the next token. - - function peekLineTerminator() { - var pos, line, start, found; - - pos = index; - line = lineNumber; - start = lineStart; - skipComment(); - found = lineNumber !== line; - index = pos; - lineNumber = line; - lineStart = start; - - return found; - } - - // Throw an exception - - function throwError(token, messageFormat) { - var error, - args = Array.prototype.slice.call(arguments, 2), - msg = messageFormat.replace( - /%(\d)/g, - function (whole, index) { - assert(index < args.length, 'Message reference must be in range'); - return args[index]; - } - ); - - if (typeof token.lineNumber === 'number') { - error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.start; - error.lineNumber = token.lineNumber; - error.column = token.start - lineStart + 1; - } else { - error = new Error('Line ' + lineNumber + ': ' + msg); - error.index = index; - error.lineNumber = lineNumber; - error.column = index - lineStart + 1; - } - - error.description = msg; - throw error; - } - - function throwErrorTolerant() { - try { - throwError.apply(null, arguments); - } catch (e) { - if (extra.errors) { - extra.errors.push(e); - } else { - throw e; - } - } - } - - - // Throw an exception because of the token. - - function throwUnexpected(token) { - if (token.type === Token.EOF) { - throwError(token, Messages.UnexpectedEOS); - } - - if (token.type === Token.NumericLiteral) { - throwError(token, Messages.UnexpectedNumber); - } - - if (token.type === Token.StringLiteral) { - throwError(token, Messages.UnexpectedString); - } - - if (token.type === Token.Identifier) { - throwError(token, Messages.UnexpectedIdentifier); - } - - if (token.type === Token.Keyword) { - if (isFutureReservedWord(token.value)) { - throwError(token, Messages.UnexpectedReserved); - } else if (strict && isStrictModeReservedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictReservedWord); - return; - } - throwError(token, Messages.UnexpectedToken, token.value); - } - - // BooleanLiteral, NullLiteral, or Punctuator. - throwError(token, Messages.UnexpectedToken, token.value); - } - - // Expect the next token to match the specified punctuator. - // If not, an exception will be thrown. - - function expect(value) { - var token = lex(); - if (token.type !== Token.Punctuator || token.value !== value) { - throwUnexpected(token); - } - } - - // Expect the next token to match the specified keyword. - // If not, an exception will be thrown. - - function expectKeyword(keyword) { - var token = lex(); - if (token.type !== Token.Keyword || token.value !== keyword) { - throwUnexpected(token); - } - } - - // Return true if the next token matches the specified punctuator. - - function match(value) { - return lookahead.type === Token.Punctuator && lookahead.value === value; - } - - // Return true if the next token matches the specified keyword - - function matchKeyword(keyword) { - return lookahead.type === Token.Keyword && lookahead.value === keyword; - } - - // Return true if the next token is an assignment operator - - function matchAssign() { - var op; - - if (lookahead.type !== Token.Punctuator) { - return false; - } - op = lookahead.value; - return op === '=' || - op === '*=' || - op === '/=' || - op === '%=' || - op === '+=' || - op === '-=' || - op === '<<=' || - op === '>>=' || - op === '>>>=' || - op === '&=' || - op === '^=' || - op === '|='; - } - - function consumeSemicolon() { - var line, oldIndex = index, oldLineNumber = lineNumber, - oldLineStart = lineStart, oldLookahead = lookahead; - - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(index) === 0x3B || match(';')) { - lex(); - return; - } - - line = lineNumber; - skipComment(); - if (lineNumber !== line) { - index = oldIndex; - lineNumber = oldLineNumber; - lineStart = oldLineStart; - lookahead = oldLookahead; - return; - } - - if (lookahead.type !== Token.EOF && !match('}')) { - throwUnexpected(lookahead); - } - } - - // Return true if provided expression is LeftHandSideExpression - - function isLeftHandSide(expr) { - return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; - } - - // 11.1.4 Array Initialiser - - function parseArrayInitialiser() { - var elements = [], startToken; - - startToken = lookahead; - expect('['); - - while (!match(']')) { - if (match(',')) { - lex(); - elements.push(null); - } else { - elements.push(parseAssignmentExpression()); - - if (!match(']')) { - expect(','); - } - } - } - - lex(); - - return delegate.markEnd(delegate.createArrayExpression(elements), startToken); - } - - // 11.1.5 Object Initialiser - - function parsePropertyFunction(param, first) { - var previousStrict, body, startToken; - - previousStrict = strict; - startToken = lookahead; - body = parseFunctionSourceElements(); - if (first && strict && isRestrictedWord(param[0].name)) { - throwErrorTolerant(first, Messages.StrictParamName); - } - strict = previousStrict; - return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); - } - - function parseObjectPropertyKey() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - // Note: This function is called only from parseObjectProperty(), where - // EOF and Punctuator tokens are already filtered out. - - if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { - if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); - } - return delegate.markEnd(delegate.createLiteral(token), startToken); - } - - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); - } - - function parseObjectProperty() { - var token, key, id, value, param, startToken; - - token = lookahead; - startToken = lookahead; - - if (token.type === Token.Identifier) { - - id = parseObjectPropertyKey(); - - // Property Assignment: Getter and Setter. - - if (token.value === 'get' && !match(':')) { - key = parseObjectPropertyKey(); - expect('('); - expect(')'); - value = parsePropertyFunction([]); - return delegate.markEnd(delegate.createProperty('get', key, value), startToken); - } - if (token.value === 'set' && !match(':')) { - key = parseObjectPropertyKey(); - expect('('); - token = lookahead; - if (token.type !== Token.Identifier) { - expect(')'); - throwErrorTolerant(token, Messages.UnexpectedToken, token.value); - value = parsePropertyFunction([]); - } else { - param = [ parseVariableIdentifier() ]; - expect(')'); - value = parsePropertyFunction(param, token); - } - return delegate.markEnd(delegate.createProperty('set', key, value), startToken); - } - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', id, value), startToken); - } - if (token.type === Token.EOF || token.type === Token.Punctuator) { - throwUnexpected(token); - } else { - key = parseObjectPropertyKey(); - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', key, value), startToken); - } - } - - function parseObjectInitialiser() { - var properties = [], property, name, key, kind, map = {}, toString = String, startToken; - - startToken = lookahead; - - expect('{'); - - while (!match('}')) { - property = parseObjectProperty(); - - if (property.key.type === Syntax.Identifier) { - name = property.key.name; - } else { - name = toString(property.key.value); - } - kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; - - key = '$' + name; - if (Object.prototype.hasOwnProperty.call(map, key)) { - if (map[key] === PropertyKind.Data) { - if (strict && kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.StrictDuplicateProperty); - } else if (kind !== PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); - } - } else { - if (kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); - } else if (map[key] & kind) { - throwErrorTolerant({}, Messages.AccessorGetSet); - } - } - map[key] |= kind; - } else { - map[key] = kind; - } - - properties.push(property); - - if (!match('}')) { - expect(','); - } - } - - expect('}'); - - return delegate.markEnd(delegate.createObjectExpression(properties), startToken); - } - - // 11.1.6 The Grouping Operator - - function parseGroupExpression() { - var expr; - - expect('('); - - expr = parseExpression(); - - expect(')'); - - return expr; - } - - - // 11.1 Primary Expressions - - function parsePrimaryExpression() { - var type, token, expr, startToken; - - if (match('(')) { - return parseGroupExpression(); - } - - if (match('[')) { - return parseArrayInitialiser(); - } - - if (match('{')) { - return parseObjectInitialiser(); - } - - type = lookahead.type; - startToken = lookahead; - - if (type === Token.Identifier) { - expr = delegate.createIdentifier(lex().value); - } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { - if (strict && lookahead.octal) { - throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); - } - expr = delegate.createLiteral(lex()); - } else if (type === Token.Keyword) { - if (matchKeyword('function')) { - return parseFunctionExpression(); - } - if (matchKeyword('this')) { - lex(); - expr = delegate.createThisExpression(); - } else { - throwUnexpected(lex()); - } - } else if (type === Token.BooleanLiteral) { - token = lex(); - token.value = (token.value === 'true'); - expr = delegate.createLiteral(token); - } else if (type === Token.NullLiteral) { - token = lex(); - token.value = null; - expr = delegate.createLiteral(token); - } else if (match('/') || match('/=')) { - if (typeof extra.tokens !== 'undefined') { - expr = delegate.createLiteral(collectRegex()); - } else { - expr = delegate.createLiteral(scanRegExp()); - } - peek(); - } else { - throwUnexpected(lex()); - } - - return delegate.markEnd(expr, startToken); - } - - // 11.2 Left-Hand-Side Expressions - - function parseArguments() { - var args = []; - - expect('('); - - if (!match(')')) { - while (index < length) { - args.push(parseAssignmentExpression()); - if (match(')')) { - break; - } - expect(','); - } - } - - expect(')'); - - return args; - } - - function parseNonComputedProperty() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - if (!isIdentifierName(token)) { - throwUnexpected(token); - } - - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); - } - - function parseNonComputedMember() { - expect('.'); - - return parseNonComputedProperty(); - } - - function parseComputedMember() { - var expr; - - expect('['); - - expr = parseExpression(); - - expect(']'); - - return expr; - } - - function parseNewExpression() { - var callee, args, startToken; - - startToken = lookahead; - expectKeyword('new'); - callee = parseLeftHandSideExpression(); - args = match('(') ? parseArguments() : []; - - return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); - } - - function parseLeftHandSideExpressionAllowCall() { - var expr, args, property, startToken, previousAllowIn = state.allowIn; - - startToken = lookahead; - state.allowIn = true; - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - - for (;;) { - if (match('.')) { - property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); - } else if (match('(')) { - args = parseArguments(); - expr = delegate.createCallExpression(expr, args); - } else if (match('[')) { - property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { - break; - } - delegate.markEnd(expr, startToken); - } - state.allowIn = previousAllowIn; - - return expr; - } - - function parseLeftHandSideExpression() { - var expr, property, startToken; - assert(state.allowIn, 'callee of new expression always allow in keyword.'); - - startToken = lookahead; - - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - - while (match('.') || match('[')) { - if (match('[')) { - property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { - property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); - } - delegate.markEnd(expr, startToken); - } - return expr; - } - - // 11.3 Postfix Expressions - - function parsePostfixExpression() { - var expr, token, startToken = lookahead; - - expr = parseLeftHandSideExpressionAllowCall(); - - if (lookahead.type === Token.Punctuator) { - if ((match('++') || match('--')) && !peekLineTerminator()) { - // 11.3.1, 11.3.2 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); - } - - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - token = lex(); - expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); - } - } - - return expr; - } - - // 11.4 Unary Operators - - function parseUnaryExpression() { - var token, expr, startToken; - - if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { - expr = parsePostfixExpression(); - } else if (match('++') || match('--')) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - // 11.4.4, 11.4.5 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPrefix); - } - - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - } else if (match('+') || match('-') || match('~') || match('!')) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { - throwErrorTolerant({}, Messages.StrictDelete); - } - } else { - expr = parsePostfixExpression(); - } - - return expr; - } - - function binaryPrecedence(token, allowIn) { - var prec = 0; - - if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { - return 0; - } - - switch (token.value) { - case '||': - prec = 1; - break; - - case '&&': - prec = 2; - break; - - case '|': - prec = 3; - break; - - case '^': - prec = 4; - break; - - case '&': - prec = 5; - break; - - case '==': - case '!=': - case '===': - case '!==': - prec = 6; - break; - - case '<': - case '>': - case '<=': - case '>=': - case 'instanceof': - prec = 7; - break; - - case 'in': - prec = allowIn ? 7 : 0; - break; - - case '<<': - case '>>': - case '>>>': - prec = 8; - break; - - case '+': - case '-': - prec = 9; - break; - - case '*': - case '/': - case '%': - prec = 11; - break; - - default: - break; - } - - return prec; - } - - // 11.5 Multiplicative Operators - // 11.6 Additive Operators - // 11.7 Bitwise Shift Operators - // 11.8 Relational Operators - // 11.9 Equality Operators - // 11.10 Binary Bitwise Operators - // 11.11 Binary Logical Operators - - function parseBinaryExpression() { - var marker, markers, expr, token, prec, stack, right, operator, left, i; - - marker = lookahead; - left = parseUnaryExpression(); - - token = lookahead; - prec = binaryPrecedence(token, state.allowIn); - if (prec === 0) { - return left; - } - token.prec = prec; - lex(); - - markers = [marker, lookahead]; - right = parseUnaryExpression(); - - stack = [left, token, right]; - - while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { - - // Reduce: make a binary expression from the three topmost entries. - while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { - right = stack.pop(); - operator = stack.pop().value; - left = stack.pop(); - expr = delegate.createBinaryExpression(operator, left, right); - markers.pop(); - marker = markers[markers.length - 1]; - delegate.markEnd(expr, marker); - stack.push(expr); - } - - // Shift. - token = lex(); - token.prec = prec; - stack.push(token); - markers.push(lookahead); - expr = parseUnaryExpression(); - stack.push(expr); - } - - // Final reduce to clean-up the stack. - i = stack.length - 1; - expr = stack[i]; - markers.pop(); - while (i > 1) { - expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); - i -= 2; - marker = markers.pop(); - delegate.markEnd(expr, marker); - } - - return expr; - } - - - // 11.12 Conditional Operator - - function parseConditionalExpression() { - var expr, previousAllowIn, consequent, alternate, startToken; - - startToken = lookahead; - - expr = parseBinaryExpression(); - - if (match('?')) { - lex(); - previousAllowIn = state.allowIn; - state.allowIn = true; - consequent = parseAssignmentExpression(); - state.allowIn = previousAllowIn; - expect(':'); - alternate = parseAssignmentExpression(); - - expr = delegate.createConditionalExpression(expr, consequent, alternate); - delegate.markEnd(expr, startToken); - } - - return expr; - } - - // 11.13 Assignment Operators - - function parseAssignmentExpression() { - var token, left, right, node, startToken; - - token = lookahead; - startToken = lookahead; - - node = left = parseConditionalExpression(); - - if (matchAssign()) { - // LeftHandSideExpression - if (!isLeftHandSide(left)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - // 11.13.1 - if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { - throwErrorTolerant(token, Messages.StrictLHSAssignment); - } - - token = lex(); - right = parseAssignmentExpression(); - node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); - } - - return node; - } - - // 11.14 Comma Operator - - function parseExpression() { - var expr, startToken = lookahead; - - expr = parseAssignmentExpression(); - - if (match(',')) { - expr = delegate.createSequenceExpression([ expr ]); - - while (index < length) { - if (!match(',')) { - break; - } - lex(); - expr.expressions.push(parseAssignmentExpression()); - } - - delegate.markEnd(expr, startToken); - } - - return expr; - } - - // 12.1 Block - - function parseStatementList() { - var list = [], - statement; - - while (index < length) { - if (match('}')) { - break; - } - statement = parseSourceElement(); - if (typeof statement === 'undefined') { - break; - } - list.push(statement); - } - - return list; - } - - function parseBlock() { - var block, startToken; - - startToken = lookahead; - expect('{'); - - block = parseStatementList(); - - expect('}'); - - return delegate.markEnd(delegate.createBlockStatement(block), startToken); - } - - // 12.2 Variable Statement - - function parseVariableIdentifier() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - if (token.type !== Token.Identifier) { - throwUnexpected(token); - } - - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); - } - - function parseVariableDeclaration(kind) { - var init = null, id, startToken; - - startToken = lookahead; - id = parseVariableIdentifier(); - - // 12.2.1 - if (strict && isRestrictedWord(id.name)) { - throwErrorTolerant({}, Messages.StrictVarName); - } - - if (kind === 'const') { - expect('='); - init = parseAssignmentExpression(); - } else if (match('=')) { - lex(); - init = parseAssignmentExpression(); - } - - return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); - } - - function parseVariableDeclarationList(kind) { - var list = []; - - do { - list.push(parseVariableDeclaration(kind)); - if (!match(',')) { - break; - } - lex(); - } while (index < length); - - return list; - } - - function parseVariableStatement() { - var declarations; - - expectKeyword('var'); - - declarations = parseVariableDeclarationList(); - - consumeSemicolon(); - - return delegate.createVariableDeclaration(declarations, 'var'); - } - - // kind may be `const` or `let` - // Both are experimental and not in the specification yet. - // see http://wiki.ecmascript.org/doku.php?id=harmony:const - // and http://wiki.ecmascript.org/doku.php?id=harmony:let - function parseConstLetDeclaration(kind) { - var declarations, startToken; - - startToken = lookahead; - - expectKeyword(kind); - - declarations = parseVariableDeclarationList(kind); - - consumeSemicolon(); - - return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); - } - - // 12.3 Empty Statement - - function parseEmptyStatement() { - expect(';'); - return delegate.createEmptyStatement(); - } - - // 12.4 Expression Statement - - function parseExpressionStatement() { - var expr = parseExpression(); - consumeSemicolon(); - return delegate.createExpressionStatement(expr); - } - - // 12.5 If statement - - function parseIfStatement() { - var test, consequent, alternate; - - expectKeyword('if'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - consequent = parseStatement(); - - if (matchKeyword('else')) { - lex(); - alternate = parseStatement(); - } else { - alternate = null; - } - - return delegate.createIfStatement(test, consequent, alternate); - } - - // 12.6 Iteration Statements - - function parseDoWhileStatement() { - var body, test, oldInIteration; - - expectKeyword('do'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - if (match(';')) { - lex(); - } - - return delegate.createDoWhileStatement(body, test); - } - - function parseWhileStatement() { - var test, body, oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - return delegate.createWhileStatement(test, body); - } - - function parseForVariableDeclaration() { - var token, declarations, startToken; - - startToken = lookahead; - token = lex(); - declarations = parseVariableDeclarationList(); - - return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); - } - - function parseForStatement() { - var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; - - init = test = update = null; - - expectKeyword('for'); - - expect('('); - - if (match(';')) { - lex(); - } else { - if (matchKeyword('var') || matchKeyword('let')) { - state.allowIn = false; - init = parseForVariableDeclaration(); - state.allowIn = previousAllowIn; - - if (init.declarations.length === 1 && matchKeyword('in')) { - lex(); - left = init; - right = parseExpression(); - init = null; - } - } else { - state.allowIn = false; - init = parseExpression(); - state.allowIn = previousAllowIn; - - if (matchKeyword('in')) { - // LeftHandSideExpression - if (!isLeftHandSide(init)) { - throwErrorTolerant({}, Messages.InvalidLHSInForIn); - } - - lex(); - left = init; - right = parseExpression(); - init = null; - } - } - - if (typeof left === 'undefined') { - expect(';'); - } - } - - if (typeof left === 'undefined') { - - if (!match(';')) { - test = parseExpression(); - } - expect(';'); - - if (!match(')')) { - update = parseExpression(); - } - } - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - return (typeof left === 'undefined') ? - delegate.createForStatement(init, test, update, body) : - delegate.createForInStatement(left, right, body); - } - - // 12.7 The continue statement - - function parseContinueStatement() { - var label = null, key; - - expectKeyword('continue'); - - // Optimize the most common form: 'continue;'. - if (source.charCodeAt(index) === 0x3B) { - lex(); - - if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(null); - } - - if (peekLineTerminator()) { - if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(null); - } - - if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(label); - } - - // 12.8 The break statement - - function parseBreakStatement() { - var label = null, key; - - expectKeyword('break'); - - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(index) === 0x3B) { - lex(); - - if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(null); - } - - if (peekLineTerminator()) { - if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(null); - } - - if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(label); - } - - // 12.9 The return statement - - function parseReturnStatement() { - var argument = null; - - expectKeyword('return'); - - if (!state.inFunctionBody) { - throwErrorTolerant({}, Messages.IllegalReturn); - } - - // 'return' followed by a space and an identifier is very common. - if (source.charCodeAt(index) === 0x20) { - if (isIdentifierStart(source.charCodeAt(index + 1))) { - argument = parseExpression(); - consumeSemicolon(); - return delegate.createReturnStatement(argument); - } - } - - if (peekLineTerminator()) { - return delegate.createReturnStatement(null); - } - - if (!match(';')) { - if (!match('}') && lookahead.type !== Token.EOF) { - argument = parseExpression(); - } - } - - consumeSemicolon(); - - return delegate.createReturnStatement(argument); - } - - // 12.10 The with statement - - function parseWithStatement() { - var object, body; - - if (strict) { - // TODO(ikarienator): Should we update the test cases instead? - skipComment(); - throwErrorTolerant({}, Messages.StrictModeWith); - } - - expectKeyword('with'); - - expect('('); - - object = parseExpression(); - - expect(')'); - - body = parseStatement(); - - return delegate.createWithStatement(object, body); - } - - // 12.10 The swith statement - - function parseSwitchCase() { - var test, consequent = [], statement, startToken; - - startToken = lookahead; - if (matchKeyword('default')) { - lex(); - test = null; - } else { - expectKeyword('case'); - test = parseExpression(); - } - expect(':'); - - while (index < length) { - if (match('}') || matchKeyword('default') || matchKeyword('case')) { - break; - } - statement = parseStatement(); - consequent.push(statement); - } - - return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); - } - - function parseSwitchStatement() { - var discriminant, cases, clause, oldInSwitch, defaultFound; - - expectKeyword('switch'); - - expect('('); - - discriminant = parseExpression(); - - expect(')'); - - expect('{'); - - cases = []; - - if (match('}')) { - lex(); - return delegate.createSwitchStatement(discriminant, cases); - } - - oldInSwitch = state.inSwitch; - state.inSwitch = true; - defaultFound = false; - - while (index < length) { - if (match('}')) { - break; - } - clause = parseSwitchCase(); - if (clause.test === null) { - if (defaultFound) { - throwError({}, Messages.MultipleDefaultsInSwitch); - } - defaultFound = true; - } - cases.push(clause); - } - - state.inSwitch = oldInSwitch; - - expect('}'); - - return delegate.createSwitchStatement(discriminant, cases); - } - - // 12.13 The throw statement - - function parseThrowStatement() { - var argument; - - expectKeyword('throw'); - - if (peekLineTerminator()) { - throwError({}, Messages.NewlineAfterThrow); - } - - argument = parseExpression(); - - consumeSemicolon(); - - return delegate.createThrowStatement(argument); - } - - // 12.14 The try statement - - function parseCatchClause() { - var param, body, startToken; - - startToken = lookahead; - expectKeyword('catch'); - - expect('('); - if (match(')')) { - throwUnexpected(lookahead); - } - - param = parseVariableIdentifier(); - // 12.14.1 - if (strict && isRestrictedWord(param.name)) { - throwErrorTolerant({}, Messages.StrictCatchVariable); - } - - expect(')'); - body = parseBlock(); - return delegate.markEnd(delegate.createCatchClause(param, body), startToken); - } - - function parseTryStatement() { - var block, handlers = [], finalizer = null; - - expectKeyword('try'); - - block = parseBlock(); - - if (matchKeyword('catch')) { - handlers.push(parseCatchClause()); - } - - if (matchKeyword('finally')) { - lex(); - finalizer = parseBlock(); - } - - if (handlers.length === 0 && !finalizer) { - throwError({}, Messages.NoCatchOrFinally); - } - - return delegate.createTryStatement(block, [], handlers, finalizer); - } - - // 12.15 The debugger statement - - function parseDebuggerStatement() { - expectKeyword('debugger'); - - consumeSemicolon(); - - return delegate.createDebuggerStatement(); - } - - // 12 Statements - - function parseStatement() { - var type = lookahead.type, - expr, - labeledBody, - key, - startToken; - - if (type === Token.EOF) { - throwUnexpected(lookahead); - } - - if (type === Token.Punctuator && lookahead.value === '{') { - return parseBlock(); - } - - startToken = lookahead; - - if (type === Token.Punctuator) { - switch (lookahead.value) { - case ';': - return delegate.markEnd(parseEmptyStatement(), startToken); - case '(': - return delegate.markEnd(parseExpressionStatement(), startToken); - default: - break; - } - } - - if (type === Token.Keyword) { - switch (lookahead.value) { - case 'break': - return delegate.markEnd(parseBreakStatement(), startToken); - case 'continue': - return delegate.markEnd(parseContinueStatement(), startToken); - case 'debugger': - return delegate.markEnd(parseDebuggerStatement(), startToken); - case 'do': - return delegate.markEnd(parseDoWhileStatement(), startToken); - case 'for': - return delegate.markEnd(parseForStatement(), startToken); - case 'function': - return delegate.markEnd(parseFunctionDeclaration(), startToken); - case 'if': - return delegate.markEnd(parseIfStatement(), startToken); - case 'return': - return delegate.markEnd(parseReturnStatement(), startToken); - case 'switch': - return delegate.markEnd(parseSwitchStatement(), startToken); - case 'throw': - return delegate.markEnd(parseThrowStatement(), startToken); - case 'try': - return delegate.markEnd(parseTryStatement(), startToken); - case 'var': - return delegate.markEnd(parseVariableStatement(), startToken); - case 'while': - return delegate.markEnd(parseWhileStatement(), startToken); - case 'with': - return delegate.markEnd(parseWithStatement(), startToken); - default: - break; - } - } - - expr = parseExpression(); - - // 12.12 Labelled Statements - if ((expr.type === Syntax.Identifier) && match(':')) { - lex(); - - key = '$' + expr.name; - if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.Redeclaration, 'Label', expr.name); - } - - state.labelSet[key] = true; - labeledBody = parseStatement(); - delete state.labelSet[key]; - return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); - } - - consumeSemicolon(); - - return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); - } - - // 13 Function Definition - - function parseFunctionSourceElements() { - var sourceElement, sourceElements = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; - - startToken = lookahead; - expect('{'); - - while (index < length) { - if (lookahead.type !== Token.StringLiteral) { - break; - } - token = lookahead; - - sourceElement = parseSourceElement(); - sourceElements.push(sourceElement); - if (sourceElement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - oldLabelSet = state.labelSet; - oldInIteration = state.inIteration; - oldInSwitch = state.inSwitch; - oldInFunctionBody = state.inFunctionBody; - - state.labelSet = {}; - state.inIteration = false; - state.inSwitch = false; - state.inFunctionBody = true; - - while (index < length) { - if (match('}')) { - break; - } - sourceElement = parseSourceElement(); - if (typeof sourceElement === 'undefined') { - break; - } - sourceElements.push(sourceElement); - } - - expect('}'); - - state.labelSet = oldLabelSet; - state.inIteration = oldInIteration; - state.inSwitch = oldInSwitch; - state.inFunctionBody = oldInFunctionBody; - - return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); - } - - function parseParams(firstRestricted) { - var param, params = [], token, stricted, paramSet, key, message; - expect('('); - - if (!match(')')) { - paramSet = {}; - while (index < length) { - token = lookahead; - param = parseVariableIdentifier(); - key = '$' + token.value; - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[key] = true; - if (match(')')) { - break; - } - expect(','); - } - } - - expect(')'); - - return { - params: params, - stricted: stricted, - firstRestricted: firstRestricted, - message: message - }; - } - - function parseFunctionDeclaration() { - var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; - - startToken = lookahead; - - expectKeyword('function'); - token = lookahead; - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - - tmp = parseParams(firstRestricted); - params = tmp.params; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwError(firstRestricted, message); - } - if (strict && stricted) { - throwErrorTolerant(stricted, message); - } - strict = previousStrict; - - return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); - } - - function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; - - startToken = lookahead; - expectKeyword('function'); - - if (!match('(')) { - token = lookahead; - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - } - - tmp = parseParams(firstRestricted); - params = tmp.params; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwError(firstRestricted, message); - } - if (strict && stricted) { - throwErrorTolerant(stricted, message); - } - strict = previousStrict; - - return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); - } - - // 14 Program - - function parseSourceElement() { - if (lookahead.type === Token.Keyword) { - switch (lookahead.value) { - case 'const': - case 'let': - return parseConstLetDeclaration(lookahead.value); - case 'function': - return parseFunctionDeclaration(); - default: - return parseStatement(); - } - } - - if (lookahead.type !== Token.EOF) { - return parseStatement(); - } - } - - function parseSourceElements() { - var sourceElement, sourceElements = [], token, directive, firstRestricted; - - while (index < length) { - token = lookahead; - if (token.type !== Token.StringLiteral) { - break; - } - - sourceElement = parseSourceElement(); - sourceElements.push(sourceElement); - if (sourceElement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - while (index < length) { - sourceElement = parseSourceElement(); - /* istanbul ignore if */ - if (typeof sourceElement === 'undefined') { - break; - } - sourceElements.push(sourceElement); - } - return sourceElements; - } - - function parseProgram() { - var body, startToken; - - skipComment(); - peek(); - startToken = lookahead; - strict = false; - - body = parseSourceElements(); - return delegate.markEnd(delegate.createProgram(body), startToken); - } - - function filterTokenLocation() { - var i, entry, token, tokens = []; - - for (i = 0; i < extra.tokens.length; ++i) { - entry = extra.tokens[i]; - token = { - type: entry.type, - value: entry.value - }; - if (extra.range) { - token.range = entry.range; - } - if (extra.loc) { - token.loc = entry.loc; - } - tokens.push(token); - } - - extra.tokens = tokens; - } - - function tokenize(code, options) { - var toString, - token, - tokens; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - delegate = SyntaxTreeDelegate; - source = code; - index = 0; - lineNumber = (source.length > 0) ? 1 : 0; - lineStart = 0; - length = source.length; - lookahead = null; - state = { - allowIn: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1 - }; - - extra = {}; - - // Options matching. - options = options || {}; - - // Of course we collect tokens here. - options.tokens = true; - extra.tokens = []; - extra.tokenize = true; - // The following two fields are necessary to compute the Regex tokens. - extra.openParenToken = -1; - extra.openCurlyToken = -1; - - extra.range = (typeof options.range === 'boolean') && options.range; - extra.loc = (typeof options.loc === 'boolean') && options.loc; - - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - - try { - peek(); - if (lookahead.type === Token.EOF) { - return extra.tokens; - } - - token = lex(); - while (lookahead.type !== Token.EOF) { - try { - token = lex(); - } catch (lexError) { - token = lookahead; - if (extra.errors) { - extra.errors.push(lexError); - // We have to break on the first error - // to avoid infinite loops. - break; - } else { - throw lexError; - } - } - } - - filterTokenLocation(); - tokens = extra.tokens; - if (typeof extra.comments !== 'undefined') { - tokens.comments = extra.comments; - } - if (typeof extra.errors !== 'undefined') { - tokens.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - return tokens; - } - - function parse(code, options) { - var program, toString; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - delegate = SyntaxTreeDelegate; - source = code; - index = 0; - lineNumber = (source.length > 0) ? 1 : 0; - lineStart = 0; - length = source.length; - lookahead = null; - state = { - allowIn: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1 - }; - - extra = {}; - if (typeof options !== 'undefined') { - extra.range = (typeof options.range === 'boolean') && options.range; - extra.loc = (typeof options.loc === 'boolean') && options.loc; - extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; - - if (extra.loc && options.source !== null && options.source !== undefined) { - extra.source = toString(options.source); - } - - if (typeof options.tokens === 'boolean' && options.tokens) { - extra.tokens = []; - } - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - if (extra.attachComment) { - extra.range = true; - extra.comments = []; - extra.bottomRightStack = []; - extra.trailingComments = []; - extra.leadingComments = []; - } - } - - try { - program = parseProgram(); - if (typeof extra.comments !== 'undefined') { - program.comments = extra.comments; - } - if (typeof extra.tokens !== 'undefined') { - filterTokenLocation(); - program.tokens = extra.tokens; - } - if (typeof extra.errors !== 'undefined') { - program.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - - return program; - } - - // Sync with *.json manifests. - exports.version = '1.2.4'; - - exports.tokenize = tokenize; - - exports.parse = parse; - - // Deep copy. - /* istanbul ignore next */ - exports.Syntax = (function () { - var name, types = {}; - - if (typeof Object.create === 'function') { - types = Object.create(null); - } - - for (name in Syntax) { - if (Syntax.hasOwnProperty(name)) { - types[name] = Syntax[name]; - } - } - - if (typeof Object.freeze === 'function') { - Object.freeze(types); - } - - return types; - }()); - -})); -/* vim: set sw=4 ts=4 et tw=80 : */ - -},{}],22:[function(_dereq_,module,exports){ -/** - * power-assert-formatter.js - Power Assert output formatter - * - * https://github.com/twada/power-assert-formatter - * - * Copyright (c) 2013-2015 Takuto Wada - * Licensed under the MIT license. - * https://github.com/twada/power-assert-formatter/blob/master/MIT-LICENSE.txt - */ -'use strict'; - -module.exports = _dereq_('./lib/create'); - -},{"./lib/create":27}],23:[function(_dereq_,module,exports){ -'use strict'; - -function AssertionRenderer (traversal, config) { - var assertionLine; - traversal.on('start', function (context) { - assertionLine = context.source.content; - }); - traversal.on('render', function (writer) { - writer.write(''); - writer.write(assertionLine); - }); -} -module.exports = AssertionRenderer; - -},{}],24:[function(_dereq_,module,exports){ -'use strict'; - -var typeName = _dereq_('type-name'), - keys = Object.keys || _dereq_('object-keys'), - syntax = _dereq_('estraverse').Syntax; - - -function BinaryExpressionRenderer(traversal, config) { - this.config = config; - this.stringify = config.stringify; - this.diff = config.diff; - this.espathToPair = {}; - var _this = this; - traversal.on('esnode', function (esNode) { - var pair; - if (!esNode.isCaptured()) { - if (isTargetBinaryExpression(esNode.getParent()) && esNode.currentNode.type === syntax.Literal) { - _this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()}; - } - return; - } - if (isTargetBinaryExpression(esNode.getParent())) { - _this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()}; - } - if (isTargetBinaryExpression(esNode)) { - pair = { - operator: esNode.currentNode.operator, - value: esNode.value() - }; - _this.espathToPair[esNode.espath] = pair; - } - }); - traversal.on('render', function (writer) { - var pairs = []; - keys(_this.espathToPair).forEach(function (espath) { - var pair = _this.espathToPair[espath]; - if (pair.left && pair.right) { - pairs.push(pair); - } - }); - pairs.forEach(function (pair) { - _this.compare(pair, writer); - }); - }); -} - -BinaryExpressionRenderer.prototype.compare = function (pair, writer) { - if (isStringDiffTarget(pair)) { - this.showStringDiff(pair, writer); - } else { - this.showExpectedAndActual(pair, writer); - } -}; - -BinaryExpressionRenderer.prototype.showExpectedAndActual = function (pair, writer) { - writer.write(''); - writer.write('[' + typeName(pair.right.value) + '] ' + pair.right.code); - writer.write('=> ' + this.stringify(pair.right.value)); - writer.write('[' + typeName(pair.left.value) + '] ' + pair.left.code); - writer.write('=> ' + this.stringify(pair.left.value)); -}; - -BinaryExpressionRenderer.prototype.showStringDiff = function (pair, writer) { - writer.write(''); - writer.write('--- [string] ' + pair.right.code); - writer.write('+++ [string] ' + pair.left.code); - writer.write(this.diff(pair.right.value, pair.left.value, this.config)); -}; - -function isTargetBinaryExpression (esNode) { - return esNode && - esNode.currentNode.type === syntax.BinaryExpression && - (esNode.currentNode.operator === '===' || esNode.currentNode.operator === '==') && - esNode.isCaptured() && - !(esNode.value()); -} - -function isStringDiffTarget(pair) { - return typeof pair.left.value === 'string' && typeof pair.right.value === 'string'; -} - -module.exports = BinaryExpressionRenderer; - -},{"estraverse":36,"object-keys":39,"type-name":43}],25:[function(_dereq_,module,exports){ -'use strict'; - -function DiagramRenderer (traversal, config) { - this.config = config; - this.events = []; - this.stringify = config.stringify; - this.widthOf = config.widthOf; - this.initialVertivalBarLength = 1; - var _this = this; - traversal.on('start', function (context) { - _this.context = context; - _this.assertionLine = context.source.content; - _this.initializeRows(); - }); - traversal.on('esnode', function (esNode) { - if (!esNode.isCaptured()) { - return; - } - _this.events.push({value: esNode.value(), loc: esNode.location()}); - }); - traversal.on('render', function (writer) { - _this.events.sort(rightToLeft); - _this.constructRows(_this.events); - _this.rows.forEach(function (columns) { - writer.write(columns.join('')); - }); - }); -} - -DiagramRenderer.prototype.initializeRows = function () { - this.rows = []; - for (var i = 0; i <= this.initialVertivalBarLength; i += 1) { - this.addOneMoreRow(); - } -}; - -DiagramRenderer.prototype.newRowFor = function (assertionLine) { - return createRow(this.widthOf(assertionLine), ' '); -}; - -DiagramRenderer.prototype.addOneMoreRow = function () { - this.rows.push(this.newRowFor(this.assertionLine)); -}; - -DiagramRenderer.prototype.lastRow = function () { - return this.rows[this.rows.length - 1]; -}; - -DiagramRenderer.prototype.renderVerticalBarAt = function (columnIndex) { - var i, lastRowIndex = this.rows.length - 1; - for (i = 0; i < lastRowIndex; i += 1) { - this.rows[i].splice(columnIndex, 1, '|'); - } -}; - -DiagramRenderer.prototype.renderValueAt = function (columnIndex, dumpedValue) { - var i, width = this.widthOf(dumpedValue); - for (i = 0; i < width; i += 1) { - this.lastRow().splice(columnIndex + i, 1, dumpedValue.charAt(i)); - } -}; - -DiagramRenderer.prototype.isOverlapped = function (prevCapturing, nextCaputuring, dumpedValue) { - return (typeof prevCapturing !== 'undefined') && this.startColumnFor(prevCapturing) <= (this.startColumnFor(nextCaputuring) + this.widthOf(dumpedValue)); -}; - -DiagramRenderer.prototype.constructRows = function (capturedEvents) { - var that = this, - prevCaptured; - capturedEvents.forEach(function (captured) { - var dumpedValue = that.stringify(captured.value); - if (that.isOverlapped(prevCaptured, captured, dumpedValue)) { - that.addOneMoreRow(); - } - that.renderVerticalBarAt(that.startColumnFor(captured)); - that.renderValueAt(that.startColumnFor(captured), dumpedValue); - prevCaptured = captured; - }); -}; - -DiagramRenderer.prototype.startColumnFor = function (captured) { - return this.widthOf(this.assertionLine.slice(0, captured.loc.start.column)); -}; - -function createRow (numCols, initial) { - var row = [], i; - for(i = 0; i < numCols; i += 1) { - row[i] = initial; - } - return row; -} - -function rightToLeft (a, b) { - return b.loc.start.column - a.loc.start.column; -} - -module.exports = DiagramRenderer; - -},{}],26:[function(_dereq_,module,exports){ -'use strict'; - -function FileRenderer (traversal, config) { - var filepath, lineNumber; - traversal.on('start', function (context) { - filepath = context.source.filepath; - lineNumber = context.source.line; - }); - traversal.on('render', function (writer) { - if (filepath) { - writer.write('# ' + [filepath, lineNumber].join(':')); - } else { - writer.write('# at line: ' + lineNumber); - } - }); -} -module.exports = FileRenderer; - -},{}],27:[function(_dereq_,module,exports){ -'use strict'; - -var stringifier = _dereq_('stringifier'), - stringWidth = _dereq_('./string-width'), - StringWriter = _dereq_('./string-writer'), - ContextTraversal = _dereq_('./traverse'), - udiff = _dereq_('./udiff'), - defaultOptions = _dereq_('./default-options'), - typeName = _dereq_('type-name'), - extend = _dereq_('xtend'); - -(function() { - // "Browserify can only analyze static requires. It is not in the scope of browserify to handle dynamic requires." - // https://github.com/substack/node-browserify/issues/377 - _dereq_('./built-in/assertion'); - _dereq_('./built-in/binary-expression'); - _dereq_('./built-in/diagram'); - _dereq_('./built-in/file'); -})(); - -function create (options) { - var config = extend(defaultOptions(), options); - if (typeof config.widthOf !== 'function') { - config.widthOf = stringWidth(extend(config)); - } - if (typeof config.stringify !== 'function') { - config.stringify = stringifier(extend(config)); - } - if (typeof config.diff !== 'function') { - config.diff = udiff(extend(config)); - } - if (!config.writerClass) { - config.writerClass = StringWriter; - } - return function (context) { - var traversal = new ContextTraversal(context); - var writer = new config.writerClass(extend(config)); - var renderers = config.renderers.map(function (rendererName) { - var RendererClass; - if (typeName(rendererName) === 'function') { - RendererClass = rendererName; - } else if (typeName(rendererName) === 'string') { - RendererClass = _dereq_(rendererName); - } - return new RendererClass(traversal, extend(config)); - }); - traversal.emit('start', context); - traversal.traverse(); - traversal.emit('render', writer); - writer.write(''); - renderers.length = 0; - return writer.flush(); - }; -} - -create.defaultOptions = defaultOptions; -create.stringWidth = stringWidth; -module.exports = create; - -},{"./built-in/assertion":23,"./built-in/binary-expression":24,"./built-in/diagram":25,"./built-in/file":26,"./default-options":28,"./string-width":31,"./string-writer":32,"./traverse":33,"./udiff":34,"stringifier":41,"type-name":43,"xtend":45}],28:[function(_dereq_,module,exports){ -module.exports = function defaultOptions () { - 'use strict'; - return { - lineDiffThreshold: 5, - maxDepth: 1, - outputOffset: 2, - anonymous: 'Object', - circular: '#@Circular#', - lineSeparator: '\n', - ambiguousEastAsianCharWidth: 2, - renderers: [ - './built-in/file', - './built-in/assertion', - './built-in/diagram', - './built-in/binary-expression' - ] - }; -}; - -},{}],29:[function(_dereq_,module,exports){ -'use strict'; - -var syntax = _dereq_('estraverse').Syntax, - locationOf = _dereq_('./location'); - -function EsNode (path, currentNode, parentNode, espathToValue, jsCode, jsAST) { - if (path) { - this.espath = path.join('/'); - this.parentEspath = path.slice(0, path.length - 1).join('/'); - this.currentProp = path[path.length - 1]; - } else { - this.espath = ''; - this.parentEspath = ''; - this.currentProp = null; - } - this.currentNode = currentNode; - this.parentNode = parentNode; - this.parentEsNode = null; - this.espathToValue = espathToValue; - this.jsCode = jsCode; - this.jsAST = jsAST; -} - -EsNode.prototype.setParent = function (parentEsNode) { - this.parentEsNode = parentEsNode; -}; - -EsNode.prototype.getParent = function () { - return this.parentEsNode; -}; - -EsNode.prototype.code = function () { - return this.jsCode.slice(this.currentNode.loc.start.column, this.currentNode.loc.end.column); -}; - -EsNode.prototype.value = function () { - if (this.currentNode.type === syntax.Literal) { - return this.currentNode.value; - } - return this.espathToValue[this.espath]; -}; - -EsNode.prototype.isCaptured = function () { - return this.espathToValue.hasOwnProperty(this.espath); -}; - -EsNode.prototype.location = function () { - return locationOf(this.currentNode, this.jsAST.tokens); -}; - -module.exports = EsNode; - -},{"./location":30,"estraverse":36}],30:[function(_dereq_,module,exports){ -'use strict'; - -var syntax = _dereq_('estraverse').Syntax; - -function locationOf(currentNode, tokens) { - switch(currentNode.type) { - case syntax.MemberExpression: - return propertyLocationOf(currentNode, tokens); - case syntax.CallExpression: - if (currentNode.callee.type === syntax.MemberExpression) { - return propertyLocationOf(currentNode.callee, tokens); - } - break; - case syntax.BinaryExpression: - case syntax.LogicalExpression: - case syntax.AssignmentExpression: - return infixOperatorLocationOf(currentNode, tokens); - default: - break; - } - return currentNode.loc; -} - -function propertyLocationOf(memberExpression, tokens) { - var prop = memberExpression.property, - token; - if (!memberExpression.computed) { - return prop.loc; - } - token = findLeftBracketTokenOf(memberExpression, tokens); - return token ? token.loc : prop.loc; -} - -// calculate location of infix operator for BinaryExpression, AssignmentExpression and LogicalExpression. -function infixOperatorLocationOf (expression, tokens) { - var token = findOperatorTokenOf(expression, tokens); - return token ? token.loc : expression.left.loc; -} - -function findLeftBracketTokenOf(expression, tokens) { - var fromLine = expression.loc.start.line, - toLine = expression.property.loc.start.line, - fromColumn = expression.property.loc.start.column; - return searchToken(tokens, fromLine, toLine, function (token, index) { - var prevToken; - if (token.loc.start.column === fromColumn) { - prevToken = tokens[index - 1]; - if (prevToken.type === 'Punctuator' && prevToken.value === '[') { - return prevToken; - } - } - return undefined; - }); -} - -function findOperatorTokenOf(expression, tokens) { - var fromLine = expression.left.loc.end.line, - toLine = expression.right.loc.start.line, - fromColumn = expression.left.loc.end.column, - toColumn = expression.right.loc.start.column; - return searchToken(tokens, fromLine, toLine, function (token, index) { - if (fromColumn < token.loc.start.column && - token.loc.end.column < toColumn && - token.type === 'Punctuator' && - token.value === expression.operator) { - return token; - } - return undefined; - }); -} - -function searchToken(tokens, fromLine, toLine, predicate) { - var i, token, found; - for(i = 0; i < tokens.length; i += 1) { - token = tokens[i]; - if (token.loc.start.line < fromLine) { - continue; - } - if (toLine < token.loc.end.line) { - break; - } - found = predicate(token, i); - if (found) { - return found; - } - } - return undefined; -} - -module.exports = locationOf; - -},{"estraverse":36}],31:[function(_dereq_,module,exports){ -'use strict'; - -var eaw = _dereq_('eastasianwidth'); - -function stringWidth (config) { - var ambiguousCharWidth = (config && config.ambiguousEastAsianCharWidth) || 1; - return function widthOf (str) { - var i, code, width = 0; - for(i = 0; i < str.length; i+=1) { - code = eaw.eastAsianWidth(str.charAt(i)); - switch(code) { - case 'F': - case 'W': - width += 2; - break; - case 'H': - case 'Na': - case 'N': - width += 1; - break; - case 'A': - width += ambiguousCharWidth; - break; - } - } - return width; - }; -} - -module.exports = stringWidth; - -},{"eastasianwidth":35}],32:[function(_dereq_,module,exports){ -'use strict'; - -function spacerStr (len) { - var str = ''; - for(var i = 0; i < len; i += 1) { - str += ' '; - } - return str; -} - -function StringWriter (config) { - this.lines = []; - this.lineSeparator = config.lineSeparator; - this.regex = new RegExp(this.lineSeparator, 'g'); - this.spacer = spacerStr(config.outputOffset); -} - -StringWriter.prototype.write = function (str) { - this.lines.push(this.spacer + str.replace(this.regex, this.lineSeparator + this.spacer)); -}; - -StringWriter.prototype.flush = function () { - var str = this.lines.join(this.lineSeparator); - this.lines.length = 0; - return str; -}; - -module.exports = StringWriter; - -},{}],33:[function(_dereq_,module,exports){ -'use strict'; - -var estraverse = _dereq_('estraverse'), - esprima = _dereq_('esprima'), - EventEmitter = _dereq_('events').EventEmitter, - inherits = _dereq_('util').inherits, - EsNode = _dereq_('./esnode'); - -function ContextTraversal (context) { - this.context = context; - EventEmitter.call(this); -} -inherits(ContextTraversal, EventEmitter); - -ContextTraversal.prototype.traverse = function () { - var _this = this; - this.context.args.forEach(function (arg) { - onEachEsNode(arg, _this.context.source.content, function (esNode) { - _this.emit('esnode', esNode); - }); - }); -}; - -function onEachEsNode(arg, jsCode, callback) { - var jsAST = esprima.parse(jsCode, {tolerant: true, loc: true, tokens: true, raw: true}), - espathToValue = arg.events.reduce(function (accum, ev) { - accum[ev.espath] = ev.value; - return accum; - }, {}), - nodeStack = []; - estraverse.traverse(extractExpressionFrom(jsAST), { - enter: function (currentNode, parentNode) { - var esNode = new EsNode(this.path(), currentNode, parentNode, espathToValue, jsCode, jsAST); - if (1 < nodeStack.length) { - esNode.setParent(nodeStack[nodeStack.length - 1]); - } - nodeStack.push(esNode); - callback(esNode); - }, - leave: function (currentNode, parentNode) { - nodeStack.pop(); - } - }); -} - -function extractExpressionFrom (tree) { - var expressionStatement = tree.body[0], - expression = expressionStatement.expression; - return expression; -} - -module.exports = ContextTraversal; - -},{"./esnode":29,"esprima":21,"estraverse":36,"events":2,"util":6}],34:[function(_dereq_,module,exports){ -'use strict'; - -var DiffMatchPatch = _dereq_('googlediff'), - dmp = new DiffMatchPatch(); - -function udiff (config) { - return function diff (text1, text2) { - var patch; - if (config && shouldUseLineLevelDiff(text1, config)) { - patch = udiffLines(text1, text2); - } else { - patch = udiffChars(text1, text2); - } - return decodeURIComponent(patch); - }; -} - -function shouldUseLineLevelDiff (text, config) { - return config.lineDiffThreshold < text.split(/\r\n|\r|\n/).length; -} - -function udiffLines(text1, text2) { - /*jshint camelcase: false */ - var a = dmp.diff_linesToChars_(text1, text2), - diffs = dmp.diff_main(a.chars1, a.chars2, false); - dmp.diff_charsToLines_(diffs, a.lineArray); - dmp.diff_cleanupSemantic(diffs); - return dmp.patch_toText(dmp.patch_make(text1, diffs)); -} - -function udiffChars (text1, text2) { - /*jshint camelcase: false */ - var diffs = dmp.diff_main(text1, text2, false); - dmp.diff_cleanupSemantic(diffs); - return dmp.patch_toText(dmp.patch_make(text1, diffs)); -} - -module.exports = udiff; - -},{"googlediff":37}],35:[function(_dereq_,module,exports){ -var eaw = exports; - -eaw.eastAsianWidth = function(character) { - var x = character.charCodeAt(0); - var y = (character.length == 2) ? character.charCodeAt(1) : 0; - var codePoint = x; - if ((0xD800 <= x && x <= 0xDBFF) && (0xDC00 <= y && y <= 0xDFFF)) { - x &= 0x3FF; - y &= 0x3FF; - codePoint = (x << 10) | y; - codePoint += 0x10000; - } - - if ((0x3000 == codePoint) || - (0xFF01 <= codePoint && codePoint <= 0xFF60) || - (0xFFE0 <= codePoint && codePoint <= 0xFFE6)) { - return 'F'; - } - if ((0x20A9 == codePoint) || - (0xFF61 <= codePoint && codePoint <= 0xFFBE) || - (0xFFC2 <= codePoint && codePoint <= 0xFFC7) || - (0xFFCA <= codePoint && codePoint <= 0xFFCF) || - (0xFFD2 <= codePoint && codePoint <= 0xFFD7) || - (0xFFDA <= codePoint && codePoint <= 0xFFDC) || - (0xFFE8 <= codePoint && codePoint <= 0xFFEE)) { - return 'H'; - } - if ((0x1100 <= codePoint && codePoint <= 0x115F) || - (0x11A3 <= codePoint && codePoint <= 0x11A7) || - (0x11FA <= codePoint && codePoint <= 0x11FF) || - (0x2329 <= codePoint && codePoint <= 0x232A) || - (0x2E80 <= codePoint && codePoint <= 0x2E99) || - (0x2E9B <= codePoint && codePoint <= 0x2EF3) || - (0x2F00 <= codePoint && codePoint <= 0x2FD5) || - (0x2FF0 <= codePoint && codePoint <= 0x2FFB) || - (0x3001 <= codePoint && codePoint <= 0x303E) || - (0x3041 <= codePoint && codePoint <= 0x3096) || - (0x3099 <= codePoint && codePoint <= 0x30FF) || - (0x3105 <= codePoint && codePoint <= 0x312D) || - (0x3131 <= codePoint && codePoint <= 0x318E) || - (0x3190 <= codePoint && codePoint <= 0x31BA) || - (0x31C0 <= codePoint && codePoint <= 0x31E3) || - (0x31F0 <= codePoint && codePoint <= 0x321E) || - (0x3220 <= codePoint && codePoint <= 0x3247) || - (0x3250 <= codePoint && codePoint <= 0x32FE) || - (0x3300 <= codePoint && codePoint <= 0x4DBF) || - (0x4E00 <= codePoint && codePoint <= 0xA48C) || - (0xA490 <= codePoint && codePoint <= 0xA4C6) || - (0xA960 <= codePoint && codePoint <= 0xA97C) || - (0xAC00 <= codePoint && codePoint <= 0xD7A3) || - (0xD7B0 <= codePoint && codePoint <= 0xD7C6) || - (0xD7CB <= codePoint && codePoint <= 0xD7FB) || - (0xF900 <= codePoint && codePoint <= 0xFAFF) || - (0xFE10 <= codePoint && codePoint <= 0xFE19) || - (0xFE30 <= codePoint && codePoint <= 0xFE52) || - (0xFE54 <= codePoint && codePoint <= 0xFE66) || - (0xFE68 <= codePoint && codePoint <= 0xFE6B) || - (0x1B000 <= codePoint && codePoint <= 0x1B001) || - (0x1F200 <= codePoint && codePoint <= 0x1F202) || - (0x1F210 <= codePoint && codePoint <= 0x1F23A) || - (0x1F240 <= codePoint && codePoint <= 0x1F248) || - (0x1F250 <= codePoint && codePoint <= 0x1F251) || - (0x20000 <= codePoint && codePoint <= 0x2F73F) || - (0x2B740 <= codePoint && codePoint <= 0x2FFFD) || - (0x30000 <= codePoint && codePoint <= 0x3FFFD)) { - return 'W'; - } - if ((0x0020 <= codePoint && codePoint <= 0x007E) || - (0x00A2 <= codePoint && codePoint <= 0x00A3) || - (0x00A5 <= codePoint && codePoint <= 0x00A6) || - (0x00AC == codePoint) || - (0x00AF == codePoint) || - (0x27E6 <= codePoint && codePoint <= 0x27ED) || - (0x2985 <= codePoint && codePoint <= 0x2986)) { - return 'Na'; - } - if ((0x00A1 == codePoint) || - (0x00A4 == codePoint) || - (0x00A7 <= codePoint && codePoint <= 0x00A8) || - (0x00AA == codePoint) || - (0x00AD <= codePoint && codePoint <= 0x00AE) || - (0x00B0 <= codePoint && codePoint <= 0x00B4) || - (0x00B6 <= codePoint && codePoint <= 0x00BA) || - (0x00BC <= codePoint && codePoint <= 0x00BF) || - (0x00C6 == codePoint) || - (0x00D0 == codePoint) || - (0x00D7 <= codePoint && codePoint <= 0x00D8) || - (0x00DE <= codePoint && codePoint <= 0x00E1) || - (0x00E6 == codePoint) || - (0x00E8 <= codePoint && codePoint <= 0x00EA) || - (0x00EC <= codePoint && codePoint <= 0x00ED) || - (0x00F0 == codePoint) || - (0x00F2 <= codePoint && codePoint <= 0x00F3) || - (0x00F7 <= codePoint && codePoint <= 0x00FA) || - (0x00FC == codePoint) || - (0x00FE == codePoint) || - (0x0101 == codePoint) || - (0x0111 == codePoint) || - (0x0113 == codePoint) || - (0x011B == codePoint) || - (0x0126 <= codePoint && codePoint <= 0x0127) || - (0x012B == codePoint) || - (0x0131 <= codePoint && codePoint <= 0x0133) || - (0x0138 == codePoint) || - (0x013F <= codePoint && codePoint <= 0x0142) || - (0x0144 == codePoint) || - (0x0148 <= codePoint && codePoint <= 0x014B) || - (0x014D == codePoint) || - (0x0152 <= codePoint && codePoint <= 0x0153) || - (0x0166 <= codePoint && codePoint <= 0x0167) || - (0x016B == codePoint) || - (0x01CE == codePoint) || - (0x01D0 == codePoint) || - (0x01D2 == codePoint) || - (0x01D4 == codePoint) || - (0x01D6 == codePoint) || - (0x01D8 == codePoint) || - (0x01DA == codePoint) || - (0x01DC == codePoint) || - (0x0251 == codePoint) || - (0x0261 == codePoint) || - (0x02C4 == codePoint) || - (0x02C7 == codePoint) || - (0x02C9 <= codePoint && codePoint <= 0x02CB) || - (0x02CD == codePoint) || - (0x02D0 == codePoint) || - (0x02D8 <= codePoint && codePoint <= 0x02DB) || - (0x02DD == codePoint) || - (0x02DF == codePoint) || - (0x0300 <= codePoint && codePoint <= 0x036F) || - (0x0391 <= codePoint && codePoint <= 0x03A1) || - (0x03A3 <= codePoint && codePoint <= 0x03A9) || - (0x03B1 <= codePoint && codePoint <= 0x03C1) || - (0x03C3 <= codePoint && codePoint <= 0x03C9) || - (0x0401 == codePoint) || - (0x0410 <= codePoint && codePoint <= 0x044F) || - (0x0451 == codePoint) || - (0x2010 == codePoint) || - (0x2013 <= codePoint && codePoint <= 0x2016) || - (0x2018 <= codePoint && codePoint <= 0x2019) || - (0x201C <= codePoint && codePoint <= 0x201D) || - (0x2020 <= codePoint && codePoint <= 0x2022) || - (0x2024 <= codePoint && codePoint <= 0x2027) || - (0x2030 == codePoint) || - (0x2032 <= codePoint && codePoint <= 0x2033) || - (0x2035 == codePoint) || - (0x203B == codePoint) || - (0x203E == codePoint) || - (0x2074 == codePoint) || - (0x207F == codePoint) || - (0x2081 <= codePoint && codePoint <= 0x2084) || - (0x20AC == codePoint) || - (0x2103 == codePoint) || - (0x2105 == codePoint) || - (0x2109 == codePoint) || - (0x2113 == codePoint) || - (0x2116 == codePoint) || - (0x2121 <= codePoint && codePoint <= 0x2122) || - (0x2126 == codePoint) || - (0x212B == codePoint) || - (0x2153 <= codePoint && codePoint <= 0x2154) || - (0x215B <= codePoint && codePoint <= 0x215E) || - (0x2160 <= codePoint && codePoint <= 0x216B) || - (0x2170 <= codePoint && codePoint <= 0x2179) || - (0x2189 == codePoint) || - (0x2190 <= codePoint && codePoint <= 0x2199) || - (0x21B8 <= codePoint && codePoint <= 0x21B9) || - (0x21D2 == codePoint) || - (0x21D4 == codePoint) || - (0x21E7 == codePoint) || - (0x2200 == codePoint) || - (0x2202 <= codePoint && codePoint <= 0x2203) || - (0x2207 <= codePoint && codePoint <= 0x2208) || - (0x220B == codePoint) || - (0x220F == codePoint) || - (0x2211 == codePoint) || - (0x2215 == codePoint) || - (0x221A == codePoint) || - (0x221D <= codePoint && codePoint <= 0x2220) || - (0x2223 == codePoint) || - (0x2225 == codePoint) || - (0x2227 <= codePoint && codePoint <= 0x222C) || - (0x222E == codePoint) || - (0x2234 <= codePoint && codePoint <= 0x2237) || - (0x223C <= codePoint && codePoint <= 0x223D) || - (0x2248 == codePoint) || - (0x224C == codePoint) || - (0x2252 == codePoint) || - (0x2260 <= codePoint && codePoint <= 0x2261) || - (0x2264 <= codePoint && codePoint <= 0x2267) || - (0x226A <= codePoint && codePoint <= 0x226B) || - (0x226E <= codePoint && codePoint <= 0x226F) || - (0x2282 <= codePoint && codePoint <= 0x2283) || - (0x2286 <= codePoint && codePoint <= 0x2287) || - (0x2295 == codePoint) || - (0x2299 == codePoint) || - (0x22A5 == codePoint) || - (0x22BF == codePoint) || - (0x2312 == codePoint) || - (0x2460 <= codePoint && codePoint <= 0x24E9) || - (0x24EB <= codePoint && codePoint <= 0x254B) || - (0x2550 <= codePoint && codePoint <= 0x2573) || - (0x2580 <= codePoint && codePoint <= 0x258F) || - (0x2592 <= codePoint && codePoint <= 0x2595) || - (0x25A0 <= codePoint && codePoint <= 0x25A1) || - (0x25A3 <= codePoint && codePoint <= 0x25A9) || - (0x25B2 <= codePoint && codePoint <= 0x25B3) || - (0x25B6 <= codePoint && codePoint <= 0x25B7) || - (0x25BC <= codePoint && codePoint <= 0x25BD) || - (0x25C0 <= codePoint && codePoint <= 0x25C1) || - (0x25C6 <= codePoint && codePoint <= 0x25C8) || - (0x25CB == codePoint) || - (0x25CE <= codePoint && codePoint <= 0x25D1) || - (0x25E2 <= codePoint && codePoint <= 0x25E5) || - (0x25EF == codePoint) || - (0x2605 <= codePoint && codePoint <= 0x2606) || - (0x2609 == codePoint) || - (0x260E <= codePoint && codePoint <= 0x260F) || - (0x2614 <= codePoint && codePoint <= 0x2615) || - (0x261C == codePoint) || - (0x261E == codePoint) || - (0x2640 == codePoint) || - (0x2642 == codePoint) || - (0x2660 <= codePoint && codePoint <= 0x2661) || - (0x2663 <= codePoint && codePoint <= 0x2665) || - (0x2667 <= codePoint && codePoint <= 0x266A) || - (0x266C <= codePoint && codePoint <= 0x266D) || - (0x266F == codePoint) || - (0x269E <= codePoint && codePoint <= 0x269F) || - (0x26BE <= codePoint && codePoint <= 0x26BF) || - (0x26C4 <= codePoint && codePoint <= 0x26CD) || - (0x26CF <= codePoint && codePoint <= 0x26E1) || - (0x26E3 == codePoint) || - (0x26E8 <= codePoint && codePoint <= 0x26FF) || - (0x273D == codePoint) || - (0x2757 == codePoint) || - (0x2776 <= codePoint && codePoint <= 0x277F) || - (0x2B55 <= codePoint && codePoint <= 0x2B59) || - (0x3248 <= codePoint && codePoint <= 0x324F) || - (0xE000 <= codePoint && codePoint <= 0xF8FF) || - (0xFE00 <= codePoint && codePoint <= 0xFE0F) || - (0xFFFD == codePoint) || - (0x1F100 <= codePoint && codePoint <= 0x1F10A) || - (0x1F110 <= codePoint && codePoint <= 0x1F12D) || - (0x1F130 <= codePoint && codePoint <= 0x1F169) || - (0x1F170 <= codePoint && codePoint <= 0x1F19A) || - (0xE0100 <= codePoint && codePoint <= 0xE01EF) || - (0xF0000 <= codePoint && codePoint <= 0xFFFFD) || - (0x100000 <= codePoint && codePoint <= 0x10FFFD)) { - return 'A'; - } - - return 'N'; -}; - -eaw.characterLength = function(character) { - var code = this.eastAsianWidth(character); - if (code == 'F' || code == 'W' || code == 'A') { - return 2; - } else { - return 1; - } -}; - -eaw.length = function(string) { - var len = 0; - for (var i = 0; i < string.length; i++) { - len = len + this.characterLength(string.charAt(i)); - } - return len; -}; - -},{}],36:[function(_dereq_,module,exports){ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012 Ariya Hidayat - - 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 HOLDERS AND CONTRIBUTORS "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 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. -*/ -/*jslint vars:false, bitwise:true*/ -/*jshint indent:4*/ -/*global exports:true, define:true*/ -(function (root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // and plain browser loading, - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.estraverse = {})); - } -}(this, function (exports) { - 'use strict'; - - var Syntax, - isArray, - VisitorOption, - VisitorKeys, - objectCreate, - objectKeys, - BREAK, - SKIP, - REMOVE; - - function ignoreJSHintError() { } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - - // based on LLVM libc++ upper_bound / lower_bound - // MIT License - - function upperBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - - function lowerBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - - objectCreate = Object.create || (function () { - function F() { } - - return function (o) { - F.prototype = o; - return new F(); - }; - })(); - - objectKeys = Object.keys || function (o) { - var keys = [], key; - for (key in o) { - keys.push(key); - } - return keys; - }; - - function extend(to, from) { - objectKeys(from).forEach(function (key) { - to[key] = from[key]; - }); - return to; - } - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ClassBody: 'ClassBody', - ClassDeclaration: 'ClassDeclaration', - ClassExpression: 'ClassExpression', - ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. - ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExportBatchSpecifier: 'ExportBatchSpecifier', - ExportDeclaration: 'ExportDeclaration', - ExportSpecifier: 'ExportSpecifier', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - ForOfStatement: 'ForOfStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. - Identifier: 'Identifier', - IfStatement: 'IfStatement', - ImportDeclaration: 'ImportDeclaration', - ImportDefaultSpecifier: 'ImportDefaultSpecifier', - ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', - ImportSpecifier: 'ImportSpecifier', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - MethodDefinition: 'MethodDefinition', - ModuleSpecifier: 'ModuleSpecifier', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SpreadElement: 'SpreadElement', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - TaggedTemplateExpression: 'TaggedTemplateExpression', - TemplateElement: 'TemplateElement', - TemplateLiteral: 'TemplateLiteral', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - - VisitorKeys = { - AssignmentExpression: ['left', 'right'], - ArrayExpression: ['elements'], - ArrayPattern: ['elements'], - ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'], - BlockStatement: ['body'], - BinaryExpression: ['left', 'right'], - BreakStatement: ['label'], - CallExpression: ['callee', 'arguments'], - CatchClause: ['param', 'body'], - ClassBody: ['body'], - ClassDeclaration: ['id', 'body', 'superClass'], - ClassExpression: ['id', 'body', 'superClass'], - ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. - ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. - ConditionalExpression: ['test', 'consequent', 'alternate'], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: ['body', 'test'], - EmptyStatement: [], - ExportBatchSpecifier: [], - ExportDeclaration: ['declaration', 'specifiers', 'source'], - ExportSpecifier: ['id', 'name'], - ExpressionStatement: ['expression'], - ForStatement: ['init', 'test', 'update', 'body'], - ForInStatement: ['left', 'right', 'body'], - ForOfStatement: ['left', 'right', 'body'], - FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'], - FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], - GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. - Identifier: [], - IfStatement: ['test', 'consequent', 'alternate'], - ImportDeclaration: ['specifiers', 'source'], - ImportDefaultSpecifier: ['id'], - ImportNamespaceSpecifier: ['id'], - ImportSpecifier: ['id', 'name'], - Literal: [], - LabeledStatement: ['label', 'body'], - LogicalExpression: ['left', 'right'], - MemberExpression: ['object', 'property'], - MethodDefinition: ['key', 'value'], - ModuleSpecifier: [], - NewExpression: ['callee', 'arguments'], - ObjectExpression: ['properties'], - ObjectPattern: ['properties'], - Program: ['body'], - Property: ['key', 'value'], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SpreadElement: ['argument'], - SwitchStatement: ['discriminant', 'cases'], - SwitchCase: ['test', 'consequent'], - TaggedTemplateExpression: ['tag', 'quasi'], - TemplateElement: [], - TemplateLiteral: ['quasis', 'expressions'], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: ['id', 'init'], - WhileStatement: ['test', 'body'], - WithStatement: ['object', 'body'], - YieldExpression: ['argument'] - }; - - // unique id - BREAK = {}; - SKIP = {}; - REMOVE = {}; - - VisitorOption = { - Break: BREAK, - Skip: SKIP, - Remove: REMOVE - }; - - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - - Reference.prototype.remove = function remove() { - if (isArray(this.parent)) { - this.parent.splice(this.key, 1); - return true; - } else { - this.replace(null); - return false; - } - }; - - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - - function Controller() { } - - // API: - // return property path array from root to current node - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - - // root node - if (!this.__current.path) { - return null; - } - - // first node is sentinel, second node is root element - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - - // API: - // return array of parent elements - Controller.prototype.parents = function parents() { - var i, iz, result; - - // first node is sentinel - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - - return result; - }; - - // API: - // return current node - Controller.prototype.current = function current() { - return this.__current.node; - }; - - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - - result = undefined; - - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - - return result; - }; - - // API: - // notify control skip / break - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - - // API: - // skip child nodes of current node - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - - // API: - // break traversals - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - - // API: - // remove node - Controller.prototype.remove = function () { - this.notify(REMOVE); - }; - - Controller.prototype.__initialize = function(root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - this.__fallback = visitor.fallback === 'iteration'; - this.__keys = VisitorKeys; - if (visitor.keys) { - this.__keys = extend(objectCreate(this.__keys), visitor.keys); - } - }; - - function isNode(node) { - if (node == null) { - return false; - } - return typeof node === 'object' && typeof node.type === 'string'; - } - - function isProperty(nodeType, key) { - return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; - } - - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, - leavelist, - element, - node, - nodeType, - ret, - key, - current, - current2, - candidates, - candidate, - sentinel; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - ret = this.__execute(visitor.leave, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - - if (element.node) { - - ret = this.__execute(visitor.enter, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || ret === SKIP) { - continue; - } - - node = element.node; - nodeType = element.wrap || node.type; - candidates = this.__keys[nodeType]; - if (!candidates) { - if (this.__fallback) { - candidates = objectKeys(node); - } else { - throw new Error('Unknown node type ' + nodeType + '.'); - } - } - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (isArray(candidate)) { - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (isProperty(nodeType, candidates[current])) { - element = new Element(candidate[current2], [key, current2], 'Property', null); - } else if (isNode(candidate[current2])) { - element = new Element(candidate[current2], [key, current2], null, null); - } else { - continue; - } - worklist.push(element); - } - } else if (isNode(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - } - } - } - } - }; - - Controller.prototype.replace = function replace(root, visitor) { - function removeElem(element) { - var i, - key, - nextElem, - parent; - - if (element.ref.remove()) { - // When the reference is an element of an array. - key = element.ref.key; - parent = element.ref.parent; - - // If removed from array, then decrease following items' keys. - i = worklist.length; - while (i--) { - nextElem = worklist[i]; - if (nextElem.ref && nextElem.ref.parent === parent) { - if (nextElem.ref.key < key) { - break; - } - --nextElem.ref.key; - } - } - } - } - - var worklist, - leavelist, - node, - nodeType, - target, - element, - current, - current2, - candidates, - candidate, - sentinel, - outer, - key; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - outer = { - root: root - }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - target = this.__execute(visitor.leave, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { - // replace - element.ref.replace(target); - } - - if (this.__state === REMOVE || target === REMOVE) { - removeElem(element); - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - - target = this.__execute(visitor.enter, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { - // replace - element.ref.replace(target); - element.node = target; - } - - if (this.__state === REMOVE || target === REMOVE) { - removeElem(element); - element.node = null; - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - - // node may be null - node = element.node; - if (!node) { - continue; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || target === SKIP) { - continue; - } - - nodeType = element.wrap || node.type; - candidates = this.__keys[nodeType]; - if (!candidates) { - if (this.__fallback) { - candidates = objectKeys(node); - } else { - throw new Error('Unknown node type ' + nodeType + '.'); - } - } - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (isArray(candidate)) { - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (isProperty(nodeType, candidates[current])) { - element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); - } else if (isNode(candidate[current2])) { - element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); - } else { - continue; - } - worklist.push(element); - } - } else if (isNode(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - } - } - } - - return outer.root; - }; - - function traverse(root, visitor) { - var controller = new Controller(); - return controller.traverse(root, visitor); - } - - function replace(root, visitor) { - var controller = new Controller(); - return controller.replace(root, visitor); - } - - function extendCommentRange(comment, tokens) { - var target; - - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - - comment.extendedRange = [comment.range[0], comment.range[1]]; - - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - - target -= 1; - if (target >= 0) { - comment.extendedRange[0] = tokens[target].range[1]; - } - - return comment; - } - - function attachComments(tree, providedComments, tokens) { - // At first, we should calculate extended comment ranges. - var comments = [], comment, len, i, cursor; - - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - - // tokens array is empty, we attach comments to tree as 'leadingComments' - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [0, tree.range[0]]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - - // This is based on John Freeman's implementation. - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - return tree; - } - - exports.version = '1.7.1'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; -})); -/* vim: set sw=4 ts=4 et tw=80 : */ - -},{}],37:[function(_dereq_,module,exports){ -module.exports = _dereq_('./javascript/diff_match_patch_uncompressed.js').diff_match_patch; - -},{"./javascript/diff_match_patch_uncompressed.js":38}],38:[function(_dereq_,module,exports){ -/** - * Diff Match and Patch - * - * Copyright 2006 Google Inc. - * http://code.google.com/p/google-diff-match-patch/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Computes the difference between two texts to create a patch. - * Applies the patch onto another text, allowing for errors. - * @author fraser@google.com (Neil Fraser) - */ - -/** - * Class containing the diff, match and patch methods. - * @constructor - */ -function diff_match_patch() { - - // Defaults. - // Redefine these in your program to override the defaults. - - // Number of seconds to map a diff before giving up (0 for infinity). - this.Diff_Timeout = 1.0; - // Cost of an empty edit operation in terms of edit characters. - this.Diff_EditCost = 4; - // At what point is no match declared (0.0 = perfection, 1.0 = very loose). - this.Match_Threshold = 0.5; - // How far to search for a match (0 = exact location, 1000+ = broad match). - // A match this many characters away from the expected location will add - // 1.0 to the score (0.0 is a perfect match). - this.Match_Distance = 1000; - // When deleting a large block of text (over ~64 characters), how close do - // the contents have to be to match the expected contents. (0.0 = perfection, - // 1.0 = very loose). Note that Match_Threshold controls how closely the - // end points of a delete need to match. - this.Patch_DeleteThreshold = 0.5; - // Chunk size for context length. - this.Patch_Margin = 4; - - // The number of bits in an int. - this.Match_MaxBits = 32; -} - - -// DIFF FUNCTIONS - - -/** - * The data structure representing a diff is an array of tuples: - * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']] - * which means: delete 'Hello', add 'Goodbye' and keep ' world.' - */ -var DIFF_DELETE = -1; -var DIFF_INSERT = 1; -var DIFF_EQUAL = 0; - -/** @typedef {{0: number, 1: string}} */ -diff_match_patch.Diff; - - -/** - * Find the differences between two texts. Simplifies the problem by stripping - * any common prefix or suffix off the texts before diffing. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {boolean=} opt_checklines Optional speedup flag. If present and false, - * then don't run a line-level diff first to identify the changed areas. - * Defaults to true, which does a faster, slightly less optimal diff. - * @param {number} opt_deadline Optional time when the diff should be complete - * by. Used internally for recursive calls. Users should set DiffTimeout - * instead. - * @return {!Array.} Array of diff tuples. - */ -diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines, - opt_deadline) { - // Set a deadline by which time the diff must be complete. - if (typeof opt_deadline == 'undefined') { - if (this.Diff_Timeout <= 0) { - opt_deadline = Number.MAX_VALUE; - } else { - opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000; - } - } - var deadline = opt_deadline; - - // Check for null inputs. - if (text1 == null || text2 == null) { - throw new Error('Null input. (diff_main)'); - } - - // Check for equality (speedup). - if (text1 == text2) { - if (text1) { - return [[DIFF_EQUAL, text1]]; - } - return []; - } - - if (typeof opt_checklines == 'undefined') { - opt_checklines = true; - } - var checklines = opt_checklines; - - // Trim off common prefix (speedup). - var commonlength = this.diff_commonPrefix(text1, text2); - var commonprefix = text1.substring(0, commonlength); - text1 = text1.substring(commonlength); - text2 = text2.substring(commonlength); - - // Trim off common suffix (speedup). - commonlength = this.diff_commonSuffix(text1, text2); - var commonsuffix = text1.substring(text1.length - commonlength); - text1 = text1.substring(0, text1.length - commonlength); - text2 = text2.substring(0, text2.length - commonlength); - - // Compute the diff on the middle block. - var diffs = this.diff_compute_(text1, text2, checklines, deadline); - - // Restore the prefix and suffix. - if (commonprefix) { - diffs.unshift([DIFF_EQUAL, commonprefix]); - } - if (commonsuffix) { - diffs.push([DIFF_EQUAL, commonsuffix]); - } - this.diff_cleanupMerge(diffs); - return diffs; -}; - - -/** - * Find the differences between two texts. Assumes that the texts do not - * have any common prefix or suffix. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {boolean} checklines Speedup flag. If false, then don't run a - * line-level diff first to identify the changed areas. - * If true, then run a faster, slightly less optimal diff. - * @param {number} deadline Time when the diff should be complete by. - * @return {!Array.} Array of diff tuples. - * @private - */ -diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines, - deadline) { - var diffs; - - if (!text1) { - // Just add some text (speedup). - return [[DIFF_INSERT, text2]]; - } - - if (!text2) { - // Just delete some text (speedup). - return [[DIFF_DELETE, text1]]; - } - - var longtext = text1.length > text2.length ? text1 : text2; - var shorttext = text1.length > text2.length ? text2 : text1; - var i = longtext.indexOf(shorttext); - if (i != -1) { - // Shorter text is inside the longer text (speedup). - diffs = [[DIFF_INSERT, longtext.substring(0, i)], - [DIFF_EQUAL, shorttext], - [DIFF_INSERT, longtext.substring(i + shorttext.length)]]; - // Swap insertions for deletions if diff is reversed. - if (text1.length > text2.length) { - diffs[0][0] = diffs[2][0] = DIFF_DELETE; - } - return diffs; - } - - if (shorttext.length == 1) { - // Single character string. - // After the previous speedup, the character can't be an equality. - return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; - } - - // Check to see if the problem can be split in two. - var hm = this.diff_halfMatch_(text1, text2); - if (hm) { - // A half-match was found, sort out the return data. - var text1_a = hm[0]; - var text1_b = hm[1]; - var text2_a = hm[2]; - var text2_b = hm[3]; - var mid_common = hm[4]; - // Send both pairs off for separate processing. - var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline); - var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline); - // Merge the results. - return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b); - } - - if (checklines && text1.length > 100 && text2.length > 100) { - return this.diff_lineMode_(text1, text2, deadline); - } - - return this.diff_bisect_(text1, text2, deadline); -}; - - -/** - * Do a quick line-level diff on both strings, then rediff the parts for - * greater accuracy. - * This speedup can produce non-minimal diffs. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {number} deadline Time when the diff should be complete by. - * @return {!Array.} Array of diff tuples. - * @private - */ -diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) { - // Scan the text on a line-by-line basis first. - var a = this.diff_linesToChars_(text1, text2); - text1 = a.chars1; - text2 = a.chars2; - var linearray = a.lineArray; - - var diffs = this.diff_main(text1, text2, false, deadline); - - // Convert the diff back to original text. - this.diff_charsToLines_(diffs, linearray); - // Eliminate freak matches (e.g. blank lines) - this.diff_cleanupSemantic(diffs); - - // Rediff any replacement blocks, this time character-by-character. - // Add a dummy entry at the end. - diffs.push([DIFF_EQUAL, '']); - var pointer = 0; - var count_delete = 0; - var count_insert = 0; - var text_delete = ''; - var text_insert = ''; - while (pointer < diffs.length) { - switch (diffs[pointer][0]) { - case DIFF_INSERT: - count_insert++; - text_insert += diffs[pointer][1]; - break; - case DIFF_DELETE: - count_delete++; - text_delete += diffs[pointer][1]; - break; - case DIFF_EQUAL: - // Upon reaching an equality, check for prior redundancies. - if (count_delete >= 1 && count_insert >= 1) { - // Delete the offending records and add the merged ones. - diffs.splice(pointer - count_delete - count_insert, - count_delete + count_insert); - pointer = pointer - count_delete - count_insert; - var a = this.diff_main(text_delete, text_insert, false, deadline); - for (var j = a.length - 1; j >= 0; j--) { - diffs.splice(pointer, 0, a[j]); - } - pointer = pointer + a.length; - } - count_insert = 0; - count_delete = 0; - text_delete = ''; - text_insert = ''; - break; - } - pointer++; - } - diffs.pop(); // Remove the dummy entry at the end. - - return diffs; -}; - - -/** - * Find the 'middle snake' of a diff, split the problem in two - * and return the recursively constructed diff. - * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {number} deadline Time at which to bail if not yet complete. - * @return {!Array.} Array of diff tuples. - * @private - */ -diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) { - // Cache the text lengths to prevent multiple calls. - var text1_length = text1.length; - var text2_length = text2.length; - var max_d = Math.ceil((text1_length + text2_length) / 2); - var v_offset = max_d; - var v_length = 2 * max_d; - var v1 = new Array(v_length); - var v2 = new Array(v_length); - // Setting all elements to -1 is faster in Chrome & Firefox than mixing - // integers and undefined. - for (var x = 0; x < v_length; x++) { - v1[x] = -1; - v2[x] = -1; - } - v1[v_offset + 1] = 0; - v2[v_offset + 1] = 0; - var delta = text1_length - text2_length; - // If the total number of characters is odd, then the front path will collide - // with the reverse path. - var front = (delta % 2 != 0); - // Offsets for start and end of k loop. - // Prevents mapping of space beyond the grid. - var k1start = 0; - var k1end = 0; - var k2start = 0; - var k2end = 0; - for (var d = 0; d < max_d; d++) { - // Bail out if deadline is reached. - if ((new Date()).getTime() > deadline) { - break; - } - - // Walk the front path one step. - for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { - var k1_offset = v_offset + k1; - var x1; - if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) { - x1 = v1[k1_offset + 1]; - } else { - x1 = v1[k1_offset - 1] + 1; - } - var y1 = x1 - k1; - while (x1 < text1_length && y1 < text2_length && - text1.charAt(x1) == text2.charAt(y1)) { - x1++; - y1++; - } - v1[k1_offset] = x1; - if (x1 > text1_length) { - // Ran off the right of the graph. - k1end += 2; - } else if (y1 > text2_length) { - // Ran off the bottom of the graph. - k1start += 2; - } else if (front) { - var k2_offset = v_offset + delta - k1; - if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) { - // Mirror x2 onto top-left coordinate system. - var x2 = text1_length - v2[k2_offset]; - if (x1 >= x2) { - // Overlap detected. - return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); - } - } - } - } - - // Walk the reverse path one step. - for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { - var k2_offset = v_offset + k2; - var x2; - if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) { - x2 = v2[k2_offset + 1]; - } else { - x2 = v2[k2_offset - 1] + 1; - } - var y2 = x2 - k2; - while (x2 < text1_length && y2 < text2_length && - text1.charAt(text1_length - x2 - 1) == - text2.charAt(text2_length - y2 - 1)) { - x2++; - y2++; - } - v2[k2_offset] = x2; - if (x2 > text1_length) { - // Ran off the left of the graph. - k2end += 2; - } else if (y2 > text2_length) { - // Ran off the top of the graph. - k2start += 2; - } else if (!front) { - var k1_offset = v_offset + delta - k2; - if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) { - var x1 = v1[k1_offset]; - var y1 = v_offset + x1 - k1_offset; - // Mirror x2 onto top-left coordinate system. - x2 = text1_length - x2; - if (x1 >= x2) { - // Overlap detected. - return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); - } - } - } - } - } - // Diff took too long and hit the deadline or - // number of diffs equals number of characters, no commonality at all. - return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; -}; - - -/** - * Given the location of the 'middle snake', split the diff in two parts - * and recurse. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {number} x Index of split point in text1. - * @param {number} y Index of split point in text2. - * @param {number} deadline Time at which to bail if not yet complete. - * @return {!Array.} Array of diff tuples. - * @private - */ -diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y, - deadline) { - var text1a = text1.substring(0, x); - var text2a = text2.substring(0, y); - var text1b = text1.substring(x); - var text2b = text2.substring(y); - - // Compute both diffs serially. - var diffs = this.diff_main(text1a, text2a, false, deadline); - var diffsb = this.diff_main(text1b, text2b, false, deadline); - - return diffs.concat(diffsb); -}; - - -/** - * Split two texts into an array of strings. Reduce the texts to a string of - * hashes where each Unicode character represents one line. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {{chars1: string, chars2: string, lineArray: !Array.}} - * An object containing the encoded text1, the encoded text2 and - * the array of unique strings. - * The zeroth element of the array of unique strings is intentionally blank. - * @private - */ -diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) { - var lineArray = []; // e.g. lineArray[4] == 'Hello\n' - var lineHash = {}; // e.g. lineHash['Hello\n'] == 4 - - // '\x00' is a valid character, but various debuggers don't like it. - // So we'll insert a junk entry to avoid generating a null character. - lineArray[0] = ''; - - /** - * Split a text into an array of strings. Reduce the texts to a string of - * hashes where each Unicode character represents one line. - * Modifies linearray and linehash through being a closure. - * @param {string} text String to encode. - * @return {string} Encoded string. - * @private - */ - function diff_linesToCharsMunge_(text) { - var chars = ''; - // Walk the text, pulling out a substring for each line. - // text.split('\n') would would temporarily double our memory footprint. - // Modifying text would create many large strings to garbage collect. - var lineStart = 0; - var lineEnd = -1; - // Keeping our own length variable is faster than looking it up. - var lineArrayLength = lineArray.length; - while (lineEnd < text.length - 1) { - lineEnd = text.indexOf('\n', lineStart); - if (lineEnd == -1) { - lineEnd = text.length - 1; - } - var line = text.substring(lineStart, lineEnd + 1); - lineStart = lineEnd + 1; - - if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : - (lineHash[line] !== undefined)) { - chars += String.fromCharCode(lineHash[line]); - } else { - chars += String.fromCharCode(lineArrayLength); - lineHash[line] = lineArrayLength; - lineArray[lineArrayLength++] = line; - } - } - return chars; - } - - var chars1 = diff_linesToCharsMunge_(text1); - var chars2 = diff_linesToCharsMunge_(text2); - return {chars1: chars1, chars2: chars2, lineArray: lineArray}; -}; - - -/** - * Rehydrate the text in a diff from a string of line hashes to real lines of - * text. - * @param {!Array.} diffs Array of diff tuples. - * @param {!Array.} lineArray Array of unique strings. - * @private - */ -diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) { - for (var x = 0; x < diffs.length; x++) { - var chars = diffs[x][1]; - var text = []; - for (var y = 0; y < chars.length; y++) { - text[y] = lineArray[chars.charCodeAt(y)]; - } - diffs[x][1] = text.join(''); - } -}; - - -/** - * Determine the common prefix of two strings. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {number} The number of characters common to the start of each - * string. - */ -diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) { - // Quick check for common null cases. - if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) { - return 0; - } - // Binary search. - // Performance analysis: http://neil.fraser.name/news/2007/10/09/ - var pointermin = 0; - var pointermax = Math.min(text1.length, text2.length); - var pointermid = pointermax; - var pointerstart = 0; - while (pointermin < pointermid) { - if (text1.substring(pointerstart, pointermid) == - text2.substring(pointerstart, pointermid)) { - pointermin = pointermid; - pointerstart = pointermin; - } else { - pointermax = pointermid; - } - pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); - } - return pointermid; -}; - - -/** - * Determine the common suffix of two strings. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {number} The number of characters common to the end of each string. - */ -diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) { - // Quick check for common null cases. - if (!text1 || !text2 || - text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { - return 0; - } - // Binary search. - // Performance analysis: http://neil.fraser.name/news/2007/10/09/ - var pointermin = 0; - var pointermax = Math.min(text1.length, text2.length); - var pointermid = pointermax; - var pointerend = 0; - while (pointermin < pointermid) { - if (text1.substring(text1.length - pointermid, text1.length - pointerend) == - text2.substring(text2.length - pointermid, text2.length - pointerend)) { - pointermin = pointermid; - pointerend = pointermin; - } else { - pointermax = pointermid; - } - pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); - } - return pointermid; -}; - - -/** - * Determine if the suffix of one string is the prefix of another. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {number} The number of characters common to the end of the first - * string and the start of the second string. - * @private - */ -diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) { - // Cache the text lengths to prevent multiple calls. - var text1_length = text1.length; - var text2_length = text2.length; - // Eliminate the null case. - if (text1_length == 0 || text2_length == 0) { - return 0; - } - // Truncate the longer string. - if (text1_length > text2_length) { - text1 = text1.substring(text1_length - text2_length); - } else if (text1_length < text2_length) { - text2 = text2.substring(0, text1_length); - } - var text_length = Math.min(text1_length, text2_length); - // Quick check for the worst case. - if (text1 == text2) { - return text_length; - } - - // Start by looking for a single character match - // and increase length until no match is found. - // Performance analysis: http://neil.fraser.name/news/2010/11/04/ - var best = 0; - var length = 1; - while (true) { - var pattern = text1.substring(text_length - length); - var found = text2.indexOf(pattern); - if (found == -1) { - return best; - } - length += found; - if (found == 0 || text1.substring(text_length - length) == - text2.substring(0, length)) { - best = length; - length++; - } - } -}; - - -/** - * Do the two texts share a substring which is at least half the length of the - * longer text? - * This speedup can produce non-minimal diffs. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {Array.} Five element Array, containing the prefix of - * text1, the suffix of text1, the prefix of text2, the suffix of - * text2 and the common middle. Or null if there was no match. - * @private - */ -diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) { - if (this.Diff_Timeout <= 0) { - // Don't risk returning a non-optimal diff if we have unlimited time. - return null; - } - var longtext = text1.length > text2.length ? text1 : text2; - var shorttext = text1.length > text2.length ? text2 : text1; - if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { - return null; // Pointless. - } - var dmp = this; // 'this' becomes 'window' in a closure. - - /** - * Does a substring of shorttext exist within longtext such that the substring - * is at least half the length of longtext? - * Closure, but does not reference any external variables. - * @param {string} longtext Longer string. - * @param {string} shorttext Shorter string. - * @param {number} i Start index of quarter length substring within longtext. - * @return {Array.} Five element Array, containing the prefix of - * longtext, the suffix of longtext, the prefix of shorttext, the suffix - * of shorttext and the common middle. Or null if there was no match. - * @private - */ - function diff_halfMatchI_(longtext, shorttext, i) { - // Start with a 1/4 length substring at position i as a seed. - var seed = longtext.substring(i, i + Math.floor(longtext.length / 4)); - var j = -1; - var best_common = ''; - var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b; - while ((j = shorttext.indexOf(seed, j + 1)) != -1) { - var prefixLength = dmp.diff_commonPrefix(longtext.substring(i), - shorttext.substring(j)); - var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i), - shorttext.substring(0, j)); - if (best_common.length < suffixLength + prefixLength) { - best_common = shorttext.substring(j - suffixLength, j) + - shorttext.substring(j, j + prefixLength); - best_longtext_a = longtext.substring(0, i - suffixLength); - best_longtext_b = longtext.substring(i + prefixLength); - best_shorttext_a = shorttext.substring(0, j - suffixLength); - best_shorttext_b = shorttext.substring(j + prefixLength); - } - } - if (best_common.length * 2 >= longtext.length) { - return [best_longtext_a, best_longtext_b, - best_shorttext_a, best_shorttext_b, best_common]; - } else { - return null; - } - } - - // First check if the second quarter is the seed for a half-match. - var hm1 = diff_halfMatchI_(longtext, shorttext, - Math.ceil(longtext.length / 4)); - // Check again based on the third quarter. - var hm2 = diff_halfMatchI_(longtext, shorttext, - Math.ceil(longtext.length / 2)); - var hm; - if (!hm1 && !hm2) { - return null; - } else if (!hm2) { - hm = hm1; - } else if (!hm1) { - hm = hm2; - } else { - // Both matched. Select the longest. - hm = hm1[4].length > hm2[4].length ? hm1 : hm2; - } - - // A half-match was found, sort out the return data. - var text1_a, text1_b, text2_a, text2_b; - if (text1.length > text2.length) { - text1_a = hm[0]; - text1_b = hm[1]; - text2_a = hm[2]; - text2_b = hm[3]; - } else { - text2_a = hm[0]; - text2_b = hm[1]; - text1_a = hm[2]; - text1_b = hm[3]; - } - var mid_common = hm[4]; - return [text1_a, text1_b, text2_a, text2_b, mid_common]; -}; - - -/** - * Reduce the number of edits by eliminating semantically trivial equalities. - * @param {!Array.} diffs Array of diff tuples. - */ -diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) { - var changes = false; - var equalities = []; // Stack of indices where equalities are found. - var equalitiesLength = 0; // Keeping our own length var is faster in JS. - /** @type {?string} */ - var lastequality = null; - // Always equal to diffs[equalities[equalitiesLength - 1]][1] - var pointer = 0; // Index of current position. - // Number of characters that changed prior to the equality. - var length_insertions1 = 0; - var length_deletions1 = 0; - // Number of characters that changed after the equality. - var length_insertions2 = 0; - var length_deletions2 = 0; - while (pointer < diffs.length) { - if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. - equalities[equalitiesLength++] = pointer; - length_insertions1 = length_insertions2; - length_deletions1 = length_deletions2; - length_insertions2 = 0; - length_deletions2 = 0; - lastequality = diffs[pointer][1]; - } else { // An insertion or deletion. - if (diffs[pointer][0] == DIFF_INSERT) { - length_insertions2 += diffs[pointer][1].length; - } else { - length_deletions2 += diffs[pointer][1].length; - } - // Eliminate an equality that is smaller or equal to the edits on both - // sides of it. - if (lastequality && (lastequality.length <= - Math.max(length_insertions1, length_deletions1)) && - (lastequality.length <= Math.max(length_insertions2, - length_deletions2))) { - // Duplicate record. - diffs.splice(equalities[equalitiesLength - 1], 0, - [DIFF_DELETE, lastequality]); - // Change second copy to insert. - diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; - // Throw away the equality we just deleted. - equalitiesLength--; - // Throw away the previous equality (it needs to be reevaluated). - equalitiesLength--; - pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; - length_insertions1 = 0; // Reset the counters. - length_deletions1 = 0; - length_insertions2 = 0; - length_deletions2 = 0; - lastequality = null; - changes = true; - } - } - pointer++; - } - - // Normalize the diff. - if (changes) { - this.diff_cleanupMerge(diffs); - } - this.diff_cleanupSemanticLossless(diffs); - - // Find any overlaps between deletions and insertions. - // e.g: abcxxxxxxdef - // -> abcxxxdef - // e.g: xxxabcdefxxx - // -> defxxxabc - // Only extract an overlap if it is as big as the edit ahead or behind it. - pointer = 1; - while (pointer < diffs.length) { - if (diffs[pointer - 1][0] == DIFF_DELETE && - diffs[pointer][0] == DIFF_INSERT) { - var deletion = diffs[pointer - 1][1]; - var insertion = diffs[pointer][1]; - var overlap_length1 = this.diff_commonOverlap_(deletion, insertion); - var overlap_length2 = this.diff_commonOverlap_(insertion, deletion); - if (overlap_length1 >= overlap_length2) { - if (overlap_length1 >= deletion.length / 2 || - overlap_length1 >= insertion.length / 2) { - // Overlap found. Insert an equality and trim the surrounding edits. - diffs.splice(pointer, 0, - [DIFF_EQUAL, insertion.substring(0, overlap_length1)]); - diffs[pointer - 1][1] = - deletion.substring(0, deletion.length - overlap_length1); - diffs[pointer + 1][1] = insertion.substring(overlap_length1); - pointer++; - } - } else { - if (overlap_length2 >= deletion.length / 2 || - overlap_length2 >= insertion.length / 2) { - // Reverse overlap found. - // Insert an equality and swap and trim the surrounding edits. - diffs.splice(pointer, 0, - [DIFF_EQUAL, deletion.substring(0, overlap_length2)]); - diffs[pointer - 1][0] = DIFF_INSERT; - diffs[pointer - 1][1] = - insertion.substring(0, insertion.length - overlap_length2); - diffs[pointer + 1][0] = DIFF_DELETE; - diffs[pointer + 1][1] = - deletion.substring(overlap_length2); - pointer++; - } - } - pointer++; - } - pointer++; - } -}; - - -/** - * Look for single edits surrounded on both sides by equalities - * which can be shifted sideways to align the edit to a word boundary. - * e.g: The cat came. -> The cat came. - * @param {!Array.} diffs Array of diff tuples. - */ -diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) { - /** - * Given two strings, compute a score representing whether the internal - * boundary falls on logical boundaries. - * Scores range from 6 (best) to 0 (worst). - * Closure, but does not reference any external variables. - * @param {string} one First string. - * @param {string} two Second string. - * @return {number} The score. - * @private - */ - function diff_cleanupSemanticScore_(one, two) { - if (!one || !two) { - // Edges are the best. - return 6; - } - - // Each port of this function behaves slightly differently due to - // subtle differences in each language's definition of things like - // 'whitespace'. Since this function's purpose is largely cosmetic, - // the choice has been made to use each language's native features - // rather than force total conformity. - var char1 = one.charAt(one.length - 1); - var char2 = two.charAt(0); - var nonAlphaNumeric1 = char1.match(diff_match_patch.nonAlphaNumericRegex_); - var nonAlphaNumeric2 = char2.match(diff_match_patch.nonAlphaNumericRegex_); - var whitespace1 = nonAlphaNumeric1 && - char1.match(diff_match_patch.whitespaceRegex_); - var whitespace2 = nonAlphaNumeric2 && - char2.match(diff_match_patch.whitespaceRegex_); - var lineBreak1 = whitespace1 && - char1.match(diff_match_patch.linebreakRegex_); - var lineBreak2 = whitespace2 && - char2.match(diff_match_patch.linebreakRegex_); - var blankLine1 = lineBreak1 && - one.match(diff_match_patch.blanklineEndRegex_); - var blankLine2 = lineBreak2 && - two.match(diff_match_patch.blanklineStartRegex_); - - if (blankLine1 || blankLine2) { - // Five points for blank lines. - return 5; - } else if (lineBreak1 || lineBreak2) { - // Four points for line breaks. - return 4; - } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) { - // Three points for end of sentences. - return 3; - } else if (whitespace1 || whitespace2) { - // Two points for whitespace. - return 2; - } else if (nonAlphaNumeric1 || nonAlphaNumeric2) { - // One point for non-alphanumeric. - return 1; - } - return 0; - } - - var pointer = 1; - // Intentionally ignore the first and last element (don't need checking). - while (pointer < diffs.length - 1) { - if (diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL) { - // This is a single edit surrounded by equalities. - var equality1 = diffs[pointer - 1][1]; - var edit = diffs[pointer][1]; - var equality2 = diffs[pointer + 1][1]; - - // First, shift the edit as far left as possible. - var commonOffset = this.diff_commonSuffix(equality1, edit); - if (commonOffset) { - var commonString = edit.substring(edit.length - commonOffset); - equality1 = equality1.substring(0, equality1.length - commonOffset); - edit = commonString + edit.substring(0, edit.length - commonOffset); - equality2 = commonString + equality2; - } - - // Second, step character by character right, looking for the best fit. - var bestEquality1 = equality1; - var bestEdit = edit; - var bestEquality2 = equality2; - var bestScore = diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); - while (edit.charAt(0) === equality2.charAt(0)) { - equality1 += edit.charAt(0); - edit = edit.substring(1) + equality2.charAt(0); - equality2 = equality2.substring(1); - var score = diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); - // The >= encourages trailing rather than leading whitespace on edits. - if (score >= bestScore) { - bestScore = score; - bestEquality1 = equality1; - bestEdit = edit; - bestEquality2 = equality2; - } - } - - if (diffs[pointer - 1][1] != bestEquality1) { - // We have an improvement, save it back to the diff. - if (bestEquality1) { - diffs[pointer - 1][1] = bestEquality1; - } else { - diffs.splice(pointer - 1, 1); - pointer--; - } - diffs[pointer][1] = bestEdit; - if (bestEquality2) { - diffs[pointer + 1][1] = bestEquality2; - } else { - diffs.splice(pointer + 1, 1); - pointer--; - } - } - } - pointer++; - } -}; - -// Define some regex patterns for matching boundaries. -diff_match_patch.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/; -diff_match_patch.whitespaceRegex_ = /\s/; -diff_match_patch.linebreakRegex_ = /[\r\n]/; -diff_match_patch.blanklineEndRegex_ = /\n\r?\n$/; -diff_match_patch.blanklineStartRegex_ = /^\r?\n\r?\n/; - -/** - * Reduce the number of edits by eliminating operationally trivial equalities. - * @param {!Array.} diffs Array of diff tuples. - */ -diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) { - var changes = false; - var equalities = []; // Stack of indices where equalities are found. - var equalitiesLength = 0; // Keeping our own length var is faster in JS. - /** @type {?string} */ - var lastequality = null; - // Always equal to diffs[equalities[equalitiesLength - 1]][1] - var pointer = 0; // Index of current position. - // Is there an insertion operation before the last equality. - var pre_ins = false; - // Is there a deletion operation before the last equality. - var pre_del = false; - // Is there an insertion operation after the last equality. - var post_ins = false; - // Is there a deletion operation after the last equality. - var post_del = false; - while (pointer < diffs.length) { - if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. - if (diffs[pointer][1].length < this.Diff_EditCost && - (post_ins || post_del)) { - // Candidate found. - equalities[equalitiesLength++] = pointer; - pre_ins = post_ins; - pre_del = post_del; - lastequality = diffs[pointer][1]; - } else { - // Not a candidate, and can never become one. - equalitiesLength = 0; - lastequality = null; - } - post_ins = post_del = false; - } else { // An insertion or deletion. - if (diffs[pointer][0] == DIFF_DELETE) { - post_del = true; - } else { - post_ins = true; - } - /* - * Five types to be split: - * ABXYCD - * AXCD - * ABXC - * AXCD - * ABXC - */ - if (lastequality && ((pre_ins && pre_del && post_ins && post_del) || - ((lastequality.length < this.Diff_EditCost / 2) && - (pre_ins + pre_del + post_ins + post_del) == 3))) { - // Duplicate record. - diffs.splice(equalities[equalitiesLength - 1], 0, - [DIFF_DELETE, lastequality]); - // Change second copy to insert. - diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; - equalitiesLength--; // Throw away the equality we just deleted; - lastequality = null; - if (pre_ins && pre_del) { - // No changes made which could affect previous entry, keep going. - post_ins = post_del = true; - equalitiesLength = 0; - } else { - equalitiesLength--; // Throw away the previous equality. - pointer = equalitiesLength > 0 ? - equalities[equalitiesLength - 1] : -1; - post_ins = post_del = false; - } - changes = true; - } - } - pointer++; - } - - if (changes) { - this.diff_cleanupMerge(diffs); - } -}; - - -/** - * Reorder and merge like edit sections. Merge equalities. - * Any edit section can move as long as it doesn't cross an equality. - * @param {!Array.} diffs Array of diff tuples. - */ -diff_match_patch.prototype.diff_cleanupMerge = function(diffs) { - diffs.push([DIFF_EQUAL, '']); // Add a dummy entry at the end. - var pointer = 0; - var count_delete = 0; - var count_insert = 0; - var text_delete = ''; - var text_insert = ''; - var commonlength; - while (pointer < diffs.length) { - switch (diffs[pointer][0]) { - case DIFF_INSERT: - count_insert++; - text_insert += diffs[pointer][1]; - pointer++; - break; - case DIFF_DELETE: - count_delete++; - text_delete += diffs[pointer][1]; - pointer++; - break; - case DIFF_EQUAL: - // Upon reaching an equality, check for prior redundancies. - if (count_delete + count_insert > 1) { - if (count_delete !== 0 && count_insert !== 0) { - // Factor out any common prefixies. - commonlength = this.diff_commonPrefix(text_insert, text_delete); - if (commonlength !== 0) { - if ((pointer - count_delete - count_insert) > 0 && - diffs[pointer - count_delete - count_insert - 1][0] == - DIFF_EQUAL) { - diffs[pointer - count_delete - count_insert - 1][1] += - text_insert.substring(0, commonlength); - } else { - diffs.splice(0, 0, [DIFF_EQUAL, - text_insert.substring(0, commonlength)]); - pointer++; - } - text_insert = text_insert.substring(commonlength); - text_delete = text_delete.substring(commonlength); - } - // Factor out any common suffixies. - commonlength = this.diff_commonSuffix(text_insert, text_delete); - if (commonlength !== 0) { - diffs[pointer][1] = text_insert.substring(text_insert.length - - commonlength) + diffs[pointer][1]; - text_insert = text_insert.substring(0, text_insert.length - - commonlength); - text_delete = text_delete.substring(0, text_delete.length - - commonlength); - } - } - // Delete the offending records and add the merged ones. - if (count_delete === 0) { - diffs.splice(pointer - count_insert, - count_delete + count_insert, [DIFF_INSERT, text_insert]); - } else if (count_insert === 0) { - diffs.splice(pointer - count_delete, - count_delete + count_insert, [DIFF_DELETE, text_delete]); - } else { - diffs.splice(pointer - count_delete - count_insert, - count_delete + count_insert, [DIFF_DELETE, text_delete], - [DIFF_INSERT, text_insert]); - } - pointer = pointer - count_delete - count_insert + - (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1; - } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) { - // Merge this equality with the previous one. - diffs[pointer - 1][1] += diffs[pointer][1]; - diffs.splice(pointer, 1); - } else { - pointer++; - } - count_insert = 0; - count_delete = 0; - text_delete = ''; - text_insert = ''; - break; - } - } - if (diffs[diffs.length - 1][1] === '') { - diffs.pop(); // Remove the dummy entry at the end. - } - - // Second pass: look for single edits surrounded on both sides by equalities - // which can be shifted sideways to eliminate an equality. - // e.g: ABAC -> ABAC - var changes = false; - pointer = 1; - // Intentionally ignore the first and last element (don't need checking). - while (pointer < diffs.length - 1) { - if (diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL) { - // This is a single edit surrounded by equalities. - if (diffs[pointer][1].substring(diffs[pointer][1].length - - diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { - // Shift the edit over the previous equality. - diffs[pointer][1] = diffs[pointer - 1][1] + - diffs[pointer][1].substring(0, diffs[pointer][1].length - - diffs[pointer - 1][1].length); - diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; - diffs.splice(pointer - 1, 1); - changes = true; - } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == - diffs[pointer + 1][1]) { - // Shift the edit over the next equality. - diffs[pointer - 1][1] += diffs[pointer + 1][1]; - diffs[pointer][1] = - diffs[pointer][1].substring(diffs[pointer + 1][1].length) + - diffs[pointer + 1][1]; - diffs.splice(pointer + 1, 1); - changes = true; - } - } - pointer++; - } - // If shifts were made, the diff needs reordering and another shift sweep. - if (changes) { - this.diff_cleanupMerge(diffs); - } -}; - - -/** - * loc is a location in text1, compute and return the equivalent location in - * text2. - * e.g. 'The cat' vs 'The big cat', 1->1, 5->8 - * @param {!Array.} diffs Array of diff tuples. - * @param {number} loc Location within text1. - * @return {number} Location within text2. - */ -diff_match_patch.prototype.diff_xIndex = function(diffs, loc) { - var chars1 = 0; - var chars2 = 0; - var last_chars1 = 0; - var last_chars2 = 0; - var x; - for (x = 0; x < diffs.length; x++) { - if (diffs[x][0] !== DIFF_INSERT) { // Equality or deletion. - chars1 += diffs[x][1].length; - } - if (diffs[x][0] !== DIFF_DELETE) { // Equality or insertion. - chars2 += diffs[x][1].length; - } - if (chars1 > loc) { // Overshot the location. - break; - } - last_chars1 = chars1; - last_chars2 = chars2; - } - // Was the location was deleted? - if (diffs.length != x && diffs[x][0] === DIFF_DELETE) { - return last_chars2; - } - // Add the remaining character length. - return last_chars2 + (loc - last_chars1); -}; - - -/** - * Convert a diff array into a pretty HTML report. - * @param {!Array.} diffs Array of diff tuples. - * @return {string} HTML representation. - */ -diff_match_patch.prototype.diff_prettyHtml = function(diffs) { - var html = []; - var pattern_amp = /&/g; - var pattern_lt = //g; - var pattern_para = /\n/g; - for (var x = 0; x < diffs.length; x++) { - var op = diffs[x][0]; // Operation (insert, delete, equal) - var data = diffs[x][1]; // Text of change. - var text = data.replace(pattern_amp, '&').replace(pattern_lt, '<') - .replace(pattern_gt, '>').replace(pattern_para, '¶
'); - switch (op) { - case DIFF_INSERT: - html[x] = '' + text + ''; - break; - case DIFF_DELETE: - html[x] = '' + text + ''; - break; - case DIFF_EQUAL: - html[x] = '' + text + ''; - break; - } - } - return html.join(''); -}; - - -/** - * Compute and return the source text (all equalities and deletions). - * @param {!Array.} diffs Array of diff tuples. - * @return {string} Source text. - */ -diff_match_patch.prototype.diff_text1 = function(diffs) { - var text = []; - for (var x = 0; x < diffs.length; x++) { - if (diffs[x][0] !== DIFF_INSERT) { - text[x] = diffs[x][1]; - } - } - return text.join(''); -}; - - -/** - * Compute and return the destination text (all equalities and insertions). - * @param {!Array.} diffs Array of diff tuples. - * @return {string} Destination text. - */ -diff_match_patch.prototype.diff_text2 = function(diffs) { - var text = []; - for (var x = 0; x < diffs.length; x++) { - if (diffs[x][0] !== DIFF_DELETE) { - text[x] = diffs[x][1]; - } - } - return text.join(''); -}; - - -/** - * Compute the Levenshtein distance; the number of inserted, deleted or - * substituted characters. - * @param {!Array.} diffs Array of diff tuples. - * @return {number} Number of changes. - */ -diff_match_patch.prototype.diff_levenshtein = function(diffs) { - var levenshtein = 0; - var insertions = 0; - var deletions = 0; - for (var x = 0; x < diffs.length; x++) { - var op = diffs[x][0]; - var data = diffs[x][1]; - switch (op) { - case DIFF_INSERT: - insertions += data.length; - break; - case DIFF_DELETE: - deletions += data.length; - break; - case DIFF_EQUAL: - // A deletion and an insertion is one substitution. - levenshtein += Math.max(insertions, deletions); - insertions = 0; - deletions = 0; - break; - } - } - levenshtein += Math.max(insertions, deletions); - return levenshtein; -}; - - -/** - * Crush the diff into an encoded string which describes the operations - * required to transform text1 into text2. - * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'. - * Operations are tab-separated. Inserted text is escaped using %xx notation. - * @param {!Array.} diffs Array of diff tuples. - * @return {string} Delta text. - */ -diff_match_patch.prototype.diff_toDelta = function(diffs) { - var text = []; - for (var x = 0; x < diffs.length; x++) { - switch (diffs[x][0]) { - case DIFF_INSERT: - text[x] = '+' + encodeURI(diffs[x][1]); - break; - case DIFF_DELETE: - text[x] = '-' + diffs[x][1].length; - break; - case DIFF_EQUAL: - text[x] = '=' + diffs[x][1].length; - break; - } - } - return text.join('\t').replace(/%20/g, ' '); -}; - - -/** - * Given the original text1, and an encoded string which describes the - * operations required to transform text1 into text2, compute the full diff. - * @param {string} text1 Source string for the diff. - * @param {string} delta Delta text. - * @return {!Array.} Array of diff tuples. - * @throws {!Error} If invalid input. - */ -diff_match_patch.prototype.diff_fromDelta = function(text1, delta) { - var diffs = []; - var diffsLength = 0; // Keeping our own length var is faster in JS. - var pointer = 0; // Cursor in text1 - var tokens = delta.split(/\t/g); - for (var x = 0; x < tokens.length; x++) { - // Each token begins with a one character parameter which specifies the - // operation of this token (delete, insert, equality). - var param = tokens[x].substring(1); - switch (tokens[x].charAt(0)) { - case '+': - try { - diffs[diffsLength++] = [DIFF_INSERT, decodeURI(param)]; - } catch (ex) { - // Malformed URI sequence. - throw new Error('Illegal escape in diff_fromDelta: ' + param); - } - break; - case '-': - // Fall through. - case '=': - var n = parseInt(param, 10); - if (isNaN(n) || n < 0) { - throw new Error('Invalid number in diff_fromDelta: ' + param); - } - var text = text1.substring(pointer, pointer += n); - if (tokens[x].charAt(0) == '=') { - diffs[diffsLength++] = [DIFF_EQUAL, text]; - } else { - diffs[diffsLength++] = [DIFF_DELETE, text]; - } - break; - default: - // Blank tokens are ok (from a trailing \t). - // Anything else is an error. - if (tokens[x]) { - throw new Error('Invalid diff operation in diff_fromDelta: ' + - tokens[x]); - } - } - } - if (pointer != text1.length) { - throw new Error('Delta length (' + pointer + - ') does not equal source text length (' + text1.length + ').'); - } - return diffs; -}; - - -// MATCH FUNCTIONS - - -/** - * Locate the best instance of 'pattern' in 'text' near 'loc'. - * @param {string} text The text to search. - * @param {string} pattern The pattern to search for. - * @param {number} loc The location to search around. - * @return {number} Best match index or -1. - */ -diff_match_patch.prototype.match_main = function(text, pattern, loc) { - // Check for null inputs. - if (text == null || pattern == null || loc == null) { - throw new Error('Null input. (match_main)'); - } - - loc = Math.max(0, Math.min(loc, text.length)); - if (text == pattern) { - // Shortcut (potentially not guaranteed by the algorithm) - return 0; - } else if (!text.length) { - // Nothing to match. - return -1; - } else if (text.substring(loc, loc + pattern.length) == pattern) { - // Perfect match at the perfect spot! (Includes case of null pattern) - return loc; - } else { - // Do a fuzzy compare. - return this.match_bitap_(text, pattern, loc); - } -}; - - -/** - * Locate the best instance of 'pattern' in 'text' near 'loc' using the - * Bitap algorithm. - * @param {string} text The text to search. - * @param {string} pattern The pattern to search for. - * @param {number} loc The location to search around. - * @return {number} Best match index or -1. - * @private - */ -diff_match_patch.prototype.match_bitap_ = function(text, pattern, loc) { - if (pattern.length > this.Match_MaxBits) { - throw new Error('Pattern too long for this browser.'); - } - - // Initialise the alphabet. - var s = this.match_alphabet_(pattern); - - var dmp = this; // 'this' becomes 'window' in a closure. - - /** - * Compute and return the score for a match with e errors and x location. - * Accesses loc and pattern through being a closure. - * @param {number} e Number of errors in match. - * @param {number} x Location of match. - * @return {number} Overall score for match (0.0 = good, 1.0 = bad). - * @private - */ - function match_bitapScore_(e, x) { - var accuracy = e / pattern.length; - var proximity = Math.abs(loc - x); - if (!dmp.Match_Distance) { - // Dodge divide by zero error. - return proximity ? 1.0 : accuracy; - } - return accuracy + (proximity / dmp.Match_Distance); - } - - // Highest score beyond which we give up. - var score_threshold = this.Match_Threshold; - // Is there a nearby exact match? (speedup) - var best_loc = text.indexOf(pattern, loc); - if (best_loc != -1) { - score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); - // What about in the other direction? (speedup) - best_loc = text.lastIndexOf(pattern, loc + pattern.length); - if (best_loc != -1) { - score_threshold = - Math.min(match_bitapScore_(0, best_loc), score_threshold); - } - } - - // Initialise the bit arrays. - var matchmask = 1 << (pattern.length - 1); - best_loc = -1; - - var bin_min, bin_mid; - var bin_max = pattern.length + text.length; - var last_rd; - for (var d = 0; d < pattern.length; d++) { - // Scan for the best match; each iteration allows for one more error. - // Run a binary search to determine how far from 'loc' we can stray at this - // error level. - bin_min = 0; - bin_mid = bin_max; - while (bin_min < bin_mid) { - if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) { - bin_min = bin_mid; - } else { - bin_max = bin_mid; - } - bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min); - } - // Use the result from this iteration as the maximum for the next. - bin_max = bin_mid; - var start = Math.max(1, loc - bin_mid + 1); - var finish = Math.min(loc + bin_mid, text.length) + pattern.length; - - var rd = Array(finish + 2); - rd[finish + 1] = (1 << d) - 1; - for (var j = finish; j >= start; j--) { - // The alphabet (s) is a sparse hash, so the following line generates - // warnings. - var charMatch = s[text.charAt(j - 1)]; - if (d === 0) { // First pass: exact match. - rd[j] = ((rd[j + 1] << 1) | 1) & charMatch; - } else { // Subsequent passes: fuzzy match. - rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) | - (((last_rd[j + 1] | last_rd[j]) << 1) | 1) | - last_rd[j + 1]; - } - if (rd[j] & matchmask) { - var score = match_bitapScore_(d, j - 1); - // This match will almost certainly be better than any existing match. - // But check anyway. - if (score <= score_threshold) { - // Told you so. - score_threshold = score; - best_loc = j - 1; - if (best_loc > loc) { - // When passing loc, don't exceed our current distance from loc. - start = Math.max(1, 2 * loc - best_loc); - } else { - // Already passed loc, downhill from here on in. - break; - } - } - } - } - // No hope for a (better) match at greater error levels. - if (match_bitapScore_(d + 1, loc) > score_threshold) { - break; - } - last_rd = rd; - } - return best_loc; -}; - - -/** - * Initialise the alphabet for the Bitap algorithm. - * @param {string} pattern The text to encode. - * @return {!Object} Hash of character locations. - * @private - */ -diff_match_patch.prototype.match_alphabet_ = function(pattern) { - var s = {}; - for (var i = 0; i < pattern.length; i++) { - s[pattern.charAt(i)] = 0; - } - for (var i = 0; i < pattern.length; i++) { - s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1); - } - return s; -}; - - -// PATCH FUNCTIONS - - -/** - * Increase the context until it is unique, - * but don't let the pattern expand beyond Match_MaxBits. - * @param {!diff_match_patch.patch_obj} patch The patch to grow. - * @param {string} text Source text. - * @private - */ -diff_match_patch.prototype.patch_addContext_ = function(patch, text) { - if (text.length == 0) { - return; - } - var pattern = text.substring(patch.start2, patch.start2 + patch.length1); - var padding = 0; - - // Look for the first and last matches of pattern in text. If two different - // matches are found, increase the pattern length. - while (text.indexOf(pattern) != text.lastIndexOf(pattern) && - pattern.length < this.Match_MaxBits - this.Patch_Margin - - this.Patch_Margin) { - padding += this.Patch_Margin; - pattern = text.substring(patch.start2 - padding, - patch.start2 + patch.length1 + padding); - } - // Add one chunk for good luck. - padding += this.Patch_Margin; - - // Add the prefix. - var prefix = text.substring(patch.start2 - padding, patch.start2); - if (prefix) { - patch.diffs.unshift([DIFF_EQUAL, prefix]); - } - // Add the suffix. - var suffix = text.substring(patch.start2 + patch.length1, - patch.start2 + patch.length1 + padding); - if (suffix) { - patch.diffs.push([DIFF_EQUAL, suffix]); - } - - // Roll back the start points. - patch.start1 -= prefix.length; - patch.start2 -= prefix.length; - // Extend the lengths. - patch.length1 += prefix.length + suffix.length; - patch.length2 += prefix.length + suffix.length; -}; - - -/** - * Compute a list of patches to turn text1 into text2. - * Use diffs if provided, otherwise compute it ourselves. - * There are four ways to call this function, depending on what data is - * available to the caller: - * Method 1: - * a = text1, b = text2 - * Method 2: - * a = diffs - * Method 3 (optimal): - * a = text1, b = diffs - * Method 4 (deprecated, use method 3): - * a = text1, b = text2, c = diffs - * - * @param {string|!Array.} a text1 (methods 1,3,4) or - * Array of diff tuples for text1 to text2 (method 2). - * @param {string|!Array.} opt_b text2 (methods 1,4) or - * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2). - * @param {string|!Array.} opt_c Array of diff tuples - * for text1 to text2 (method 4) or undefined (methods 1,2,3). - * @return {!Array.} Array of Patch objects. - */ -diff_match_patch.prototype.patch_make = function(a, opt_b, opt_c) { - var text1, diffs; - if (typeof a == 'string' && typeof opt_b == 'string' && - typeof opt_c == 'undefined') { - // Method 1: text1, text2 - // Compute diffs from text1 and text2. - text1 = /** @type {string} */(a); - diffs = this.diff_main(text1, /** @type {string} */(opt_b), true); - if (diffs.length > 2) { - this.diff_cleanupSemantic(diffs); - this.diff_cleanupEfficiency(diffs); - } - } else if (a && typeof a == 'object' && typeof opt_b == 'undefined' && - typeof opt_c == 'undefined') { - // Method 2: diffs - // Compute text1 from diffs. - diffs = /** @type {!Array.} */(a); - text1 = this.diff_text1(diffs); - } else if (typeof a == 'string' && opt_b && typeof opt_b == 'object' && - typeof opt_c == 'undefined') { - // Method 3: text1, diffs - text1 = /** @type {string} */(a); - diffs = /** @type {!Array.} */(opt_b); - } else if (typeof a == 'string' && typeof opt_b == 'string' && - opt_c && typeof opt_c == 'object') { - // Method 4: text1, text2, diffs - // text2 is not used. - text1 = /** @type {string} */(a); - diffs = /** @type {!Array.} */(opt_c); - } else { - throw new Error('Unknown call format to patch_make.'); - } - - if (diffs.length === 0) { - return []; // Get rid of the null case. - } - var patches = []; - var patch = new diff_match_patch.patch_obj(); - var patchDiffLength = 0; // Keeping our own length var is faster in JS. - var char_count1 = 0; // Number of characters into the text1 string. - var char_count2 = 0; // Number of characters into the text2 string. - // Start with text1 (prepatch_text) and apply the diffs until we arrive at - // text2 (postpatch_text). We recreate the patches one by one to determine - // context info. - var prepatch_text = text1; - var postpatch_text = text1; - for (var x = 0; x < diffs.length; x++) { - var diff_type = diffs[x][0]; - var diff_text = diffs[x][1]; - - if (!patchDiffLength && diff_type !== DIFF_EQUAL) { - // A new patch starts here. - patch.start1 = char_count1; - patch.start2 = char_count2; - } - - switch (diff_type) { - case DIFF_INSERT: - patch.diffs[patchDiffLength++] = diffs[x]; - patch.length2 += diff_text.length; - postpatch_text = postpatch_text.substring(0, char_count2) + diff_text + - postpatch_text.substring(char_count2); - break; - case DIFF_DELETE: - patch.length1 += diff_text.length; - patch.diffs[patchDiffLength++] = diffs[x]; - postpatch_text = postpatch_text.substring(0, char_count2) + - postpatch_text.substring(char_count2 + - diff_text.length); - break; - case DIFF_EQUAL: - if (diff_text.length <= 2 * this.Patch_Margin && - patchDiffLength && diffs.length != x + 1) { - // Small equality inside a patch. - patch.diffs[patchDiffLength++] = diffs[x]; - patch.length1 += diff_text.length; - patch.length2 += diff_text.length; - } else if (diff_text.length >= 2 * this.Patch_Margin) { - // Time for a new patch. - if (patchDiffLength) { - this.patch_addContext_(patch, prepatch_text); - patches.push(patch); - patch = new diff_match_patch.patch_obj(); - patchDiffLength = 0; - // Unlike Unidiff, our patch lists have a rolling context. - // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff - // Update prepatch text & pos to reflect the application of the - // just completed patch. - prepatch_text = postpatch_text; - char_count1 = char_count2; - } - } - break; - } - - // Update the current character count. - if (diff_type !== DIFF_INSERT) { - char_count1 += diff_text.length; - } - if (diff_type !== DIFF_DELETE) { - char_count2 += diff_text.length; - } - } - // Pick up the leftover patch if not empty. - if (patchDiffLength) { - this.patch_addContext_(patch, prepatch_text); - patches.push(patch); - } - - return patches; -}; - - -/** - * Given an array of patches, return another array that is identical. - * @param {!Array.} patches Array of Patch objects. - * @return {!Array.} Array of Patch objects. - */ -diff_match_patch.prototype.patch_deepCopy = function(patches) { - // Making deep copies is hard in JavaScript. - var patchesCopy = []; - for (var x = 0; x < patches.length; x++) { - var patch = patches[x]; - var patchCopy = new diff_match_patch.patch_obj(); - patchCopy.diffs = []; - for (var y = 0; y < patch.diffs.length; y++) { - patchCopy.diffs[y] = patch.diffs[y].slice(); - } - patchCopy.start1 = patch.start1; - patchCopy.start2 = patch.start2; - patchCopy.length1 = patch.length1; - patchCopy.length2 = patch.length2; - patchesCopy[x] = patchCopy; - } - return patchesCopy; -}; - - -/** - * Merge a set of patches onto the text. Return a patched text, as well - * as a list of true/false values indicating which patches were applied. - * @param {!Array.} patches Array of Patch objects. - * @param {string} text Old text. - * @return {!Array.>} Two element Array, containing the - * new text and an array of boolean values. - */ -diff_match_patch.prototype.patch_apply = function(patches, text) { - if (patches.length == 0) { - return [text, []]; - } - - // Deep copy the patches so that no changes are made to originals. - patches = this.patch_deepCopy(patches); - - var nullPadding = this.patch_addPadding(patches); - text = nullPadding + text + nullPadding; - - this.patch_splitMax(patches); - // delta keeps track of the offset between the expected and actual location - // of the previous patch. If there are patches expected at positions 10 and - // 20, but the first patch was found at 12, delta is 2 and the second patch - // has an effective expected position of 22. - var delta = 0; - var results = []; - for (var x = 0; x < patches.length; x++) { - var expected_loc = patches[x].start2 + delta; - var text1 = this.diff_text1(patches[x].diffs); - var start_loc; - var end_loc = -1; - if (text1.length > this.Match_MaxBits) { - // patch_splitMax will only provide an oversized pattern in the case of - // a monster delete. - start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits), - expected_loc); - if (start_loc != -1) { - end_loc = this.match_main(text, - text1.substring(text1.length - this.Match_MaxBits), - expected_loc + text1.length - this.Match_MaxBits); - if (end_loc == -1 || start_loc >= end_loc) { - // Can't find valid trailing context. Drop this patch. - start_loc = -1; - } - } - } else { - start_loc = this.match_main(text, text1, expected_loc); - } - if (start_loc == -1) { - // No match found. :( - results[x] = false; - // Subtract the delta for this failed patch from subsequent patches. - delta -= patches[x].length2 - patches[x].length1; - } else { - // Found a match. :) - results[x] = true; - delta = start_loc - expected_loc; - var text2; - if (end_loc == -1) { - text2 = text.substring(start_loc, start_loc + text1.length); - } else { - text2 = text.substring(start_loc, end_loc + this.Match_MaxBits); - } - if (text1 == text2) { - // Perfect match, just shove the replacement text in. - text = text.substring(0, start_loc) + - this.diff_text2(patches[x].diffs) + - text.substring(start_loc + text1.length); - } else { - // Imperfect match. Run a diff to get a framework of equivalent - // indices. - var diffs = this.diff_main(text1, text2, false); - if (text1.length > this.Match_MaxBits && - this.diff_levenshtein(diffs) / text1.length > - this.Patch_DeleteThreshold) { - // The end points match, but the content is unacceptably bad. - results[x] = false; - } else { - this.diff_cleanupSemanticLossless(diffs); - var index1 = 0; - var index2; - for (var y = 0; y < patches[x].diffs.length; y++) { - var mod = patches[x].diffs[y]; - if (mod[0] !== DIFF_EQUAL) { - index2 = this.diff_xIndex(diffs, index1); - } - if (mod[0] === DIFF_INSERT) { // Insertion - text = text.substring(0, start_loc + index2) + mod[1] + - text.substring(start_loc + index2); - } else if (mod[0] === DIFF_DELETE) { // Deletion - text = text.substring(0, start_loc + index2) + - text.substring(start_loc + this.diff_xIndex(diffs, - index1 + mod[1].length)); - } - if (mod[0] !== DIFF_DELETE) { - index1 += mod[1].length; - } - } - } - } - } - } - // Strip the padding off. - text = text.substring(nullPadding.length, text.length - nullPadding.length); - return [text, results]; -}; - - -/** - * Add some padding on text start and end so that edges can match something. - * Intended to be called only from within patch_apply. - * @param {!Array.} patches Array of Patch objects. - * @return {string} The padding string added to each side. - */ -diff_match_patch.prototype.patch_addPadding = function(patches) { - var paddingLength = this.Patch_Margin; - var nullPadding = ''; - for (var x = 1; x <= paddingLength; x++) { - nullPadding += String.fromCharCode(x); - } - - // Bump all the patches forward. - for (var x = 0; x < patches.length; x++) { - patches[x].start1 += paddingLength; - patches[x].start2 += paddingLength; - } - - // Add some padding on start of first diff. - var patch = patches[0]; - var diffs = patch.diffs; - if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) { - // Add nullPadding equality. - diffs.unshift([DIFF_EQUAL, nullPadding]); - patch.start1 -= paddingLength; // Should be 0. - patch.start2 -= paddingLength; // Should be 0. - patch.length1 += paddingLength; - patch.length2 += paddingLength; - } else if (paddingLength > diffs[0][1].length) { - // Grow first equality. - var extraLength = paddingLength - diffs[0][1].length; - diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1]; - patch.start1 -= extraLength; - patch.start2 -= extraLength; - patch.length1 += extraLength; - patch.length2 += extraLength; - } - - // Add some padding on end of last diff. - patch = patches[patches.length - 1]; - diffs = patch.diffs; - if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) { - // Add nullPadding equality. - diffs.push([DIFF_EQUAL, nullPadding]); - patch.length1 += paddingLength; - patch.length2 += paddingLength; - } else if (paddingLength > diffs[diffs.length - 1][1].length) { - // Grow last equality. - var extraLength = paddingLength - diffs[diffs.length - 1][1].length; - diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength); - patch.length1 += extraLength; - patch.length2 += extraLength; - } - - return nullPadding; -}; - - -/** - * Look through the patches and break up any which are longer than the maximum - * limit of the match algorithm. - * Intended to be called only from within patch_apply. - * @param {!Array.} patches Array of Patch objects. - */ -diff_match_patch.prototype.patch_splitMax = function(patches) { - var patch_size = this.Match_MaxBits; - for (var x = 0; x < patches.length; x++) { - if (patches[x].length1 <= patch_size) { - continue; - } - var bigpatch = patches[x]; - // Remove the big old patch. - patches.splice(x--, 1); - var start1 = bigpatch.start1; - var start2 = bigpatch.start2; - var precontext = ''; - while (bigpatch.diffs.length !== 0) { - // Create one of several smaller patches. - var patch = new diff_match_patch.patch_obj(); - var empty = true; - patch.start1 = start1 - precontext.length; - patch.start2 = start2 - precontext.length; - if (precontext !== '') { - patch.length1 = patch.length2 = precontext.length; - patch.diffs.push([DIFF_EQUAL, precontext]); - } - while (bigpatch.diffs.length !== 0 && - patch.length1 < patch_size - this.Patch_Margin) { - var diff_type = bigpatch.diffs[0][0]; - var diff_text = bigpatch.diffs[0][1]; - if (diff_type === DIFF_INSERT) { - // Insertions are harmless. - patch.length2 += diff_text.length; - start2 += diff_text.length; - patch.diffs.push(bigpatch.diffs.shift()); - empty = false; - } else if (diff_type === DIFF_DELETE && patch.diffs.length == 1 && - patch.diffs[0][0] == DIFF_EQUAL && - diff_text.length > 2 * patch_size) { - // This is a large deletion. Let it pass in one chunk. - patch.length1 += diff_text.length; - start1 += diff_text.length; - empty = false; - patch.diffs.push([diff_type, diff_text]); - bigpatch.diffs.shift(); - } else { - // Deletion or equality. Only take as much as we can stomach. - diff_text = diff_text.substring(0, - patch_size - patch.length1 - this.Patch_Margin); - patch.length1 += diff_text.length; - start1 += diff_text.length; - if (diff_type === DIFF_EQUAL) { - patch.length2 += diff_text.length; - start2 += diff_text.length; - } else { - empty = false; - } - patch.diffs.push([diff_type, diff_text]); - if (diff_text == bigpatch.diffs[0][1]) { - bigpatch.diffs.shift(); - } else { - bigpatch.diffs[0][1] = - bigpatch.diffs[0][1].substring(diff_text.length); - } - } - } - // Compute the head context for the next patch. - precontext = this.diff_text2(patch.diffs); - precontext = - precontext.substring(precontext.length - this.Patch_Margin); - // Append the end context for this patch. - var postcontext = this.diff_text1(bigpatch.diffs) - .substring(0, this.Patch_Margin); - if (postcontext !== '') { - patch.length1 += postcontext.length; - patch.length2 += postcontext.length; - if (patch.diffs.length !== 0 && - patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL) { - patch.diffs[patch.diffs.length - 1][1] += postcontext; - } else { - patch.diffs.push([DIFF_EQUAL, postcontext]); - } - } - if (!empty) { - patches.splice(++x, 0, patch); - } - } - } -}; - - -/** - * Take a list of patches and return a textual representation. - * @param {!Array.} patches Array of Patch objects. - * @return {string} Text representation of patches. - */ -diff_match_patch.prototype.patch_toText = function(patches) { - var text = []; - for (var x = 0; x < patches.length; x++) { - text[x] = patches[x]; - } - return text.join(''); -}; - - -/** - * Parse a textual representation of patches and return a list of Patch objects. - * @param {string} textline Text representation of patches. - * @return {!Array.} Array of Patch objects. - * @throws {!Error} If invalid input. - */ -diff_match_patch.prototype.patch_fromText = function(textline) { - var patches = []; - if (!textline) { - return patches; - } - var text = textline.split('\n'); - var textPointer = 0; - var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/; - while (textPointer < text.length) { - var m = text[textPointer].match(patchHeader); - if (!m) { - throw new Error('Invalid patch string: ' + text[textPointer]); - } - var patch = new diff_match_patch.patch_obj(); - patches.push(patch); - patch.start1 = parseInt(m[1], 10); - if (m[2] === '') { - patch.start1--; - patch.length1 = 1; - } else if (m[2] == '0') { - patch.length1 = 0; - } else { - patch.start1--; - patch.length1 = parseInt(m[2], 10); - } - - patch.start2 = parseInt(m[3], 10); - if (m[4] === '') { - patch.start2--; - patch.length2 = 1; - } else if (m[4] == '0') { - patch.length2 = 0; - } else { - patch.start2--; - patch.length2 = parseInt(m[4], 10); - } - textPointer++; - - while (textPointer < text.length) { - var sign = text[textPointer].charAt(0); - try { - var line = decodeURI(text[textPointer].substring(1)); - } catch (ex) { - // Malformed URI sequence. - throw new Error('Illegal escape in patch_fromText: ' + line); - } - if (sign == '-') { - // Deletion. - patch.diffs.push([DIFF_DELETE, line]); - } else if (sign == '+') { - // Insertion. - patch.diffs.push([DIFF_INSERT, line]); - } else if (sign == ' ') { - // Minor equality. - patch.diffs.push([DIFF_EQUAL, line]); - } else if (sign == '@') { - // Start of next patch. - break; - } else if (sign === '') { - // Blank line? Whatever. - } else { - // WTF? - throw new Error('Invalid patch mode "' + sign + '" in: ' + line); - } - textPointer++; - } - } - return patches; -}; - - -/** - * Class representing one patch operation. - * @constructor - */ -diff_match_patch.patch_obj = function() { - /** @type {!Array.} */ - this.diffs = []; - /** @type {?number} */ - this.start1 = null; - /** @type {?number} */ - this.start2 = null; - /** @type {number} */ - this.length1 = 0; - /** @type {number} */ - this.length2 = 0; -}; - - -/** - * Emmulate GNU diff's format. - * Header: @@ -382,8 +481,9 @@ - * Indicies are printed as 1-based, not 0-based. - * @return {string} The GNU diff string. - */ -diff_match_patch.patch_obj.prototype.toString = function() { - var coords1, coords2; - if (this.length1 === 0) { - coords1 = this.start1 + ',0'; - } else if (this.length1 == 1) { - coords1 = this.start1 + 1; - } else { - coords1 = (this.start1 + 1) + ',' + this.length1; - } - if (this.length2 === 0) { - coords2 = this.start2 + ',0'; - } else if (this.length2 == 1) { - coords2 = this.start2 + 1; - } else { - coords2 = (this.start2 + 1) + ',' + this.length2; - } - var text = ['@@ -' + coords1 + ' +' + coords2 + ' @@\n']; - var op; - // Escape the body of the patch with %xx notation. - for (var x = 0; x < this.diffs.length; x++) { - switch (this.diffs[x][0]) { - case DIFF_INSERT: - op = '+'; - break; - case DIFF_DELETE: - op = '-'; - break; - case DIFF_EQUAL: - op = ' '; - break; - } - text[x + 1] = op + encodeURI(this.diffs[x][1]) + '\n'; - } - return text.join('').replace(/%20/g, ' '); -}; - - -// Export these global variables so that they survive Google's JS compiler. -// In a browser, 'this' will be 'window'. -// Users of node.js should 'require' the uncompressed version since Google's -// JS compiler may break the following exports for non-browser environments. -this['diff_match_patch'] = diff_match_patch; -this['DIFF_DELETE'] = DIFF_DELETE; -this['DIFF_INSERT'] = DIFF_INSERT; -this['DIFF_EQUAL'] = DIFF_EQUAL; - -},{}],39:[function(_dereq_,module,exports){ -'use strict'; - -// modified from https://github.com/es-shims/es5-shim -var has = Object.prototype.hasOwnProperty; -var toStr = Object.prototype.toString; -var isArgs = _dereq_('./isArguments'); -var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'); -var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); -var dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' -]; - -var keysShim = function keys(object) { - var isObject = object !== null && typeof object === 'object'; - var isFunction = toStr.call(object) === '[object Function]'; - var isArguments = isArgs(object); - var isString = isObject && toStr.call(object) === '[object String]'; - var theKeys = []; - - if (!isObject && !isFunction && !isArguments) { - throw new TypeError('Object.keys called on a non-object'); - } - - var skipProto = hasProtoEnumBug && isFunction; - if (isString && object.length > 0 && !has.call(object, 0)) { - for (var i = 0; i < object.length; ++i) { - theKeys.push(String(i)); - } - } - - if (isArguments && object.length > 0) { - for (var j = 0; j < object.length; ++j) { - theKeys.push(String(j)); - } - } else { - for (var name in object) { - if (!(skipProto && name === 'prototype') && has.call(object, name)) { - theKeys.push(String(name)); - } - } - } - - if (hasDontEnumBug) { - var ctor = object.constructor; - var skipConstructor = ctor && ctor.prototype === object; - - for (var k = 0; k < dontEnums.length; ++k) { - if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { - theKeys.push(dontEnums[k]); - } - } - } - return theKeys; -}; - -keysShim.shim = function shimObjectKeys() { - if (!Object.keys) { - Object.keys = keysShim; - } - return Object.keys || keysShim; -}; - -module.exports = keysShim; - -},{"./isArguments":40}],40:[function(_dereq_,module,exports){ -'use strict'; - -var toStr = Object.prototype.toString; - -module.exports = function isArguments(value) { - var str = toStr.call(value); - var isArgs = str === '[object Arguments]'; - if (!isArgs) { - isArgs = str !== '[object Array]' - && value !== null - && typeof value === 'object' - && typeof value.length === 'number' - && value.length >= 0 - && toStr.call(value.callee) === '[object Function]'; - } - return isArgs; -}; - -},{}],41:[function(_dereq_,module,exports){ -/** - * stringifier - * - * https://github.com/twada/stringifier - * - * Copyright (c) 2014-2015 Takuto Wada - * Licensed under the MIT license. - * http://twada.mit-license.org/2014-2015 - */ -'use strict'; - -var traverse = _dereq_('traverse'), - typeName = _dereq_('type-name'), - extend = _dereq_('xtend'), - s = _dereq_('./strategies'); - -function defaultHandlers () { - return { - 'null': s.always('null'), - 'undefined': s.always('undefined'), - 'function': s.prune(), - 'string': s.json(), - 'boolean': s.json(), - 'number': s.number(), - 'RegExp': s.toStr(), - 'String': s.newLike(), - 'Boolean': s.newLike(), - 'Number': s.newLike(), - 'Date': s.newLike(), - 'Array': s.array(), - 'Object': s.object(), - '@default': s.object() - }; -} - -function defaultOptions () { - return { - maxDepth: null, - indent: null, - anonymous: '@Anonymous', - circular: '#@Circular#', - snip: '..(snip)', - lineSeparator: '\n', - typeFun: typeName - }; -} - -function createStringifier (customOptions) { - var options = extend(defaultOptions(), customOptions), - handlers = extend(defaultHandlers(), options.handlers); - return function stringifyAny (push, x) { - var context = this, - handler = handlerFor(context.node, options, handlers), - currentPath = '/' + context.path.join('/'), - customization = handlers[currentPath], - acc = { - context: context, - options: options, - handlers: handlers, - push: push - }; - if (typeName(customization) === 'function') { - handler = customization; - } else if (typeName(customization) === 'number') { - handler = s.flow.compose(s.filters.truncate(customization),handler); - } - handler(acc, x); - return push; - }; -} - -function handlerFor (val, options, handlers) { - var tname = options.typeFun(val); - if (typeName(handlers[tname]) === 'function') { - return handlers[tname]; - } - return handlers['@default']; -} - -function walk (val, reducer) { - var buffer = [], - push = function (str) { - buffer.push(str); - }; - traverse(val).reduce(reducer, push); - return buffer.join(''); -} - -function stringify (val, options) { - return walk(val, createStringifier(options)); -} - -function stringifier (options) { - return function (val) { - return walk(val, createStringifier(options)); - }; -} - -stringifier.stringify = stringify; -stringifier.strategies = s; -stringifier.defaultOptions = defaultOptions; -stringifier.defaultHandlers = defaultHandlers; -module.exports = stringifier; - -},{"./strategies":42,"traverse":44,"type-name":43,"xtend":45}],42:[function(_dereq_,module,exports){ -'use strict'; - -var typeName = _dereq_('type-name'), - slice = Array.prototype.slice, - END = {}, - ITERATE = {}; - -// arguments should end with end or iterate -function compose () { - var filters = slice.apply(arguments); - return filters.reduceRight(function(right, left) { - return left(right); - }); -} - -// skip children -function end () { - return function (acc, x) { - acc.context.keys = []; - return END; - }; -} - -// iterate children -function iterate () { - return function (acc, x) { - return ITERATE; - }; -} - -function filter (predicate) { - return function (next) { - return function (acc, x) { - var toBeIterated, - isIteratingArray = (typeName(x) === 'Array'); - if (typeName(predicate) === 'function') { - toBeIterated = []; - acc.context.keys.forEach(function (key) { - var indexOrKey = isIteratingArray ? parseInt(key, 10) : key, - kvp = { - key: indexOrKey, - value: x[key] - }, - decision = predicate(kvp); - if (decision) { - toBeIterated.push(key); - } - if (typeName(decision) === 'number') { - truncateByKey(decision, key, acc); - } - if (typeName(decision) === 'function') { - customizeStrategyForKey(decision, key, acc); - } - }); - acc.context.keys = toBeIterated; - } - return next(acc, x); - }; - }; -} - -function customizeStrategyForKey (strategy, key, acc) { - acc.handlers[currentPath(key, acc)] = strategy; -} - -function truncateByKey (size, key, acc) { - acc.handlers[currentPath(key, acc)] = size; -} - -function currentPath (key, acc) { - var pathToCurrentNode = [''].concat(acc.context.path); - if (typeName(key) !== 'undefined') { - pathToCurrentNode.push(key); - } - return pathToCurrentNode.join('/'); -} - -function allowedKeys (orderedWhiteList) { - return function (next) { - return function (acc, x) { - var isIteratingArray = (typeName(x) === 'Array'); - if (!isIteratingArray && typeName(orderedWhiteList) === 'Array') { - acc.context.keys = orderedWhiteList.filter(function (propKey) { - return acc.context.keys.indexOf(propKey) !== -1; - }); - } - return next(acc, x); - }; - }; -} - -function safeKeys () { - return function (next) { - return function (acc, x) { - if (typeName(x) !== 'Array') { - acc.context.keys = acc.context.keys.filter(function (propKey) { - // Error handling for unsafe property access. - // For example, on PhantomJS, - // accessing HTMLInputElement.selectionEnd causes TypeError - try { - var val = x[propKey]; - return true; - } catch (e) { - // skip unsafe key - return false; - } - }); - } - return next(acc, x); - }; - }; -} - -function when (guard, then) { - return function (next) { - return function (acc, x) { - var kvp = { - key: acc.context.key, - value: x - }; - if (guard(kvp, acc)) { - return then(acc, x); - } - return next(acc, x); - }; - }; -} - -function truncate (size) { - return function (next) { - return function (acc, x) { - var orig = acc.push, ret; - acc.push = function (str) { - var savings = str.length - size, - truncated; - if (savings <= size) { - orig.call(acc, str); - } else { - truncated = str.substring(0, size); - orig.call(acc, truncated + acc.options.snip); - } - }; - ret = next(acc, x); - acc.push = orig; - return ret; - }; - }; -} - -function constructorName () { - return function (next) { - return function (acc, x) { - var name = acc.options.typeFun(x); - if (name === '') { - name = acc.options.anonymous; - } - acc.push(name); - return next(acc, x); - }; - }; -} - -function always (str) { - return function (next) { - return function (acc, x) { - acc.push(str); - return next(acc, x); - }; - }; -} - -function optionValue (key) { - return function (next) { - return function (acc, x) { - acc.push(acc.options[key]); - return next(acc, x); - }; - }; -} - -function json (replacer) { - return function (next) { - return function (acc, x) { - acc.push(JSON.stringify(x, replacer)); - return next(acc, x); - }; - }; -} - -function toStr () { - return function (next) { - return function (acc, x) { - acc.push(x.toString()); - return next(acc, x); - }; - }; -} - -function decorateArray () { - return function (next) { - return function (acc, x) { - acc.context.before(function (node) { - acc.push('['); - }); - acc.context.after(function (node) { - afterAllChildren(this, acc.push, acc.options); - acc.push(']'); - }); - acc.context.pre(function (val, key) { - beforeEachChild(this, acc.push, acc.options); - }); - acc.context.post(function (childContext) { - afterEachChild(childContext, acc.push); - }); - return next(acc, x); - }; - }; -} - -function decorateObject () { - return function (next) { - return function (acc, x) { - acc.context.before(function (node) { - acc.push('{'); - }); - acc.context.after(function (node) { - afterAllChildren(this, acc.push, acc.options); - acc.push('}'); - }); - acc.context.pre(function (val, key) { - beforeEachChild(this, acc.push, acc.options); - acc.push(sanitizeKey(key) + (acc.options.indent ? ': ' : ':')); - }); - acc.context.post(function (childContext) { - afterEachChild(childContext, acc.push); - }); - return next(acc, x); - }; - }; -} - -function sanitizeKey (key) { - return /^[A-Za-z_]+$/.test(key) ? key : JSON.stringify(key); -} - -function afterAllChildren (context, push, options) { - if (options.indent && 0 < context.keys.length) { - push(options.lineSeparator); - for(var i = 0; i < context.level; i += 1) { // indent level - 1 - push(options.indent); - } - } -} - -function beforeEachChild (context, push, options) { - if (options.indent) { - push(options.lineSeparator); - for(var i = 0; i <= context.level; i += 1) { - push(options.indent); - } - } -} - -function afterEachChild (childContext, push) { - if (!childContext.isLast) { - push(','); - } -} - -function nan (kvp, acc) { - return kvp.value !== kvp.value; -} - -function positiveInfinity (kvp, acc) { - return !isFinite(kvp.value) && kvp.value === Infinity; -} - -function negativeInfinity (kvp, acc) { - return !isFinite(kvp.value) && kvp.value !== Infinity; -} - -function circular (kvp, acc) { - return acc.context.circular; -} - -function maxDepth (kvp, acc) { - return (acc.options.maxDepth && acc.options.maxDepth <= acc.context.level); -} - -var prune = compose( - always('#'), - constructorName(), - always('#'), - end() -); -var omitNaN = when(nan, compose( - always('NaN'), - end() -)); -var omitPositiveInfinity = when(positiveInfinity, compose( - always('Infinity'), - end() -)); -var omitNegativeInfinity = when(negativeInfinity, compose( - always('-Infinity'), - end() -)); -var omitCircular = when(circular, compose( - optionValue('circular'), - end() -)); -var omitMaxDepth = when(maxDepth, prune); - -module.exports = { - filters: { - always: always, - constructorName: constructorName, - json: json, - toStr: toStr, - prune: prune, - truncate: truncate, - decorateArray: decorateArray, - decorateObject: decorateObject - }, - flow: { - compose: compose, - when: when, - allowedKeys: allowedKeys, - safeKeys: safeKeys, - filter: filter, - iterate: iterate, - end: end - }, - symbols: { - END: END, - ITERATE: ITERATE - }, - always: function (str) { - return compose(always(str), end()); - }, - json: function () { - return compose(json(), end()); - }, - toStr: function () { - return compose(toStr(), end()); - }, - prune: function () { - return prune; - }, - number: function () { - return compose( - omitNaN, - omitPositiveInfinity, - omitNegativeInfinity, - json(), - end() - ); - }, - newLike: function () { - return compose( - always('new '), - constructorName(), - always('('), - json(), - always(')'), - end() - ); - }, - array: function (predicate) { - return compose( - omitCircular, - omitMaxDepth, - decorateArray(), - filter(predicate), - iterate() - ); - }, - object: function (predicate, orderedWhiteList) { - return compose( - omitCircular, - omitMaxDepth, - constructorName(), - decorateObject(), - allowedKeys(orderedWhiteList), - safeKeys(), - filter(predicate), - iterate() - ); - } -}; - -},{"type-name":43}],43:[function(_dereq_,module,exports){ -/** - * type-name - Just a reasonable typeof - * - * https://github.com/twada/type-name - * - * Copyright (c) 2014 Takuto Wada - * Licensed under the MIT license. - * http://twada.mit-license.org/ - */ -'use strict'; - -var toStr = Object.prototype.toString; - -function funcName (f) { - return f.name ? f.name : /^\s*function\s*([^\(]*)/im.exec(f.toString())[1]; -} - -function ctorName (obj) { - var strName = toStr.call(obj).slice(8, -1); - if (strName === 'Object' && obj.constructor) { - return funcName(obj.constructor); - } - return strName; -} - -function typeName (val) { - var type; - if (val === null) { - return 'null'; - } - type = typeof(val); - if (type === 'object') { - return ctorName(val); - } - return type; -} - -module.exports = typeName; - -},{}],44:[function(_dereq_,module,exports){ -var traverse = module.exports = function (obj) { - return new Traverse(obj); -}; - -function Traverse (obj) { - this.value = obj; -} - -Traverse.prototype.get = function (ps) { - var node = this.value; - for (var i = 0; i < ps.length; i ++) { - var key = ps[i]; - if (!node || !hasOwnProperty.call(node, key)) { - node = undefined; - break; - } - node = node[key]; - } - return node; -}; - -Traverse.prototype.has = function (ps) { - var node = this.value; - for (var i = 0; i < ps.length; i ++) { - var key = ps[i]; - if (!node || !hasOwnProperty.call(node, key)) { - return false; - } - node = node[key]; - } - return true; -}; - -Traverse.prototype.set = function (ps, value) { - var node = this.value; - for (var i = 0; i < ps.length - 1; i ++) { - var key = ps[i]; - if (!hasOwnProperty.call(node, key)) node[key] = {}; - node = node[key]; - } - node[ps[i]] = value; - return value; -}; - -Traverse.prototype.map = function (cb) { - return walk(this.value, cb, true); -}; - -Traverse.prototype.forEach = function (cb) { - this.value = walk(this.value, cb, false); - return this.value; -}; - -Traverse.prototype.reduce = function (cb, init) { - var skip = arguments.length === 1; - var acc = skip ? this.value : init; - this.forEach(function (x) { - if (!this.isRoot || !skip) { - acc = cb.call(this, acc, x); - } - }); - return acc; -}; - -Traverse.prototype.paths = function () { - var acc = []; - this.forEach(function (x) { - acc.push(this.path); - }); - return acc; -}; - -Traverse.prototype.nodes = function () { - var acc = []; - this.forEach(function (x) { - acc.push(this.node); - }); - return acc; -}; - -Traverse.prototype.clone = function () { - var parents = [], nodes = []; - - return (function clone (src) { - for (var i = 0; i < parents.length; i++) { - if (parents[i] === src) { - return nodes[i]; - } - } - - if (typeof src === 'object' && src !== null) { - var dst = copy(src); - - parents.push(src); - nodes.push(dst); - - forEach(objectKeys(src), function (key) { - dst[key] = clone(src[key]); - }); - - parents.pop(); - nodes.pop(); - return dst; - } - else { - return src; - } - })(this.value); -}; - -function walk (root, cb, immutable) { - var path = []; - var parents = []; - var alive = true; - - return (function walker (node_) { - var node = immutable ? copy(node_) : node_; - var modifiers = {}; - - var keepGoing = true; - - var state = { - node : node, - node_ : node_, - path : [].concat(path), - parent : parents[parents.length - 1], - parents : parents, - key : path.slice(-1)[0], - isRoot : path.length === 0, - level : path.length, - circular : null, - update : function (x, stopHere) { - if (!state.isRoot) { - state.parent.node[state.key] = x; - } - state.node = x; - if (stopHere) keepGoing = false; - }, - 'delete' : function (stopHere) { - delete state.parent.node[state.key]; - if (stopHere) keepGoing = false; - }, - remove : function (stopHere) { - if (isArray(state.parent.node)) { - state.parent.node.splice(state.key, 1); - } - else { - delete state.parent.node[state.key]; - } - if (stopHere) keepGoing = false; - }, - keys : null, - before : function (f) { modifiers.before = f }, - after : function (f) { modifiers.after = f }, - pre : function (f) { modifiers.pre = f }, - post : function (f) { modifiers.post = f }, - stop : function () { alive = false }, - block : function () { keepGoing = false } - }; - - if (!alive) return state; - - function updateState() { - if (typeof state.node === 'object' && state.node !== null) { - if (!state.keys || state.node_ !== state.node) { - state.keys = objectKeys(state.node) - } - - state.isLeaf = state.keys.length == 0; - - for (var i = 0; i < parents.length; i++) { - if (parents[i].node_ === node_) { - state.circular = parents[i]; - break; - } - } - } - else { - state.isLeaf = true; - state.keys = null; - } - - state.notLeaf = !state.isLeaf; - state.notRoot = !state.isRoot; - } - - updateState(); - - // use return values to update if defined - var ret = cb.call(state, state.node); - if (ret !== undefined && state.update) state.update(ret); - - if (modifiers.before) modifiers.before.call(state, state.node); - - if (!keepGoing) return state; - - if (typeof state.node == 'object' - && state.node !== null && !state.circular) { - parents.push(state); - - updateState(); - - forEach(state.keys, function (key, i) { - path.push(key); - - if (modifiers.pre) modifiers.pre.call(state, state.node[key], key); - - var child = walker(state.node[key]); - if (immutable && hasOwnProperty.call(state.node, key)) { - state.node[key] = child.node; - } - - child.isLast = i == state.keys.length - 1; - child.isFirst = i == 0; - - if (modifiers.post) modifiers.post.call(state, child); - - path.pop(); - }); - parents.pop(); - } - - if (modifiers.after) modifiers.after.call(state, state.node); - - return state; - })(root).node; -} - -function copy (src) { - if (typeof src === 'object' && src !== null) { - var dst; - - if (isArray(src)) { - dst = []; - } - else if (isDate(src)) { - dst = new Date(src.getTime ? src.getTime() : src); - } - else if (isRegExp(src)) { - dst = new RegExp(src); - } - else if (isError(src)) { - dst = { message: src.message }; - } - else if (isBoolean(src)) { - dst = new Boolean(src); - } - else if (isNumber(src)) { - dst = new Number(src); - } - else if (isString(src)) { - dst = new String(src); - } - else if (Object.create && Object.getPrototypeOf) { - dst = Object.create(Object.getPrototypeOf(src)); - } - else if (src.constructor === Object) { - dst = {}; - } - else { - var proto = - (src.constructor && src.constructor.prototype) - || src.__proto__ - || {} - ; - var T = function () {}; - T.prototype = proto; - dst = new T; - } - - forEach(objectKeys(src), function (key) { - dst[key] = src[key]; - }); - return dst; - } - else return src; -} - -var objectKeys = Object.keys || function keys (obj) { - var res = []; - for (var key in obj) res.push(key) - return res; -}; - -function toS (obj) { return Object.prototype.toString.call(obj) } -function isDate (obj) { return toS(obj) === '[object Date]' } -function isRegExp (obj) { return toS(obj) === '[object RegExp]' } -function isError (obj) { return toS(obj) === '[object Error]' } -function isBoolean (obj) { return toS(obj) === '[object Boolean]' } -function isNumber (obj) { return toS(obj) === '[object Number]' } -function isString (obj) { return toS(obj) === '[object String]' } - -var isArray = Array.isArray || function isArray (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -var forEach = function (xs, fn) { - if (xs.forEach) return xs.forEach(fn) - else for (var i = 0; i < xs.length; i++) { - fn(xs[i], i, xs); - } -}; - -forEach(objectKeys(Traverse.prototype), function (key) { - traverse[key] = function (obj) { - var args = [].slice.call(arguments, 1); - var t = new Traverse(obj); - return t[key].apply(t, args); - }; -}); - -var hasOwnProperty = Object.hasOwnProperty || function (obj, key) { - return key in obj; -}; - -},{}],45:[function(_dereq_,module,exports){ -module.exports = extend - -function extend() { - var target = {} - - for (var i = 0; i < arguments.length; i++) { - var source = arguments[i] - - for (var key in source) { - if (source.hasOwnProperty(key)) { - target[key] = source[key] - } - } - } - - return target -} - -},{}],46:[function(_dereq_,module,exports){ -module.exports = extend - -function extend(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] - - for (var key in source) { - if (source.hasOwnProperty(key)) { - target[key] = source[key] - } - } - } - - return target -} - -},{}]},{},[7])(7) -}); - diff --git a/packages/planner/node_modules/deepcopy/deepcopy.js b/packages/planner/node_modules/deepcopy/deepcopy.js deleted file mode 100644 index cb66bc6a..00000000 --- a/packages/planner/node_modules/deepcopy/deepcopy.js +++ /dev/null @@ -1,229 +0,0 @@ -/*! - * @license deepcopy.js Copyright(c) 2013 sasa+1 - * https://github.com/sasaplus1/deepcopy.js - * Released under the MIT license. - */ - - -/** - * export to AMD/CommonJS/global. - * - * @param {Object} global global object. - * @param {Function} factory factory method. - */ -(function(global, factory) { - 'use strict'; - - if (typeof define === 'function' && !!define.amd) { - define(factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - global.deepcopy = factory(); - } -}(this, function() { - 'use strict'; - - var isNode, util, isBuffer, getKeys, getSymbols, indexOfArray; - - // is node.js/io.js? - isNode = (typeof process !== 'undefined' && typeof require !== 'undefined'); - - // fallback util module for browser. - util = (isNode) ? require('util') : (function() { - function isArray(value) { - return (typeof value === 'object' && - Object.prototype.toString.call(value) === '[object Array]'); - } - - function isDate(value) { - return (typeof value === 'object' && - Object.prototype.toString.call(value) === '[object Date]'); - } - - function isRegExp(value) { - return (typeof value === 'object' && - Object.prototype.toString.call(value) === '[object RegExp]'); - } - - function isSymbol(value) { - return (typeof value === 'symbol'); - } - - return { - isArray: (typeof Array.isArray === 'function') ? - function(obj) { - return Array.isArray(obj); - } : isArray, - isDate: isDate, - isRegExp: isRegExp, - isSymbol: (typeof Symbol === 'function') ? - isSymbol : - function() { - // always return false when Symbol is not supported. - return false; - } - }; - }()); - - // fallback Buffer.isBuffer - isBuffer = (isNode) ? - function(obj) { - return Buffer.isBuffer(obj); - } : - function() { - // if browser, always return false - return false; - }; - - // fallback Object.keys for old browsers. - getKeys = (typeof Object.keys === 'function') ? - function(obj) { - return Object.keys(obj); - } : - function(obj) { - var keys = [], - key; - - if (obj === null || typeof obj !== 'object') { - throw new TypeError('obj is not an Object'); - } - - for (key in obj) { - obj.hasOwnProperty(key) && keys.push(key); - } - - return keys; - }; - - // get symbols in object. - getSymbols = (typeof Symbol === 'function') ? - function(obj) { - return Object.getOwnPropertySymbols(obj); - } : - function() { - // always return empty array when Symbol is not supported. - return []; - }; - - // fallback Array#indexOf for old browsers. - indexOfArray = (typeof Array.prototype.indexOf === 'function') ? - function(array, searchElement) { - return array.indexOf(searchElement); - } : - function(array, searchElement) { - var i, len; - - if (!util.isArray(array)) { - throw new TypeError('array is not an Array'); - } - - for (i = 0, len = array.length; i < len; ++i) { - if (array[i] === searchElement) { - return i; - } - } - - return -1; - }; - - /** - * recursive deep copy for value. - * - * @private - * @param {*} value copy target. - * @param {*} clone - * @param {Array} visited - * @param {Array} reference - * @return {*} copied value. - */ - function copyValue_(value, clone, visited, reference) { - var str, pos, buf, keys, i, len, key, val, idx, obj, ref; - - // number, string, boolean, null, undefined, function and symbol. - if (value === null || typeof value !== 'object') { - return value; - } - - // Date. - if (util.isDate(value)) { - // Firefox need to convert to Number - // - // Firefox: - // var date = new Date; - // +date; // 1420909365967 - // +new Date(date); // 1420909365000 - // +new Date(+date); // 1420909365967 - // Chrome: - // var date = new Date; - // +date; // 1420909757913 - // +new Date(date); // 1420909757913 - // +new Date(+date); // 1420909757913 - return new Date(+value); - } - - // RegExp. - if (util.isRegExp(value)) { - // Chrome, Safari: - // (new RegExp).source => "(?:)" - // Firefox: - // (new RegExp).source => "" - // Chrome, Safari, Firefox - // String(new RegExp) => "/(?:)/" - str = String(value); - pos = str.lastIndexOf('/'); - - return new RegExp(str.slice(1, pos), str.slice(pos + 1)); - } - - // Buffer, node.js only. - if (isBuffer(value)) { - buf = new Buffer(value.length); - value.copy(buf); - - return buf; - } - - // Object or Array. - keys = getKeys(value).concat(getSymbols(value)); - - for (i = 0, len = keys.length; i < len; ++i) { - key = keys[i]; - val = value[key]; - - if (val !== null && typeof val === 'object') { - idx = indexOfArray(visited, val); - - if (idx === -1) { - // not circular reference - obj = (util.isArray(val)) ? [] : {}; - - visited.push(val); - reference.push(obj); - } else { - // circular reference - ref = reference[idx]; - } - } - - clone[key] = ref || copyValue_(val, obj, visited, reference); - } - - return clone; - } - - /** - * deep copy for value. - * - * @param {*} value copy target. - */ - function deepcopy(value) { - var clone = (util.isArray(value)) ? [] : {}, - visited = [value], - reference = [clone]; - - return copyValue_(value, clone, visited, reference); - } - - return deepcopy; -})); diff --git a/packages/planner/node_modules/deepcopy/package.json b/packages/planner/node_modules/deepcopy/package.json deleted file mode 100644 index 17cbb745..00000000 --- a/packages/planner/node_modules/deepcopy/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "deepcopy", - "version": "0.5.0", - "author": { - "name": "sasa+1", - "email": "sasaplus1@gmail.com" - }, - "contributors": [ - { - "name": "kjirou", - "email": "kjirou.web@gmail.com" - } - ], - "description": "deep copy for any data", - "main": "./deepcopy.js", - "license": "MIT", - "repository": { - "type": "git", - "url": "git://github.com/sasaplus1/deepcopy.js.git" - }, - "directories": { - "test": "test/" - }, - "scripts": { - "bower": "bower install", - "fix": "fixjsstyle --flagfile .closurelinter -r .", - "lint": "gjslint --flagfile .closurelinter -r .", - "minify": "uglifyjs ./deepcopy.js --comments '@license' -cm -r deepcopy -o ./deepcopy.min.js", - "power": "espower ./test/test.js > ./test/test.pwr.js", - "test": "mocha ./test/test.js", - "testem": "testem", - "travis": "testem ci --launch Firefox,PhantomJS" - }, - "devDependencies": { - "bower": "~1.4", - "espower-cli": "~0.2", - "intelli-espower-loader": "~0.6", - "mocha": "~2.2", - "power-assert": "~0.10", - "testem": "~0.7", - "uglify-js": "~2.4" - }, - "gitHead": "6fffac0b35e82d5ae67b756f6955f28d10f0fac1", - "bugs": { - "url": "https://github.com/sasaplus1/deepcopy.js/issues" - }, - "homepage": "https://github.com/sasaplus1/deepcopy.js", - "_id": "deepcopy@0.5.0", - "_shasum": "d2ca34335c2d31f54c1b4f13745e001977d491a2", - "_from": "deepcopy@*", - "_npmVersion": "2.7.5", - "_nodeVersion": "1.6.4", - "_npmUser": { - "name": "sasaplus1", - "email": "sasaplus1@gmail.com" - }, - "maintainers": [ - { - "name": "sasaplus1", - "email": "sasaplus1@gmail.com" - } - ], - "dist": { - "shasum": "d2ca34335c2d31f54c1b4f13745e001977d491a2", - "tarball": "http://registry.npmjs.org/deepcopy/-/deepcopy-0.5.0.tgz" - }, - "_resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-0.5.0.tgz", - "readme": "ERROR: No README data found!" -} diff --git a/packages/planner/node_modules/deepcopy/testem.json b/packages/planner/node_modules/deepcopy/testem.json deleted file mode 100644 index d49cd811..00000000 --- a/packages/planner/node_modules/deepcopy/testem.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "before_tests": "npm run power", - "on_exit": "rm ./test/test.pwr.js", - "test_page": "./test/index.html" -} diff --git a/packages/planner/package.js b/packages/planner/package.js index 6f8b1b61..e8731b52 100644 --- a/packages/planner/package.js +++ b/packages/planner/package.js @@ -7,15 +7,17 @@ Package.describe({ git: '', // By default, Meteor will default to using README.md for documentation. // To avoid submitting documentation, set this field to null. - documentation: 'README.md' + documentation: 'README.md', }); Package.onUse(function(api) { api.versionsFrom('1.1.0.2'); + api.use('erasaur:meteor-lodash'); + api.addFiles('planner.js'); - api.export("HomeworkDescription"); - api.export("Planner"); + api.export('HomeworkDescription'); + api.export('Planner'); }); Package.onTest(function(api) { diff --git a/packages/planner/package.json b/packages/planner/package.json new file mode 100644 index 00000000..ca6f6bf2 --- /dev/null +++ b/packages/planner/package.json @@ -0,0 +1,14 @@ +{ + "name": "planner", + "version": "0.0.1", + "description": "The plan algorithm of simplyHomework.", + "main": "planner.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "simply (http://www.simplyApps.nl/)", + "license": "UNLICENSED", + "dependencies": { + "lodash": "^3.10.1" + } +} diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 0da3e518..143d2458 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -4,7 +4,7 @@ * @module planner */ -var deepcopy=require("deepcopy"); +var _ = _ || require('lodash'); var assert = function (val) { if (!val) throw new Error("AssertionError: false == true"); @@ -102,12 +102,12 @@ Planner=function(){ }; this.persistable=function(){ - return deepcopy(subjects); + return _.cloneDeep(subjects); }; this.frompersistable=function(subj){ if(subj.isPlannerObject===true) //they persisted the whole object ._. subjects=subj.persistable(); - else subjects=deepcopy(subj); + else subjects=_.cloneDeep(subj); }; this.availableTimeConvert=function(code){ @@ -120,7 +120,7 @@ Planner=function(){ // on that day of the plan region. //`today` is a Date which the planner uses as "today" this.plan=function(items,available,today){ - items=deepcopy(items); //we'll modify them for our own needs + items=_.cloneDeep(items); //we'll modify them for our own needs var ndays=available.length; var needed=new Array(ndays); var i; @@ -178,7 +178,7 @@ Planner=function(){ - if(arguments.length==1)subjects=deepcopy(arguments[0]); //from a persist source + if(arguments.length==1)subjects=_.cloneDeep(arguments[0]); //from a persist source }; From 8adfb6a9a9342b43eb4b46984aa81d3705da8bde Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 28 Aug 2015 14:28:22 +0200 Subject: [PATCH 10/18] Working planner algorithm with fixing capability in case of non-fitting stuff The test case in testtest.js is quite an aggressive one; stuff doesn't fit AT ALL. Put the [1,9] testcase at 4 days for some relief, or the [1,2] case at 3 days, for example. --- packages/planner/planner.js | 81 +++++++++++++++++++++++++++--------- packages/planner/testtest.js | 22 ++++++---- 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 143d2458..71a262af 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -4,7 +4,8 @@ * @module planner */ -var _ = _ || require('lodash'); +require("js-object-clone"); +var util=require("util"); var assert = function (val) { if (!val) throw new Error("AssertionError: false == true"); @@ -95,19 +96,19 @@ Planner=function(){ this.estimate=function(hwdesc){ var subj,loc; - //assert(hwdesc instanceof HomeworkDescription); + assert(hwdesc instanceof HomeworkDescription); return sum(hwdesc.location.map(function(loc){ return estimateSingle(HomeworkDescription(hwdesc.subject,[loc])); })); }; this.persistable=function(){ - return _.cloneDeep(subjects); + return Object.clone(subjects,true); }; this.frompersistable=function(subj){ if(subj.isPlannerObject===true) //they persisted the whole object ._. subjects=subj.persistable(); - else subjects=_.cloneDeep(subj); + else subjects=Object.clone(subj,true); }; this.availableTimeConvert=function(code){ @@ -118,14 +119,12 @@ Planner=function(){ //`items` is an Array of HomeworkDescriptions //`available` is an Array of ints, specifying how much time (in the time unit) there is available // on that day of the plan region. - //`today` is a Date which the planner uses as "today" + //`today` is a Date which the planner uses as "today"; will be rounded to start of day this.plan=function(items,available,today){ - items=_.cloneDeep(items); //we'll modify them for our own needs - var ndays=available.length; - var needed=new Array(ndays); + items=Object.clone(items,true); //we'll modify them for our own needs + var needed=new Array(items.length); var i; - for(i=0;i planned on day "+day); + schedule[day].push(it.item); + daylength[day]+=it.needed; + } else { //the item didn't fit anywhere + console.log(" -> no fit found; distributing"); + total=0; + fractions=[]; + firstUsedDay=-1; + for(day=0;day=it.needed)break; + } + if(total distributing left "+(it.needed-total)+" excess; putting on first used day"); + if(firstUsedDay==-1){ //HELP we didn't plan ANYTHING yet at all + console.log(" -> NO FIRST USED DAY, so just plugging everything on day 0"); + schedule[0].push(it.item); + daylength[0]+=it.needed; + continue; //skip all the fraction stuff + } else { + firstDayItem=schedule[firstUsedDay][schedule[firstUsedDay].length-1]; + firstDayItem.timepart+=it.needed-total; + firstDayItem.timefraction=firstDayItem.timepart/it.needed; + } + total=it.needed; + } + //NOT REACHED IF SHIT WAS JUST THROWN ON DAY 0 DUE TO continue ABOVE + fractions.sort(function(a,b){a.timepart>b.timepart;}); //descending sort on timepart + lastDayItem=schedule[lastUsedDay][schedule[lastUsedDay].length-1]; + while(fractions[0].timepart Date: Fri, 28 Aug 2015 20:25:18 +0200 Subject: [PATCH 11/18] time{part,fraction}, HD.id, (new) HD, min time/day --- packages/planner/planner.js | 29 ++++++++++++++++++++++++----- packages/planner/testtest.js | 7 ++++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 71a262af..39fda883 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -7,6 +7,10 @@ require("js-object-clone"); var util=require("util"); + +var MIN_TIME_TASK_DAY=450; //minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) + + var assert = function (val) { if (!val) throw new Error("AssertionError: false == true"); }; @@ -16,7 +20,12 @@ function subjectGrade(subjid){ } HomeworkDescription=function(){ - if(!(this instanceof HomeworkDescription))return new HomeworkDescription(arguments[0],arguments[1],arguments[2]); + if(!(this instanceof HomeworkDescription)){ + return new (Function.prototype.bind.apply( + HomeworkDescription, + [null].concat(Array.prototype.slice.call(arguments)) + )); + } //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type // and unique and fixed, i.e. there is only one identifier per subject and only one subject per identifier. @@ -30,11 +39,14 @@ HomeworkDescription=function(){ //In general, anything that can be expressed in a sequence of integers that specifies the location. // (Actually, they should be index paths — think NSIndexPath) //The `location` property contains an array of those, because homework can be multiple exercises, for example. - //Please make the array contiguous, though; don't mix indexing conventions! (!) (!!) + //Per subject, please use just one index convention. If you need to, add ones where you don't have entries. this.location=arguments.length>1?arguments[1]:[]; //A Date indicating when this homework is due this.duedate=arguments.length>2?arguments[2]:null; + + //Some id that the outside world can decide on + this.id=arguments.length>3?arguments[3]:null; }; Planner=function(){ @@ -163,7 +175,10 @@ Planner=function(){ } if(day planned on day "+day); - schedule[day].push(it.item); + itemcopy=Object.clone(it.item,true); + itemcopy.timepart=it.needed; + itemcopy.timefraction=1; + schedule[day].push(itemcopy); daylength[day]+=it.needed; } else { //the item didn't fit anywhere console.log(" -> no fit found; distributing"); @@ -173,6 +188,7 @@ Planner=function(){ for(day=0;day distributing left "+(it.needed-total)+" excess; putting on first used day"); if(firstUsedDay==-1){ //HELP we didn't plan ANYTHING yet at all console.log(" -> NO FIRST USED DAY, so just plugging everything on day 0"); - schedule[0].push(it.item); + itemcopy=Object.clone(it.item,true); + itemcopy.timepart=it.needed; + itemcopy.timefraction=1; + schedule[0].push(itemcopy); daylength[0]+=it.needed; continue; //skip all the fraction stuff } else { @@ -214,7 +233,7 @@ Planner=function(){ var ret={}; for(i=0;i Date: Sat, 29 Aug 2015 10:57:33 +0200 Subject: [PATCH 12/18] Better input interface to Planner::plan --- packages/planner/planner.js | 28 ++++++++++++++++++++-------- packages/planner/testtest.js | 12 +++++++----- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 39fda883..78e6af4c 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -129,18 +129,28 @@ Planner=function(){ }; //`items` is an Array of HomeworkDescriptions - //`available` is an Array of ints, specifying how much time (in the time unit) there is available - // on that day of the plan region. + //`availableFn` is a Function(Date) returning int, specifying the code for how much time (in the + // time unit) there is available on the given day //`today` is a Date which the planner uses as "today"; will be rounded to start of day - this.plan=function(items,available,today){ + this.plan=function(items,availableFn,today){ + today=startOfDay(today); + var availableCache=[]; + var available=(function(day){ + var targetday; + if(day<0)assert(false); + while(day>=availableCache.length){ + targetday=addDays(today,availableCache.length); + availableCache.push(this.availableTimeConvert(availableFn(targetday))); + } + return availableCache[day]; + }).bind(this); items=Object.clone(items,true); //we'll modify them for our own needs var needed=new Array(items.length); var i; for(i=0;i planned on day "+day); @@ -187,7 +199,7 @@ Planner=function(){ firstUsedDay=-1; for(day=0;dayb.timepart;}); //descending sort on timepart lastDayItem=schedule[lastUsedDay][schedule[lastUsedDay].length-1]; - while(fractions[0].timepart Date: Sat, 29 Aug 2015 15:51:06 +0200 Subject: [PATCH 13/18] planner: fix meteor stuff and npm dependencies --- packages/planner/package.js | 11 +++++++---- packages/planner/package.json | 2 +- packages/planner/planner.js | 12 ++++-------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/planner/package.js b/packages/planner/package.js index e8731b52..5c7e76ed 100644 --- a/packages/planner/package.js +++ b/packages/planner/package.js @@ -10,14 +10,17 @@ Package.describe({ documentation: 'README.md', }); +Npm.depends({ + 'js-object-clone': '0.4.2', +}); + Package.onUse(function(api) { api.versionsFrom('1.1.0.2'); - api.use('erasaur:meteor-lodash'); - api.addFiles('planner.js'); + api.addFiles('planner.js', 'server'); - api.export('HomeworkDescription'); - api.export('Planner'); + api.export('HomeworkDescription', 'server'); + api.export('Planner', 'server'); }); Package.onTest(function(api) { diff --git a/packages/planner/package.json b/packages/planner/package.json index ca6f6bf2..a9f54aee 100644 --- a/packages/planner/package.json +++ b/packages/planner/package.json @@ -9,6 +9,6 @@ "author": "simply (http://www.simplyApps.nl/)", "license": "UNLICENSED", "dependencies": { - "lodash": "^3.10.1" + "js-object-clone": "^0.4.2" } } diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 78e6af4c..c926888c 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -4,16 +4,12 @@ * @module planner */ +var require = require || Npm.require; require("js-object-clone"); -var util=require("util"); +var util = require("util"); +var assert = require('assert'); - -var MIN_TIME_TASK_DAY=450; //minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) - - -var assert = function (val) { - if (!val) throw new Error("AssertionError: false == true"); -}; +var MIN_TIME_TASK_DAY = 450; // minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) function subjectGrade(subjid){ return Math.random()*9+1; //TODO:: Get average grade of student for this subject From 9abf7c82f1553c66af1207ef33330250ad941635 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Sat, 29 Aug 2015 21:17:33 +0200 Subject: [PATCH 14/18] Fix estimation and planning for unknown subjects When we haven't learnt anything about a subject, the engine falls back to average grade. This didn't work. This works now. --- packages/planner/planner.js | 29 +++++++++++++---------------- packages/planner/testtest.js | 3 ++- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index c926888c..5337789c 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -11,10 +11,6 @@ var assert = require('assert'); var MIN_TIME_TASK_DAY = 450; // minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) -function subjectGrade(subjid){ - return Math.random()*9+1; //TODO:: Get average grade of student for this subject -} - HomeworkDescription=function(){ if(!(this instanceof HomeworkDescription)){ return new (Function.prototype.bind.apply( @@ -78,16 +74,16 @@ Planner=function(){ } }; - this.generalSubjectEstimate=function(subjid){ - var grade=subjectGrade(subjid); - return 3600*3/2-3600*grade; + this.generalSubjectEstimate=function(subjid,gradeFn){ + var grade=gradeFn(subjid); + return 3600*3/2-3600*grade/10; }; - function estimateSingle(hwdesc){ + this.estimateSingle=function(hwdesc,gradeFn){ assert(hwdesc instanceof HomeworkDescription); assert(hwdesc.location.length==1); if(!subjects[hwdesc.subject]){ - return this.generalSubjectEstimate(hwdesc.subject); + return this.generalSubjectEstimate(hwdesc.subject,gradeFn); } var i,itemref=subjects[hwdesc.subject]; for(i=0;i=availableCache.length){ targetday=addDays(today,availableCache.length); - availableCache.push(this.availableTimeConvert(availableFn(targetday))); + availableCache.push(availableFn(targetday)); } return availableCache[day]; }).bind(this); @@ -144,7 +141,7 @@ Planner=function(){ var needed=new Array(items.length); var i; for(i=0;i Date: Tue, 1 Sep 2015 15:12:45 +0200 Subject: [PATCH 15/18] small code cleanup --- packages/planner/planner.js | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 5337789c..6fdf10db 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -274,26 +274,9 @@ function sum(arr){ return sum; } -if(typeof Meteor=="undefined"){ - module.exports={ - HomeworkDescription:HomeworkDescription, - Planner:Planner +if (module !== undefined) { + module.exports= { + HomeworkDescription: HomeworkDescription, + Planner: Planner, }; } - -/* -REQ=require("./planner") -H=REQ.HomeworkDescription -P=REQ.Planner -function hh(s,l){var h=new H;h.subject=s;h.location=l;return h;} -function inspect(o){console.log(util.inspect(o,{depth:8}));} -function startOfDay(date){return new Date(date.getFullYear(),date.getMonth(),date.getDate());} -function addDays(date,ndays){return new Date(date.getTime()+ndays*24*3600*1000);} -p=new P -p.learn(hh("ne",[[1,1],[1,2]]),100) -p.learn(hh("ne",[[1,5]]),40) -inspect(p.persistable()) -p.estimate(hh("ne",[[1,5]])) -p.estimate(hh("ne",[[1,4]])) -p.plan([H("ne",[[1,2]],addDays(startOfDay(new Date),2)),H("ne",[[1,1],[1,5]],addDays(startOfDay(new Date),1))],[1,1],new Date) -*/ From 324ac671e6f28406d50e302778d8a0bc2da3673e Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Tue, 1 Sep 2015 22:32:39 +0200 Subject: [PATCH 16/18] jsdoc all the stuff --- packages/planner/planner.js | 128 ++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 21 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 6fdf10db..b43a9d0c 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -11,6 +11,14 @@ var assert = require('assert'); var MIN_TIME_TASK_DAY = 450; // minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) +/** + * @class HomeworkDescription + * @constructor + * @param {any} subject Must be primitive, unique and fixed + * @param {int[][]} locations + * @param {Date} duedate + * @param {any} id + */ HomeworkDescription=function(){ if(!(this instanceof HomeworkDescription)){ return new (Function.prototype.bind.apply( @@ -19,38 +27,76 @@ HomeworkDescription=function(){ )); } - //A unique identifier for a subject. Can be pretty much anything, lest it's a primitive type - // and unique and fixed, i.e. there is only one identifier per subject and only one subject per identifier. + /** + * A unique identifier for a subject. Can be pretty much anything, lest it's + * a primitive type and unique and fixed, i.e. there is only one identifier + * per subject and only one subject per identifier. + * + * @property subject + * @type any + */ this.subject=arguments.length>0?arguments[0]:null; - //Items in `location` can be multiple things, e.g. - //- [chapter,paragraph,exercise] - //- [bookid,page,exercise] - //- [chapter,exercise] - //- [bookid,page] - //In general, anything that can be expressed in a sequence of integers that specifies the location. - // (Actually, they should be index paths — think NSIndexPath) - //The `location` property contains an array of those, because homework can be multiple exercises, for example. - //Per subject, please use just one index convention. If you need to, add ones where you don't have entries. + /** + * Items in `location` can be multiple things, e.g. + * - [chapter,paragraph,exercise] + * - [bookid,page,exercise] + * - [chapter,exercise] + * - [bookid,page] + * + * In general, anything that can be expressed in a sequence of integers that + * specifies the location. (Actually, they should be index paths — think + * NSIndexPath) The `location` property contains an array of those, because + * homework can be multiple exercises, for example. Per subject, please use + * just one index convention. If you need to, add ones where you don't have + * entries. + * + * @property location + * @type int[][] + */ this.location=arguments.length>1?arguments[1]:[]; - //A Date indicating when this homework is due + /** + * A Date indicating when this homework is due + * @prototype duedate + * @type Date + */ this.duedate=arguments.length>2?arguments[2]:null; - //Some id that the outside world can decide on + /** + * Some id that the outside world can decide on + * @property id + * @type any + */ this.id=arguments.length>3?arguments[3]:null; }; +/** + * @class Planner + * @constructor + * @param {Object} [persisted] Result from `Planner::persistable`. + */ Planner=function(){ if(!(this instanceof Planner))return new Planner(arguments[0]); + /** + * @property isPlannerObject + * @type Boolean + * @final + * @default true + */ this.isPlannerObject=true; //PREV: Object[subject id][location index path item][value of the loc. idxp. item][samples of time taken] //Object[subject id][loc item 0][loc item 1]...[loc item n] = time taken for that index path var subjects={}; //The Cache - //`timetaken` in any unit you find convenient; but please be consistent. Suggestion: seconds. + /** + * Learn. + * @method learn + * @param {HomeworkDescription} hwdesc The `HomeworkDescription` that was done. + * @param {Number} timetaken Number in time unit that specifies how long the given description took. + */ this.learn=function(hwdesc,timetaken){ var i,j,idx,subj,loc; assert(hwdesc instanceof HomeworkDescription); @@ -74,12 +120,26 @@ Planner=function(){ } }; + /** + * @method generalSubjectEstimate + * @param {any} subjid + * @param {Function} gradeFn + * @return {Number} + */ this.generalSubjectEstimate=function(subjid,gradeFn){ var grade=gradeFn(subjid); return 3600*3/2-3600*grade/10; }; - this.estimateSingle=function(hwdesc,gradeFn){ + /** + * Guesses the time needed for the given `hwdesc` with a single location. + * @private + * @method _estimateSingle + * @param {HomeworkDescription} hwdesc + * @param {Function} gradeFn + * @return {Number} + */ + this._estimateSingle=function(hwdesc,gradeFn){ assert(hwdesc instanceof HomeworkDescription); assert(hwdesc.location.length==1); if(!subjects[hwdesc.subject]){ @@ -98,33 +158,59 @@ Planner=function(){ return rms(timearr); }; + /** + * Guesses the time needed for the given `hwdesc`. + * @method estimate + * @param {HomeworkDescription} hwdesc + * @param {Function} gradeFn + * @return {Number} + */ this.estimate=function(hwdesc,gradeFn){ var subj,loc; assert(hwdesc instanceof HomeworkDescription); return sum(hwdesc.location.map(function(loc){ - return this.estimateSingle(HomeworkDescription(hwdesc.subject,[loc]),gradeFn); + return this._estimateSingle(HomeworkDescription(hwdesc.subject,[loc]),gradeFn); }.bind(this))); }; + /** + * Converts the current Planner to a persistable object. + * @method persistable + * @return {Object} + */ this.persistable=function(){ return Object.clone(subjects,true); }; + + /** + * Loads in an object created by `Planner::persistable`. + * @method frompersistable + * @param {Object} subj The object created by `Planner:persistable` to load. + */ this.frompersistable=function(subj){ if(subj.isPlannerObject===true) //they persisted the whole object ._. subjects=subj.persistable(); else subjects=Object.clone(subj,true); }; + /** + * @method availableTimeConvert + * @param {Number} code + * @return Number + */ this.availableTimeConvert=function(code){ // return [0,30*60,90*60,180*60][code]; return (15*code*code+15*code)*60; }; - //`items` is an Array of HomeworkDescriptions - //`availableFn` is a Function(Date) returning int, specifying the code for how much time (in the - // time unit) there is available on the given day - //`today` is a Date which the planner uses as "today"; will be rounded to start of day - //`gradeFn` is a Function(String) taking a subject identifier and returning the average grade of the student for that subject + /** + * @method plan + * @param {HomeworkDescription[]} items + * @param {Function(Date) Number} availableFn Specifies the code for how much time (in time unit) there is available for the given day. + * @param {Date} today The date which the planner uses as "today"; will be rounded to start of day. + * @param {Function(String) Number} gradeFn Gets a subject identifier and must return the average grade of the student for that subject. + * @return {Object} The schedule. + */ this.plan=function(items,availableFn,today,gradeFn){ today=startOfDay(today); var availableCache=[]; From 3a8cd9c77a3b8afd46c6e0a2fe31371983b486b9 Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Tue, 1 Sep 2015 22:37:37 +0200 Subject: [PATCH 17/18] :bomb: console.log --- packages/planner/planner.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index b43a9d0c..3e37f79c 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -11,6 +11,10 @@ var assert = require('assert'); var MIN_TIME_TASK_DAY = 450; // minimum of 7.5 minutes for one task on a day (except if expected time is <7.5 min) +var log = function () { + //console.log.apply(console, arguments); +}; + /** * @class HomeworkDescription * @constructor @@ -229,7 +233,7 @@ Planner=function(){ for(i=0;i planned on day "+day); + log(" -> planned on day "+day); itemcopy=Object.clone(it.item,true); itemcopy.timepart=it.needed; itemcopy.timefraction=1; schedule[day].push(itemcopy); daylength[day]+=it.needed; } else { //the item didn't fit anywhere - console.log(" -> no fit found; distributing"); + log(" -> no fit found; distributing"); total=0; fractions=[]; firstUsedDay=-1; @@ -291,9 +295,9 @@ Planner=function(){ if(total>=it.needed)break; } if(total distributing left "+(it.needed-total)+" excess; putting on first used day"); + log(" -> distributing left "+(it.needed-total)+" excess; putting on first used day"); if(firstUsedDay==-1){ //HELP we didn't plan ANYTHING yet at all - console.log(" -> NO FIRST USED DAY, so just plugging everything on day 0"); + log(" -> NO FIRST USED DAY, so just plugging everything on day 0"); itemcopy=Object.clone(it.item,true); itemcopy.timepart=it.needed; itemcopy.timefraction=1; @@ -320,7 +324,7 @@ Planner=function(){ } } } - console.log("daylength="+util.inspect(daylength)); + log("daylength="+util.inspect(daylength)); var ret={}; for(i=0;i Date: Sun, 20 Sep 2015 01:06:53 +0200 Subject: [PATCH 18/18] don't try to use `undefined` or `null` as Planner::ctor argument as persistable. This doesn't break anything, right, @tomsmeding? --- packages/planner/planner.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/planner/planner.js b/packages/planner/planner.js index 3e37f79c..46ea2b00 100644 --- a/packages/planner/planner.js +++ b/packages/planner/planner.js @@ -80,8 +80,10 @@ HomeworkDescription=function(){ * @constructor * @param {Object} [persisted] Result from `Planner::persistable`. */ -Planner=function(){ - if(!(this instanceof Planner))return new Planner(arguments[0]); +Planner = function (persisted) { + if (!(this instanceof Planner)) { + return new Planner(persisted); + } /** * @property isPlannerObject @@ -333,9 +335,10 @@ Planner=function(){ return ret; }; - - - if(arguments.length==1)subjects=Object.clone(arguments[0],true); //from a persist source + if (persisted != null) { + // from a persist source + subjects = Object.clone(persistable, true); + } };