Repository: yanhaijing/data.js Branch: master Commit: c3a9c21c0e96 Files: 29 Total size: 601.9 KB Directory structure: gitextract_5lrr4bk9/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── MIT-LICENSE.txt ├── README.md ├── bower.json ├── data.js ├── demo/ │ ├── basic.html │ ├── js/ │ │ └── require.js │ ├── node/ │ │ ├── a.js │ │ └── main.js │ └── requirejs.html ├── doc/ │ └── api.md ├── gulpfile.js ├── lib/ │ └── es5-shim.js ├── package.json └── test/ ├── browser/ │ ├── expect.js │ ├── index.html │ ├── mocha.css │ └── mocha.js ├── get-clone-error.html ├── old/ │ ├── qunit/ │ │ ├── qunit-1.15.0.css │ │ └── qunit-1.15.0.js │ ├── test.html │ └── test.js └── test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: ['https://yanhaijing.com/mywallet/'] ================================================ FILE: .gitignore ================================================ .project #npm node_modules npm-debug.log #PhpStorm / WebStorm .idea ================================================ FILE: .jshintrc ================================================ { "curly": true, "eqeqeq": true, "immed": true, "latedef": true, "newcap": true, "noarg": true, "sub": true, "undef": false, "boss": true, "eqnull": true, "node": true } ================================================ FILE: .npmignore ================================================ demo doc lib test node_modules .gitignore .jshintrc .travis.yml bower.json gulpfile.js CHANGELOG.md ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - "8" - "6" - "4" - "0.12" - "0.10" before_script: - npm install -g mocha@~2.3.4 ================================================ FILE: CHANGELOG.md ================================================ #0.3.0 / 2016-1-22 - 优化程序性能 - 单元测试工具切换到mocha,更全面的测试,更全面的平台测试 - fix 某些数据类型的type报错问题 - fix #14 get接口获取的深度clone数据,会获取到原型链上的数据 #0.2.1 / 2014-11-17 - 修复noConflict接口逻辑错误 #0.2.0 / 2014-10-23 - 添加消息下发功能 - 传入值为对象时,添加消息通知功能 - add/update/delete 消息互斥 #0.1.0 / 2014-10-22 - 数据中心 - 消息通知 ================================================ FILE: MIT-LICENSE.txt ================================================ Copyright (C) 2013 yanhaijing 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. ================================================ FILE: README.md ================================================ # [data.js](https://github.com/yanhaijing/data.js) [![Build Status](https://travis-ci.org/yanhaijing/data.js.svg?branch=master)](https://travis-ci.org/yanhaijing/data.js) [![license](http://img.shields.io/npm/l/express.svg)](https://github.com/yanhaijing/data.js/blob/master/MIT-LICENSE.txt) [![release](https://img.shields.io/badge/release-v0.3.0-orange.svg)](https://github.com/yanhaijing/data.js/releases/tag/v0.3.0) data.js 是带有消息通知的数据中心,我称其为会说话的数据。旨在让编程变得简单,世界变得美好。 ## 特性 1. 全局数据中心,可以用来存放数据,在不同程序中共享。 2. 将程序的耦合度,变为数据耦合,采用隐式调用风格,发挥js事件风格。 ## 兼容性 - Node 0.10+ - Safari 6+ (Mac) - iOS 5+ Safari - Chrome 23+ (Windows, Mac, Android, iOS, Linux, Chrome OS) - Firefox 4+ (Windows, Mac, Android, Linux) - Internet Explorer 6+ (Windows, Windows Phone) - Opera 10+ (Windows, linux, Android) ## 下载 第一种方法,推荐使用npm安装和更新 $ npm install --save data_js 第二种方法,或者你也可以在GitHub,下载源文件或压缩包 ## 如何使用? 支持全局变量、AMD、commonjs、es6等模块系统 ### 传统用法 ### AMD require(['data'], function (Data) { Data }); ### commonjs var Data = require('data_js') ## 快速上手 Data常用接口只有三个,非常简单: ```javascript Data.sub('set', 'a', function (e) {console.log(e.data)});//订阅消息,当a被设置时,会派发消息 Data.set('a', 1);//存入数据 Data.get('a');//读取数据 ``` 更多例子,请见目录下的[demo](demo)目录。 ## 文档 [API](doc/api.md) ## 质量保证 data.js的代码运行于ecmascript严格模式下,jshint验证,完整的单元测试,并使用travis保证。测试代码见test目录下。 ## 性能 data.js的存入和取出,都是对数据的一次深拷贝,同时还要解析数据的键和派发消息,所以性能会有一些损失,但不涉及大批量循环存取不会遇到性能问题。 - [get接口性能](http://jsperf.com/yanhaijing-data-js-get) - [set接口性能](http://jsperf.com/yanhaijing-data-js-set) ## 贡献指南 如果你想为data.js贡献代码,请采用fork + pull request 方式,并在发起pr前先将master上超前的代码rebase到自己的分支上。 在目录运行如下命令,完成验证测试编译过程,确保无误: $ npm install -g mocha@~2.3.4 # 安装mocha $ npm install # 安装依赖 $ mocha test # 运行测试代码 $ npm install -g gulp@~3.9.0 # 安装gulp # gulp lint # 验证代码风格 ### 发布npm $ npm publish ## 贡献者 - [yanhaijing](http://yanhaijing.com "yanhaijing's Blog") - [Jerry Zou](https://github.com/zry656565) ## 报告问题 - [Issues](https://github.com/yanhaijing/data.js/issues "报告问题") ## 更新日志 [更新日志](CHANGELOG.md) ================================================ FILE: bower.json ================================================ { "name": "data.js", "main": "data.js", "version": "0.3.0", "homepage": "https://github.com/yanhaijing/data.js", "authors": [ "yanhaijing " ], "description": "data.js 是带有消息通知的数据中心,我称其为会说话的数据。旨在让编程变得简单,世界变得美好。", "keywords": [ "data.js", "data" ], "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ], "moduleType": [ "amd", "globals", "node" ] } ================================================ FILE: data.js ================================================ /*! * data.js v0.3.0 (https://github.com/yanhaijing/data.js) * Copyright 2013 yanhaijing. All Rights Reserved * Licensed under MIT (https://github.com/yanhaijing/data.js/blob/master/MIT-LICENSE.txt) */ (function (root, factory) { var Data = factory(root); if ( typeof define === 'function' && define.amd) { // AMD define('data', function() { return Data; }); } else if ( typeof exports === 'object') { // Node.js module.exports = Data; } else { // Browser globals var _Data = root.Data; Data.noConflict = function () { if (root.Data === Data) { root.Data = _Data; } return Data; }; root.Data = Data; } }(this, function (root) { 'use strict'; var slice = [].slice; var obj = {}; var toString = obj.toString; var hasOwn = obj.hasOwnProperty; var euid = 0; function getType(x) { if(x === null){ return 'null'; } var t= typeof x; if(t !== 'object'){ return t; } var c; // 某些类型会报错 try { c = toString.call(x).slice(8, -1).toLowerCase(); } catch(exp) { return 'unknow'; } if(c !== 'object'){ return c; } if(x.constructor===Object){ return c; } return 'unknow'; } function isFn(fn) { return getType(fn) === 'function'; } function isArr(arr) { return Array.isArray ? Array.isArray(arr) : getType(arr) === 'array'; } function isObj(obj) { return getType(obj) === 'object'; } function extendDeep() { var target = arguments[0] || {}; var arrs = slice.call(arguments, 1); var len = arrs.length; var copyIsArr; var clone; for (var i = 0; i < len; i++) { var arr = arrs[i]; for (var name in arr) { var src = target[name]; var copy = arr[name]; //避免无限循环 if (target === copy) { continue; } // 非可枚举属性 if (!hasOwn.call(arr, name)) { continue; } if (copy && (isObj(copy) || (copyIsArr = isArr(copy)))) { if (copyIsArr) { copyIsArr = false; clone = src && isArr(src) ? src : []; } else { clone = src && isObj(src) ? src : {}; } target[ name ] = extendDeep(clone, copy); } else if (typeof copy !== 'undefined'){ target[name] = copy; } } } return target; } function pub(events, event, key, data) { events = events[event][key]; if (isObj(events)) { for (var name in events) { if (events.hasOwnProperty(name)) { events[name]({ type: event, key: key, data: data }); } } } } function extendData(key, events, context, src) { var nkey; for (var name in src) { var ctx = context[name]; var copy = src[name]; var copyIsArr; var isadd = false; var isdelete = false; //避免无限循环 if (context === copy) { continue; } // 非可枚举属性 if (!hasOwn.call(src, name)) { continue; } if (typeof copy === 'undefined') { isdelete = true; } else if (typeof context[name] === 'undefined') { isadd = true; } nkey = (typeof key === 'undefined' ? '' : (key + '.')) + name; if (copy && (isObj(copy) || (copyIsArr = isArr(copy)))) { if (copyIsArr) { copyIsArr = false; context[name] = ctx && isArr(ctx) ? ctx : []; } else { context[name] = ctx && isObj(ctx) ? ctx : {}; } context[name] = extendData(nkey, events, context[name], copy); } else { context[name] = copy; } pub(events, 'set', nkey, context[name]); if (isdelete) { pub(events, 'delete', nkey, context[name]); } else if (isadd) { pub(events, 'add', nkey, context[name]); } else { pub(events, 'update', nkey, context[name]); } } return context; } function parseKey(key) { return key.split('.'); } function cloneDeep(src) { if (isObj(src)) { return extendDeep({}, src); } if (isArr(src)){ return extendDeep([], src); } return src; } //Data构造函数 var Data = function () { if (!(this instanceof Data)) { return new Data(); } this._init(); }; //扩展Data原型 extendDeep(Data.prototype, { _init: function () { this._context = {}; this._events = { 'set': {}, 'delete': {}, 'add': {}, 'update': {} }; }, set: function (key, val) { var ctx = this._context; if (typeof key !== 'string') { return false; } var keys = parseKey(key); var len = keys.length; var i = 0; var name; var src; //键值为 单个的情况 if (len < 2) { src = {}; src[key] = val; extendData(undefined, this._events, ctx, src); return true; } //切换到对应上下文 for (; i < len - 1; i++) { name = keys[i]; //若不存在对应上下文自动创建 if (!isArr(ctx[name]) && !isObj(ctx[name])) { //删除操作不存在对应值时,提前退出 if (typeof val === 'undefined') { return false; } //若键值为数组则新建数组,否则新建对象 ctx[name] = isNaN(Number(name)) ? {} : []; } ctx = ctx[name]; } name = keys.pop(); src = isArr(ctx) ? [] : {}; src[name] = val; ctx = extendData(keys.join('.'), this._events, ctx, src); return true; }, get: function (key) { //key不为字符串返回undefined if (typeof key !== 'string') { return undefined; } var keys = parseKey(key); var len = keys.length; var i = 0; var ctx = this._context; var name; for (; i < len; i++) { name = keys[i]; ctx = ctx[name]; if (typeof ctx === 'undefined' || ctx === null) { return ctx; } } //返回数据的副本 return cloneDeep(ctx); }, has: function (key) { return typeof this.get(key) === 'undefined' ? false : true; }, sub: function (type, key, callback) { //参数不合法 if (typeof type !== 'string' || typeof key !== 'string' || !isFn(callback)) { return -1; } //不支持的事件 if (!(type in this._events)) { return -2; } var events = this._events[type]; events[key] = events[key] || {}; events[key][euid++] = callback; return euid - 1; }, unsub: function (type, key, id ) { //参数不合法 if (typeof type !== 'string' || typeof key !== 'string') { return false; } //不支持的事件 if (!(type in this._events)) { return false; } var events = this._events[type]; if (!isObj(events[key])) { return false; } if (typeof id !== 'number') { delete events[key]; return true; } delete events[key][id]; return true; }, _clear: function () { return this._init(); } }); //新建默认数据中心 var data = new Data(); //扩展Data接口 extendDeep(Data, { version: '0.3.0', has: function (key) { return data.has(key); }, get: function (key) { return data.get(key); }, set: function (key, val) { return data.set(key, val); }, sub: function (type, key, callback) { return data.sub(type, key, callback); }, unsub: function (type, key, id) { return data.unsub(type, key, id); }, _clear: function () { return data._clear(); } }); return Data;//return Data })); ================================================ FILE: demo/basic.html ================================================ 浏览器中使用 ================================================ FILE: demo/js/require.js ================================================ /** vim: et:ts=4:sw=4:sts=4 * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ //Not using strict: uneven strict support in browsers, #392, and causes //problems with requirejs.exec()/transpiler plugins that may not be strict. /*jslint regexp: true, nomen: true, sloppy: true */ /*global window, navigator, document, importScripts, setTimeout, opera */ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, version = '2.1.14', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, currDirRegExp = /^\.\//, op = Object.prototype, ostring = op.toString, hasOwn = op.hasOwnProperty, ap = Array.prototype, apsp = ap.splice, isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), isWebWorker = !isBrowser && typeof importScripts !== 'undefined', //PS3 indicates loaded and complete, but need to wait for complete //specifically. Sequence is 'loading', 'loaded', execution, // then 'complete'. The UA check is unfortunate, but not sure how //to feature test w/o causing perf issues. readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? /^complete$/ : /^(complete|loaded)$/, defContextName = '_', //Oh the tragedy, detecting opera. See the usage of isOpera for reason. isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', contexts = {}, cfg = {}, globalDefQueue = [], useInteractive = false; function isFunction(it) { return ostring.call(it) === '[object Function]'; } function isArray(it) { return ostring.call(it) === '[object Array]'; } /** * Helper function for iterating over an array. If the func returns * a true value, it will break out of the loop. */ function each(ary, func) { if (ary) { var i; for (i = 0; i < ary.length; i += 1) { if (ary[i] && func(ary[i], i, ary)) { break; } } } } /** * Helper function for iterating over an array backwards. If the func * returns a true value, it will break out of the loop. */ function eachReverse(ary, func) { if (ary) { var i; for (i = ary.length - 1; i > -1; i -= 1) { if (ary[i] && func(ary[i], i, ary)) { break; } } } } function hasProp(obj, prop) { return hasOwn.call(obj, prop); } function getOwn(obj, prop) { return hasProp(obj, prop) && obj[prop]; } /** * Cycles over properties in an object and calls a function for each * property value. If the function returns a truthy value, then the * iteration is stopped. */ function eachProp(obj, func) { var prop; for (prop in obj) { if (hasProp(obj, prop)) { if (func(obj[prop], prop)) { break; } } } } /** * Simple function to mix in properties from source into target, * but only if target does not already have a property of the same name. */ function mixin(target, source, force, deepStringMixin) { if (source) { eachProp(source, function (value, prop) { if (force || !hasProp(target, prop)) { if (deepStringMixin && typeof value === 'object' && value && !isArray(value) && !isFunction(value) && !(value instanceof RegExp)) { if (!target[prop]) { target[prop] = {}; } mixin(target[prop], value, force, deepStringMixin); } else { target[prop] = value; } } }); } return target; } //Similar to Function.prototype.bind, but the 'this' object is specified //first, since it is easier to read/figure out what 'this' will be. function bind(obj, fn) { return function () { return fn.apply(obj, arguments); }; } function scripts() { return document.getElementsByTagName('script'); } function defaultOnError(err) { throw err; } //Allow getting a global that is expressed in //dot notation, like 'a.b.c'. function getGlobal(value) { if (!value) { return value; } var g = global; each(value.split('.'), function (part) { g = g[part]; }); return g; } /** * Constructs an error with a pointer to an URL with more information. * @param {String} id the error ID that maps to an ID on a web page. * @param {String} message human readable error. * @param {Error} [err] the original error, if there is one. * * @returns {Error} */ function makeError(id, msg, err, requireModules) { var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); e.requireType = id; e.requireModules = requireModules; if (err) { e.originalError = err; } return e; } if (typeof define !== 'undefined') { //If a define is already in play via another AMD loader, //do not overwrite. return; } if (typeof requirejs !== 'undefined') { if (isFunction(requirejs)) { //Do not overwrite an existing requirejs instance. return; } cfg = requirejs; requirejs = undefined; } //Allow for a require config object if (typeof require !== 'undefined' && !isFunction(require)) { //assume it is a config object. cfg = require; require = undefined; } function newContext(contextName) { var inCheckLoaded, Module, context, handlers, checkLoadedTimeoutId, config = { //Defaults. Do not set a default for map //config to speed up normalize(), which //will run faster if there is no default. waitSeconds: 7, baseUrl: './', paths: {}, bundles: {}, pkgs: {}, shim: {}, config: {} }, registry = {}, //registry of just enabled modules, to speed //cycle breaking code when lots of modules //are registered, but not activated. enabledRegistry = {}, undefEvents = {}, defQueue = [], defined = {}, urlFetched = {}, bundlesMap = {}, requireCounter = 1, unnormalizedCounter = 1; /** * Trims the . and .. from an array of path segments. * It will keep a leading path segment if a .. will become * the first path segment, to help with module name lookups, * which act like paths, but can be remapped. But the end result, * all paths that use this function should look normalized. * NOTE: this method MODIFIES the input array. * @param {Array} ary the array of path segments. */ function trimDots(ary) { var i, part; for (i = 0; i < ary.length; i++) { part = ary[i]; if (part === '.') { ary.splice(i, 1); i -= 1; } else if (part === '..') { // If at the start, or previous value is still .., // keep them so that when converted to a path it may // still work when converted to a path, even though // as an ID it is less than ideal. In larger point // releases, may be better to just kick out an error. if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') { continue; } else if (i > 0) { ary.splice(i - 1, 2); i -= 2; } } } } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @param {Boolean} applyMap apply the map config to the value. Should * only be done if this normalization is for a dependency ID. * @returns {String} normalized name */ function normalize(name, baseName, applyMap) { var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, normalizedBaseParts, baseParts = (baseName && baseName.split('/')), map = config.map, starMap = map && map['*']; //Adjust any relative paths. if (name) { name = name.split('/'); lastIndex = name.length - 1; // If wanting node ID compatibility, strip .js from end // of IDs. Have to do this here, and not in nameToUrl // because node allows either .js or non .js to map // to same file. if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); } // Starts with a '.' so need the baseName if (name[0].charAt(0) === '.' && baseParts) { //Convert baseName to array, and lop off the last part, //so that . matches that 'directory' and not name of the baseName's //module. For instance, baseName of 'one/two/three', maps to //'one/two/three.js', but we want the directory, 'one/two' for //this normalization. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); name = normalizedBaseParts.concat(name); } trimDots(name); name = name.join('/'); } //Apply map config if available. if (applyMap && map && (baseParts || starMap)) { nameParts = name.split('/'); outerLoop: for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join('/'); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = getOwn(map, baseParts.slice(0, j).join('/')); //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = getOwn(mapValue, nameSegment); if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break outerLoop; } } } } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { foundStarMap = getOwn(starMap, nameSegment); starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join('/'); } } // If the name points to a package's name, use // the package main instead. pkgMain = getOwn(config.pkgs, name); return pkgMain ? pkgMain : name; } function removeScript(name) { if (isBrowser) { each(scripts(), function (scriptNode) { if (scriptNode.getAttribute('data-requiremodule') === name && scriptNode.getAttribute('data-requirecontext') === context.contextName) { scriptNode.parentNode.removeChild(scriptNode); return true; } }); } } function hasPathFallback(id) { var pathConfig = getOwn(config.paths, id); if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { //Pop off the first array value, since it failed, and //retry pathConfig.shift(); context.require.undef(id); //Custom require that does not do map translation, since //ID is "absolute", already mapped/resolved. context.makeRequire(null, { skipMap: true })([id]); return true; } } //Turns a plugin!resource to [plugin, resource] //with the plugin being undefined if the name //did not have a plugin prefix. function splitPrefix(name) { var prefix, index = name ? name.indexOf('!') : -1; if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } return [prefix, name]; } /** * Creates a module mapping that includes plugin prefix, module * name, and path. If parentModuleMap is provided it will * also normalize the name via require.normalize() * * @param {String} name the module name * @param {String} [parentModuleMap] parent module map * for the module name, used to resolve relative names. * @param {Boolean} isNormalized: is the ID already normalized. * This is true if this call is done for a define() module ID. * @param {Boolean} applyMap: apply the map config to the ID. * Should only be true if this map is for a dependency. * * @returns {Object} */ function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { var url, pluginModule, suffix, nameParts, prefix = null, parentName = parentModuleMap ? parentModuleMap.name : null, originalName = name, isDefine = true, normalizedName = ''; //If no name, then it means it is a require call, generate an //internal name. if (!name) { isDefine = false; name = '_@r' + (requireCounter += 1); } nameParts = splitPrefix(name); prefix = nameParts[0]; name = nameParts[1]; if (prefix) { prefix = normalize(prefix, parentName, applyMap); pluginModule = getOwn(defined, prefix); } //Account for relative paths if there is a base name. if (name) { if (prefix) { if (pluginModule && pluginModule.normalize) { //Plugin is loaded, use its normalize method. normalizedName = pluginModule.normalize(name, function (name) { return normalize(name, parentName, applyMap); }); } else { // If nested plugin references, then do not try to // normalize, as it will not normalize correctly. This // places a restriction on resourceIds, and the longer // term solution is not to normalize until plugins are // loaded and all normalizations to allow for async // loading of a loader plugin. But for now, fixes the // common uses. Details in #1131 normalizedName = name.indexOf('!') === -1 ? normalize(name, parentName, applyMap) : name; } } else { //A regular module. normalizedName = normalize(name, parentName, applyMap); //Normalized name may be a plugin ID due to map config //application in normalize. The map config values must //already be normalized, so do not need to redo that part. nameParts = splitPrefix(normalizedName); prefix = nameParts[0]; normalizedName = nameParts[1]; isNormalized = true; url = context.nameToUrl(normalizedName); } } //If the id is a plugin id that cannot be determined if it needs //normalization, stamp it with a unique ID so two matching relative //ids that may conflict can be separate. suffix = prefix && !pluginModule && !isNormalized ? '_unnormalized' + (unnormalizedCounter += 1) : ''; return { prefix: prefix, name: normalizedName, parentMap: parentModuleMap, unnormalized: !!suffix, url: url, originalName: originalName, isDefine: isDefine, id: (prefix ? prefix + '!' + normalizedName : normalizedName) + suffix }; } function getModule(depMap) { var id = depMap.id, mod = getOwn(registry, id); if (!mod) { mod = registry[id] = new context.Module(depMap); } return mod; } function on(depMap, name, fn) { var id = depMap.id, mod = getOwn(registry, id); if (hasProp(defined, id) && (!mod || mod.defineEmitComplete)) { if (name === 'defined') { fn(defined[id]); } } else { mod = getModule(depMap); if (mod.error && name === 'error') { fn(mod.error); } else { mod.on(name, fn); } } } function onError(err, errback) { var ids = err.requireModules, notified = false; if (errback) { errback(err); } else { each(ids, function (id) { var mod = getOwn(registry, id); if (mod) { //Set error on module, so it skips timeout checks. mod.error = err; if (mod.events.error) { notified = true; mod.emit('error', err); } } }); if (!notified) { req.onError(err); } } } /** * Internal method to transfer globalQueue items to this context's * defQueue. */ function takeGlobalQueue() { //Push all the globalDefQueue items into the context's defQueue if (globalDefQueue.length) { //Array splice in the values since the context code has a //local var ref to defQueue, so cannot just reassign the one //on context. apsp.apply(defQueue, [defQueue.length, 0].concat(globalDefQueue)); globalDefQueue = []; } } handlers = { 'require': function (mod) { if (mod.require) { return mod.require; } else { return (mod.require = context.makeRequire(mod.map)); } }, 'exports': function (mod) { mod.usingExports = true; if (mod.map.isDefine) { if (mod.exports) { return (defined[mod.map.id] = mod.exports); } else { return (mod.exports = defined[mod.map.id] = {}); } } }, 'module': function (mod) { if (mod.module) { return mod.module; } else { return (mod.module = { id: mod.map.id, uri: mod.map.url, config: function () { return getOwn(config.config, mod.map.id) || {}; }, exports: mod.exports || (mod.exports = {}) }); } } }; function cleanRegistry(id) { //Clean up machinery used for waiting modules. delete registry[id]; delete enabledRegistry[id]; } function breakCycle(mod, traced, processed) { var id = mod.map.id; if (mod.error) { mod.emit('error', mod.error); } else { traced[id] = true; each(mod.depMaps, function (depMap, i) { var depId = depMap.id, dep = getOwn(registry, depId); //Only force things that have not completed //being defined, so still in the registry, //and only if it has not been matched up //in the module already. if (dep && !mod.depMatched[i] && !processed[depId]) { if (getOwn(traced, depId)) { mod.defineDep(i, defined[depId]); mod.check(); //pass false? } else { breakCycle(dep, traced, processed); } } }); processed[id] = true; } } function checkLoaded() { var err, usingPathFallback, waitInterval = config.waitSeconds * 1000, //It is possible to disable the wait interval by using waitSeconds of 0. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), noLoads = [], reqCalls = [], stillLoading = false, needCycleCheck = true; //Do not bother if this call was a result of a cycle break. if (inCheckLoaded) { return; } inCheckLoaded = true; //Figure out the state of all the modules. eachProp(enabledRegistry, function (mod) { var map = mod.map, modId = map.id; //Skip things that are not enabled or in error state. if (!mod.enabled) { return; } if (!map.isDefine) { reqCalls.push(mod); } if (!mod.error) { //If the module should be executed, and it has not //been inited and time is up, remember it. if (!mod.inited && expired) { if (hasPathFallback(modId)) { usingPathFallback = true; stillLoading = true; } else { noLoads.push(modId); removeScript(modId); } } else if (!mod.inited && mod.fetched && map.isDefine) { stillLoading = true; if (!map.prefix) { //No reason to keep looking for unfinished //loading. If the only stillLoading is a //plugin resource though, keep going, //because it may be that a plugin resource //is waiting on a non-plugin cycle. return (needCycleCheck = false); } } } }); if (expired && noLoads.length) { //If wait time expired, throw error of unloaded modules. err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); err.contextName = context.contextName; return onError(err); } //Not expired, check for a cycle. if (needCycleCheck) { each(reqCalls, function (mod) { breakCycle(mod, {}, {}); }); } //If still waiting on loads, and the waiting load is something //other than a plugin resource, or there are still outstanding //scripts, then just try back later. if ((!expired || usingPathFallback) && stillLoading) { //Something is still waiting to load. Wait for it, but only //if a timeout is not already in effect. if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { checkLoadedTimeoutId = setTimeout(function () { checkLoadedTimeoutId = 0; checkLoaded(); }, 50); } } inCheckLoaded = false; } Module = function (map) { this.events = getOwn(undefEvents, map.id) || {}; this.map = map; this.shim = getOwn(config.shim, map.id); this.depExports = []; this.depMaps = []; this.depMatched = []; this.pluginMaps = {}; this.depCount = 0; /* this.exports this.factory this.depMaps = [], this.enabled, this.fetched */ }; Module.prototype = { init: function (depMaps, factory, errback, options) { options = options || {}; //Do not do more inits if already done. Can happen if there //are multiple define calls for the same module. That is not //a normal, common case, but it is also not unexpected. if (this.inited) { return; } this.factory = factory; if (errback) { //Register for errors on this module. this.on('error', errback); } else if (this.events.error) { //If no errback already, but there are error listeners //on this module, set up an errback to pass to the deps. errback = bind(this, function (err) { this.emit('error', err); }); } //Do a copy of the dependency array, so that //source inputs are not modified. For example //"shim" deps are passed in here directly, and //doing a direct modification of the depMaps array //would affect that config. this.depMaps = depMaps && depMaps.slice(0); this.errback = errback; //Indicate this module has be initialized this.inited = true; this.ignore = options.ignore; //Could have option to init this module in enabled mode, //or could have been previously marked as enabled. However, //the dependencies are not known until init is called. So //if enabled previously, now trigger dependencies as enabled. if (options.enabled || this.enabled) { //Enable this module and dependencies. //Will call this.check() this.enable(); } else { this.check(); } }, defineDep: function (i, depExports) { //Because of cycles, defined callback for a given //export can be called more than once. if (!this.depMatched[i]) { this.depMatched[i] = true; this.depCount -= 1; this.depExports[i] = depExports; } }, fetch: function () { if (this.fetched) { return; } this.fetched = true; context.startTime = (new Date()).getTime(); var map = this.map; //If the manager is for a plugin managed resource, //ask the plugin to load it now. if (this.shim) { context.makeRequire(this.map, { enableBuildCallback: true })(this.shim.deps || [], bind(this, function () { return map.prefix ? this.callPlugin() : this.load(); })); } else { //Regular dependency. return map.prefix ? this.callPlugin() : this.load(); } }, load: function () { var url = this.map.url; //Regular dependency. if (!urlFetched[url]) { urlFetched[url] = true; context.load(this.map.id, url); } }, /** * Checks if the module is ready to define itself, and if so, * define it. */ check: function () { if (!this.enabled || this.enabling) { return; } var err, cjsModule, id = this.map.id, depExports = this.depExports, exports = this.exports, factory = this.factory; if (!this.inited) { this.fetch(); } else if (this.error) { this.emit('error', this.error); } else if (!this.defining) { //The factory could trigger another require call //that would result in checking this module to //define itself again. If already in the process //of doing that, skip this work. this.defining = true; if (this.depCount < 1 && !this.defined) { if (isFunction(factory)) { //If there is an error listener, favor passing //to that instead of throwing an error. However, //only do it for define()'d modules. require //errbacks should not be called for failures in //their callbacks (#699). However if a global //onError is set, use that. if ((this.events.error && this.map.isDefine) || req.onError !== defaultOnError) { try { exports = context.execCb(id, factory, depExports, exports); } catch (e) { err = e; } } else { exports = context.execCb(id, factory, depExports, exports); } // Favor return value over exports. If node/cjs in play, // then will not have a return value anyway. Favor // module.exports assignment over exports object. if (this.map.isDefine && exports === undefined) { cjsModule = this.module; if (cjsModule) { exports = cjsModule.exports; } else if (this.usingExports) { //exports already set the defined value. exports = this.exports; } } if (err) { err.requireMap = this.map; err.requireModules = this.map.isDefine ? [this.map.id] : null; err.requireType = this.map.isDefine ? 'define' : 'require'; return onError((this.error = err)); } } else { //Just a literal value exports = factory; } this.exports = exports; if (this.map.isDefine && !this.ignore) { defined[id] = exports; if (req.onResourceLoad) { req.onResourceLoad(context, this.map, this.depMaps); } } //Clean up cleanRegistry(id); this.defined = true; } //Finished the define stage. Allow calling check again //to allow define notifications below in the case of a //cycle. this.defining = false; if (this.defined && !this.defineEmitted) { this.defineEmitted = true; this.emit('defined', this.exports); this.defineEmitComplete = true; } } }, callPlugin: function () { var map = this.map, id = map.id, //Map already normalized the prefix. pluginMap = makeModuleMap(map.prefix); //Mark this as a dependency for this plugin, so it //can be traced for cycles. this.depMaps.push(pluginMap); on(pluginMap, 'defined', bind(this, function (plugin) { var load, normalizedMap, normalizedMod, bundleId = getOwn(bundlesMap, this.map.id), name = this.map.name, parentName = this.map.parentMap ? this.map.parentMap.name : null, localRequire = context.makeRequire(map.parentMap, { enableBuildCallback: true }); //If current map is not normalized, wait for that //normalized name to load instead of continuing. if (this.map.unnormalized) { //Normalize the ID if the plugin allows it. if (plugin.normalize) { name = plugin.normalize(name, function (name) { return normalize(name, parentName, true); }) || ''; } //prefix and name should already be normalized, no need //for applying map config again either. normalizedMap = makeModuleMap(map.prefix + '!' + name, this.map.parentMap); on(normalizedMap, 'defined', bind(this, function (value) { this.init([], function () { return value; }, null, { enabled: true, ignore: true }); })); normalizedMod = getOwn(registry, normalizedMap.id); if (normalizedMod) { //Mark this as a dependency for this plugin, so it //can be traced for cycles. this.depMaps.push(normalizedMap); if (this.events.error) { normalizedMod.on('error', bind(this, function (err) { this.emit('error', err); })); } normalizedMod.enable(); } return; } //If a paths config, then just load that file instead to //resolve the plugin, as it is built into that paths layer. if (bundleId) { this.map.url = context.nameToUrl(bundleId); this.load(); return; } load = bind(this, function (value) { this.init([], function () { return value; }, null, { enabled: true }); }); load.error = bind(this, function (err) { this.inited = true; this.error = err; err.requireModules = [id]; //Remove temp unnormalized modules for this module, //since they will never be resolved otherwise now. eachProp(registry, function (mod) { if (mod.map.id.indexOf(id + '_unnormalized') === 0) { cleanRegistry(mod.map.id); } }); onError(err); }); //Allow plugins to load other code without having to know the //context or how to 'complete' the load. load.fromText = bind(this, function (text, textAlt) { /*jslint evil: true */ var moduleName = map.name, moduleMap = makeModuleMap(moduleName), hasInteractive = useInteractive; //As of 2.1.0, support just passing the text, to reinforce //fromText only being called once per resource. Still //support old style of passing moduleName but discard //that moduleName in favor of the internal ref. if (textAlt) { text = textAlt; } //Turn off interactive script matching for IE for any define //calls in the text, then turn it back on at the end. if (hasInteractive) { useInteractive = false; } //Prime the system by creating a module instance for //it. getModule(moduleMap); //Transfer any config to this other module. if (hasProp(config.config, id)) { config.config[moduleName] = config.config[id]; } try { req.exec(text); } catch (e) { return onError(makeError('fromtexteval', 'fromText eval for ' + id + ' failed: ' + e, e, [id])); } if (hasInteractive) { useInteractive = true; } //Mark this as a dependency for the plugin //resource this.depMaps.push(moduleMap); //Support anonymous modules. context.completeLoad(moduleName); //Bind the value of that module to the value for this //resource ID. localRequire([moduleName], load); }); //Use parentName here since the plugin's name is not reliable, //could be some weird string with no path that actually wants to //reference the parentName's path. plugin.load(map.name, localRequire, load, config); })); context.enable(pluginMap, this); this.pluginMaps[pluginMap.id] = pluginMap; }, enable: function () { enabledRegistry[this.map.id] = this; this.enabled = true; //Set flag mentioning that the module is enabling, //so that immediate calls to the defined callbacks //for dependencies do not trigger inadvertent load //with the depCount still being zero. this.enabling = true; //Enable each dependency each(this.depMaps, bind(this, function (depMap, i) { var id, mod, handler; if (typeof depMap === 'string') { //Dependency needs to be converted to a depMap //and wired up to this module. depMap = makeModuleMap(depMap, (this.map.isDefine ? this.map : this.map.parentMap), false, !this.skipMap); this.depMaps[i] = depMap; handler = getOwn(handlers, depMap.id); if (handler) { this.depExports[i] = handler(this); return; } this.depCount += 1; on(depMap, 'defined', bind(this, function (depExports) { this.defineDep(i, depExports); this.check(); })); if (this.errback) { on(depMap, 'error', bind(this, this.errback)); } } id = depMap.id; mod = registry[id]; //Skip special modules like 'require', 'exports', 'module' //Also, don't call enable if it is already enabled, //important in circular dependency cases. if (!hasProp(handlers, id) && mod && !mod.enabled) { context.enable(depMap, this); } })); //Enable each plugin that is used in //a dependency eachProp(this.pluginMaps, bind(this, function (pluginMap) { var mod = getOwn(registry, pluginMap.id); if (mod && !mod.enabled) { context.enable(pluginMap, this); } })); this.enabling = false; this.check(); }, on: function (name, cb) { var cbs = this.events[name]; if (!cbs) { cbs = this.events[name] = []; } cbs.push(cb); }, emit: function (name, evt) { each(this.events[name], function (cb) { cb(evt); }); if (name === 'error') { //Now that the error handler was triggered, remove //the listeners, since this broken Module instance //can stay around for a while in the registry. delete this.events[name]; } } }; function callGetModule(args) { //Skip modules already defined. if (!hasProp(defined, args[0])) { getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); } } function removeListener(node, func, name, ieName) { //Favor detachEvent because of IE9 //issue, see attachEvent/addEventListener comment elsewhere //in this file. if (node.detachEvent && !isOpera) { //Probably IE. If not it will throw an error, which will be //useful to know. if (ieName) { node.detachEvent(ieName, func); } } else { node.removeEventListener(name, func, false); } } /** * Given an event from a script node, get the requirejs info from it, * and then removes the event listeners on the node. * @param {Event} evt * @returns {Object} */ function getScriptData(evt) { //Using currentTarget instead of target for Firefox 2.0's sake. Not //all old browsers will be supported, but this one was easy enough //to support and still makes sense. var node = evt.currentTarget || evt.srcElement; //Remove the listeners once here. removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); removeListener(node, context.onScriptError, 'error'); return { node: node, id: node && node.getAttribute('data-requiremodule') }; } function intakeDefines() { var args; //Any defined modules in the global queue, intake them now. takeGlobalQueue(); //Make sure any remaining defQueue items get properly processed. while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); } else { //args are id, deps, factory. Should be normalized by the //define() function. callGetModule(args); } } } context = { config: config, contextName: contextName, registry: registry, defined: defined, urlFetched: urlFetched, defQueue: defQueue, Module: Module, makeModuleMap: makeModuleMap, nextTick: req.nextTick, onError: onError, /** * Set a configuration for the context. * @param {Object} cfg config object to integrate. */ configure: function (cfg) { //Make sure the baseUrl ends in a slash. if (cfg.baseUrl) { if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { cfg.baseUrl += '/'; } } //Save off the paths since they require special processing, //they are additive. var shim = config.shim, objs = { paths: true, bundles: true, config: true, map: true }; eachProp(cfg, function (value, prop) { if (objs[prop]) { if (!config[prop]) { config[prop] = {}; } mixin(config[prop], value, true, true); } else { config[prop] = value; } }); //Reverse map the bundles if (cfg.bundles) { eachProp(cfg.bundles, function (value, prop) { each(value, function (v) { if (v !== prop) { bundlesMap[v] = prop; } }); }); } //Merge shim if (cfg.shim) { eachProp(cfg.shim, function (value, id) { //Normalize the structure if (isArray(value)) { value = { deps: value }; } if ((value.exports || value.init) && !value.exportsFn) { value.exportsFn = context.makeShimExports(value); } shim[id] = value; }); config.shim = shim; } //Adjust packages if necessary. if (cfg.packages) { each(cfg.packages, function (pkgObj) { var location, name; pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; name = pkgObj.name; location = pkgObj.location; if (location) { config.paths[name] = pkgObj.location; } //Save pointer to main module ID for pkg name. //Remove leading dot in main, so main paths are normalized, //and remove any trailing .js, since different package //envs have different conventions: some use a module name, //some use a file name. config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main') .replace(currDirRegExp, '') .replace(jsSuffixRegExp, ''); }); } //If there are any "waiting to execute" modules in the registry, //update the maps for them, since their info, like URLs to load, //may have changed. eachProp(registry, function (mod, id) { //If module already has init called, since it is too //late to modify them, and ignore unnormalized ones //since they are transient. if (!mod.inited && !mod.map.unnormalized) { mod.map = makeModuleMap(id); } }); //If a deps array or a config callback is specified, then call //require with those args. This is useful when require is defined as a //config object before require.js is loaded. if (cfg.deps || cfg.callback) { context.require(cfg.deps || [], cfg.callback); } }, makeShimExports: function (value) { function fn() { var ret; if (value.init) { ret = value.init.apply(global, arguments); } return ret || (value.exports && getGlobal(value.exports)); } return fn; }, makeRequire: function (relMap, options) { options = options || {}; function localRequire(deps, callback, errback) { var id, map, requireMod; if (options.enableBuildCallback && callback && isFunction(callback)) { callback.__requireJsBuild = true; } if (typeof deps === 'string') { if (isFunction(callback)) { //Invalid call return onError(makeError('requireargs', 'Invalid require call'), errback); } //If require|exports|module are requested, get the //value for them from the special handlers. Caveat: //this only works while module is being defined. if (relMap && hasProp(handlers, deps)) { return handlers[deps](registry[relMap.id]); } //Synchronous access to one module. If require.get is //available (as in the Node adapter), prefer that. if (req.get) { return req.get(context, deps, relMap, localRequire); } //Normalize module name, if it contains . or .. map = makeModuleMap(deps, relMap, false, true); id = map.id; if (!hasProp(defined, id)) { return onError(makeError('notloaded', 'Module name "' + id + '" has not been loaded yet for context: ' + contextName + (relMap ? '' : '. Use require([])'))); } return defined[id]; } //Grab defines waiting in the global queue. intakeDefines(); //Mark all the dependencies as needing to be loaded. context.nextTick(function () { //Some defines could have been added since the //require call, collect them. intakeDefines(); requireMod = getModule(makeModuleMap(null, relMap)); //Store if map config should be applied to this require //call for dependencies. requireMod.skipMap = options.skipMap; requireMod.init(deps, callback, errback, { enabled: true }); checkLoaded(); }); return localRequire; } mixin(localRequire, { isBrowser: isBrowser, /** * Converts a module name + .extension into an URL path. * *Requires* the use of a module name. It does not support using * plain URLs like nameToUrl. */ toUrl: function (moduleNamePlusExt) { var ext, index = moduleNamePlusExt.lastIndexOf('.'), segment = moduleNamePlusExt.split('/')[0], isRelative = segment === '.' || segment === '..'; //Have a file extension alias, and it is not the //dots from a relative path. if (index !== -1 && (!isRelative || index > 1)) { ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); moduleNamePlusExt = moduleNamePlusExt.substring(0, index); } return context.nameToUrl(normalize(moduleNamePlusExt, relMap && relMap.id, true), ext, true); }, defined: function (id) { return hasProp(defined, makeModuleMap(id, relMap, false, true).id); }, specified: function (id) { id = makeModuleMap(id, relMap, false, true).id; return hasProp(defined, id) || hasProp(registry, id); } }); //Only allow undef on top level require calls if (!relMap) { localRequire.undef = function (id) { //Bind any waiting define() calls to this context, //fix for #408 takeGlobalQueue(); var map = makeModuleMap(id, relMap, true), mod = getOwn(registry, id); removeScript(id); delete defined[id]; delete urlFetched[map.url]; delete undefEvents[id]; //Clean queued defines too. Go backwards //in array so that the splices do not //mess up the iteration. eachReverse(defQueue, function(args, i) { if(args[0] === id) { defQueue.splice(i, 1); } }); if (mod) { //Hold on to listeners in case the //module will be attempted to be reloaded //using a different config. if (mod.events.defined) { undefEvents[id] = mod.events; } cleanRegistry(id); } }; } return localRequire; }, /** * Called to enable a module if it is still in the registry * awaiting enablement. A second arg, parent, the parent module, * is passed in for context, when this method is overridden by * the optimizer. Not shown here to keep code compact. */ enable: function (depMap) { var mod = getOwn(registry, depMap.id); if (mod) { getModule(depMap).enable(); } }, /** * Internal method used by environment adapters to complete a load event. * A load event could be a script load or just a load pass from a synchronous * load call. * @param {String} moduleName the name of the module to potentially complete. */ completeLoad: function (moduleName) { var found, args, mod, shim = getOwn(config.shim, moduleName) || {}, shExports = shim.exports; takeGlobalQueue(); while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { args[0] = moduleName; //If already found an anonymous module and bound it //to this name, then this is some other anon module //waiting for its completeLoad to fire. if (found) { break; } found = true; } else if (args[0] === moduleName) { //Found matching define call for this script! found = true; } callGetModule(args); } //Do this after the cycle of callGetModule in case the result //of those calls/init calls changes the registry. mod = getOwn(registry, moduleName); if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { if (hasPathFallback(moduleName)) { return; } else { return onError(makeError('nodefine', 'No define call for ' + moduleName, null, [moduleName])); } } else { //A script that does not call define(), so just simulate //the call for it. callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); } } checkLoaded(); }, /** * Converts a module name to a file path. Supports cases where * moduleName may actually be just an URL. * Note that it **does not** call normalize on the moduleName, * it is assumed to have already been normalized. This is an * internal API, not a public one. Use toUrl for the public API. */ nameToUrl: function (moduleName, ext, skipExt) { var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName); if (pkgMain) { moduleName = pkgMain; } bundleId = getOwn(bundlesMap, moduleName); if (bundleId) { return context.nameToUrl(bundleId, ext, skipExt); } //If a colon is in the URL, it indicates a protocol is used and it is just //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) //or ends with .js, then assume the user meant to use an url and not a module id. //The slash is important for protocol-less URLs as well as full paths. if (req.jsExtRegExp.test(moduleName)) { //Just a plain path, not module name lookup, so just return it. //Add extension if it is included. This is a bit wonky, only non-.js things pass //an extension, this method probably needs to be reworked. url = moduleName + (ext || ''); } else { //A module that needs to be converted to a path. paths = config.paths; syms = moduleName.split('/'); //For each module name segment, see if there is a path //registered for it. Start with most specific name //and work up from it. for (i = syms.length; i > 0; i -= 1) { parentModule = syms.slice(0, i).join('/'); parentPath = getOwn(paths, parentModule); if (parentPath) { //If an array, it means there are a few choices, //Choose the one that is desired if (isArray(parentPath)) { parentPath = parentPath[0]; } syms.splice(0, i, parentPath); break; } } //Join the path parts together, then figure out if baseUrl is needed. url = syms.join('/'); url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; } return config.urlArgs ? url + ((url.indexOf('?') === -1 ? '?' : '&') + config.urlArgs) : url; }, //Delegates to req.load. Broken out as a separate function to //allow overriding in the optimizer. load: function (id, url) { req.load(context, id, url); }, /** * Executes a module callback function. Broken out as a separate function * solely to allow the build system to sequence the files in the built * layer in the right sequence. * * @private */ execCb: function (name, callback, args, exports) { return callback.apply(exports, args); }, /** * callback for script loads, used to check status of loading. * * @param {Event} evt the event from the browser for the script * that was loaded. */ onScriptLoad: function (evt) { //Using currentTarget instead of target for Firefox 2.0's sake. Not //all old browsers will be supported, but this one was easy enough //to support and still makes sense. if (evt.type === 'load' || (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { //Reset interactive script so a script node is not held onto for //to long. interactiveScript = null; //Pull out the name of the module and the context. var data = getScriptData(evt); context.completeLoad(data.id); } }, /** * Callback for script errors. */ onScriptError: function (evt) { var data = getScriptData(evt); if (!hasPathFallback(data.id)) { return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id])); } } }; context.require = context.makeRequire(); return context; } /** * Main entry point. * * If the only argument to require is a string, then the module that * is represented by that string is fetched for the appropriate context. * * If the first argument is an array, then it will be treated as an array * of dependency string names to fetch. An optional function callback can * be specified to execute when all of those dependencies are available. * * Make a local req variable to help Caja compliance (it assumes things * on a require that are not standardized), and to give a short * name for minification/local scope use. */ req = requirejs = function (deps, callback, errback, optional) { //Find the right context, use default var context, config, contextName = defContextName; // Determine if have config object in the call. if (!isArray(deps) && typeof deps !== 'string') { // deps is a config object config = deps; if (isArray(callback)) { // Adjust args if there are dependencies deps = callback; callback = errback; errback = optional; } else { deps = []; } } if (config && config.context) { contextName = config.context; } context = getOwn(contexts, contextName); if (!context) { context = contexts[contextName] = req.s.newContext(contextName); } if (config) { context.configure(config); } return context.require(deps, callback, errback); }; /** * Support require.config() to make it easier to cooperate with other * AMD loaders on globally agreed names. */ req.config = function (config) { return req(config); }; /** * Execute something after the current tick * of the event loop. Override for other envs * that have a better solution than setTimeout. * @param {Function} fn function to execute later. */ req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { setTimeout(fn, 4); } : function (fn) { fn(); }; /** * Export require as a global, but only if it does not already exist. */ if (!require) { require = req; } req.version = version; //Used to filter out dependencies that are already paths. req.jsExtRegExp = /^\/|:|\?|\.js$/; req.isBrowser = isBrowser; s = req.s = { contexts: contexts, newContext: newContext }; //Create default context. req({}); //Exports some context-sensitive methods on global require. each([ 'toUrl', 'undef', 'defined', 'specified' ], function (prop) { //Reference from contexts instead of early binding to default context, //so that during builds, the latest instance of the default context //with its config gets used. req[prop] = function () { var ctx = contexts[defContextName]; return ctx.require[prop].apply(ctx, arguments); }; }); if (isBrowser) { head = s.head = document.getElementsByTagName('head')[0]; //If BASE tag is in play, using appendChild is a problem for IE6. //When that browser dies, this can be removed. Details in this jQuery bug: //http://dev.jquery.com/ticket/2709 baseElement = document.getElementsByTagName('base')[0]; if (baseElement) { head = s.head = baseElement.parentNode; } } /** * Any errors that require explicitly generates will be passed to this * function. Intercept/override it if you want custom error handling. * @param {Error} err the error object. */ req.onError = defaultOnError; /** * Creates the node for the load command. Only used in browser envs. */ req.createNode = function (config, moduleName, url) { var node = config.xhtml ? document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : document.createElement('script'); node.type = config.scriptType || 'text/javascript'; node.charset = 'utf-8'; node.async = true; return node; }; /** * Does the request to load a module for the browser case. * Make this a separate function to allow other environments * to override it. * * @param {Object} context the require context to find state. * @param {String} moduleName the name of the module. * @param {Object} url the URL to the module. */ req.load = function (context, moduleName, url) { var config = (context && context.config) || {}, node; if (isBrowser) { //In the browser so use a script tag node = req.createNode(config, moduleName, url); node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName); //Set up load listener. Test attachEvent first because IE9 has //a subtle issue in its addEventListener and script onload firings //that do not match the behavior of all other browsers with //addEventListener support, which fire the onload event for a //script right after the script execution. See: //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution //UNFORTUNATELY Opera implements attachEvent but does not follow the script //script execution mode. if (node.attachEvent && //Check if node.attachEvent is artificially added by custom script or //natively supported by browser //read https://github.com/jrburke/requirejs/issues/187 //if we can NOT find [native code] then it must NOT natively supported. //in IE8, node.attachEvent does not have toString() //Note the test for "[native code" with no closing brace, see: //https://github.com/jrburke/requirejs/issues/273 !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera) { //Probably IE. IE (at least 6-8) do not fire //script onload right after executing the script, so //we cannot tie the anonymous define call to a name. //However, IE reports the script as being in 'interactive' //readyState at the time of the define call. useInteractive = true; node.attachEvent('onreadystatechange', context.onScriptLoad); //It would be great to add an error handler here to catch //404s in IE9+. However, onreadystatechange will fire before //the error handler, so that does not help. If addEventListener //is used, then IE will fire error before load, but we cannot //use that pathway given the connect.microsoft.com issue //mentioned above about not doing the 'script execute, //then fire the script load event listener before execute //next script' that other browsers do. //Best hope: IE10 fixes the issues, //and then destroys all installs of IE 6-9. //node.attachEvent('onerror', context.onScriptError); } else { node.addEventListener('load', context.onScriptLoad, false); node.addEventListener('error', context.onScriptError, false); } node.src = url; //For some cache cases in IE 6-8, the script executes before the end //of the appendChild execution, so to tie an anonymous define //call to the module name (which is stored on the node), hold on //to a reference to this node, but clear after the DOM insertion. currentlyAddingScript = node; if (baseElement) { head.insertBefore(node, baseElement); } else { head.appendChild(node); } currentlyAddingScript = null; return node; } else if (isWebWorker) { try { //In a web worker, use importScripts. This is not a very //efficient use of importScripts, importScripts will block until //its script is downloaded and evaluated. However, if web workers //are in play, the expectation that a build has been done so that //only one script needs to be loaded anyway. This may need to be //reevaluated if other use cases become common. importScripts(url); //Account for anonymous modules context.completeLoad(moduleName); } catch (e) { context.onError(makeError('importscripts', 'importScripts failed for ' + moduleName + ' at ' + url, e, [moduleName])); } } }; function getInteractiveScript() { if (interactiveScript && interactiveScript.readyState === 'interactive') { return interactiveScript; } eachReverse(scripts(), function (script) { if (script.readyState === 'interactive') { return (interactiveScript = script); } }); return interactiveScript; } //Look for a data-main script attribute, which could also adjust the baseUrl. if (isBrowser && !cfg.skipDataMain) { //Figure out baseUrl. Get it from the script tag with require.js in it. eachReverse(scripts(), function (script) { //Set the 'head' where we can append children by //using the script's parent. if (!head) { head = script.parentNode; } //Look for a data-main attribute to set main script for the page //to load. If it is there, the path to data main becomes the //baseUrl, if it is not already set. dataMain = script.getAttribute('data-main'); if (dataMain) { //Preserve dataMain in case it is a path (i.e. contains '?') mainScript = dataMain; //Set final baseUrl if there is not already an explicit one. if (!cfg.baseUrl) { //Pull off the directory of data-main for use as the //baseUrl. src = mainScript.split('/'); mainScript = src.pop(); subPath = src.length ? src.join('/') + '/' : './'; cfg.baseUrl = subPath; } //Strip off any trailing .js since mainScript is now //like a module name. mainScript = mainScript.replace(jsSuffixRegExp, ''); //If mainScript is still a path, fall back to dataMain if (req.jsExtRegExp.test(mainScript)) { mainScript = dataMain; } //Put the data-main script in the files to load. cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; return true; } }); } /** * The function that handles definitions of modules. Differs from * require() in that a string for the module should be the first argument, * and the function to execute after dependencies are loaded should * return a value to define the module corresponding to the first argument's * name. */ define = function (name, deps, callback) { var node, context; //Allow for anonymous modules if (typeof name !== 'string') { //Adjust args appropriately callback = deps; deps = name; name = null; } //This module may not have dependencies if (!isArray(deps)) { callback = deps; deps = null; } //If no name, and callback is a function, then figure out if it a //CommonJS thing with dependencies. if (!deps && isFunction(callback)) { deps = []; //Remove comments from the callback string, //look for require calls, and pull them into the dependencies, //but only if there are function args. if (callback.length) { callback .toString() .replace(commentRegExp, '') .replace(cjsRequireRegExp, function (match, dep) { deps.push(dep); }); //May be a CommonJS thing even without require calls, but still //could use exports, and module. Avoid doing exports and module //work though if it just needs require. //REQUIRES the function to expect the CommonJS variables in the //order listed below. deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); } } //If in IE 6-8 and hit an anonymous define() call, do the interactive //work. if (useInteractive) { node = currentlyAddingScript || getInteractiveScript(); if (node) { if (!name) { name = node.getAttribute('data-requiremodule'); } context = contexts[node.getAttribute('data-requirecontext')]; } } //Always save off evaluating the def call until the script onload handler. //This allows multiple modules to be in a file without prematurely //tracing dependencies, and allows for anonymous module support, //where the module name is not known until the script onload event //occurs. If no context, use the global queue, and get it processed //in the onscript load callback. (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); }; define.amd = { jQuery: true }; /** * Executes the text. Normally just uses eval, but can be modified * to use a better, environment-specific call. Only used for transpiling * loader plugins, not for plain JS modules. * @param {String} text the text to execute/evaluate. */ req.exec = function (text) { /*jslint evil: true */ return eval(text); }; //Set up with config info. req(cfg); }(this)); ================================================ FILE: demo/node/a.js ================================================ var D = require('../../data.js'); D.set('a', 1234); D.sub('set', 'a', function (e) { console.log('a.js', 'set a:', e.data); }); ================================================ FILE: demo/node/main.js ================================================ var D = require('../../data.js'); require('./a'); console.log(D.get('a')); D.set('a', 1); console.log(D.get('a')); ================================================ FILE: demo/requirejs.html ================================================ requirejs ================================================ FILE: doc/api.md ================================================ #data.js data.js在浏览器环境中默认占用全局变量Data,在模块化编程环境中,引用模块返回Data,返回的Data是一个数据中心+工厂函数,可直接将其作为一个数据中心使用,也可通过该函数创建新的数据中心。 //一下两种方式均可获取数据中心的实例 var D = Data(); var D = new Data(); //有一个数据中心,与上面的D无关系 var F = new Data(); //在实例化的数据中心上操作 F.set(***); //在默认的数据中心上操作 Data.set(***); ##noConflict 此函数会在以原始方式在浏览器中引入是存在,用来释放Data占用的全局变量Data。同时返回Data。 - return {Function} Data demo var D = Data.noConflict();//释放Data,并赋值给D ##version 获取data.js的版本号,字符串,仅在Data上存在。 console.log(Data.version);//0.1.0 console.log(Data().version);//undefined ##has 判断Data中是否存在,指定的数据。 - key {String} 要判断的键,点号是分隔符,用来分隔对象层次 - return {Bollean} 是否包含指定键值 demo Data.has(key);//返回true或false ##get* 从Data中获取指定的键值。 - key {String} 要获取的键 - return {val} 返回与键值对应的数据,若键值的上游不存在,会返回undefined或null demo Data.get('a');//undefined Data.get('a.b.c')//undefined **注:**此处获取的是Data中数据的深拷贝,即get接口返回的数据是Data中对应数据的一份深拷贝。之所以牺牲性能,这样设计是因为深拷贝能避免很多难以预知的bug。 下面是深拷贝,浅拷贝和引用的区别: //深拷贝 var a = Data.get('a');//若a为{b:{c:1}} a.b.c= 2;//此处更改不会影像Data中的数据 Data.get('a.b.c')//此处输出1 //浅拷贝 var a = Data.get('a');//若a为{b:{c:1}} a.b.c= 2; Data.get('a.b.c')//此处输出2 //仅返回引用 var a = Data.get('a');//若a为{b:{c:1}} a.b = 1; Data.get('a.b')//此处输出1 ##set* 向Data中放入数据。若已存在,则是扩展当前数据,不会重新赋值(对于数组或对象,对于其他类型值会覆盖)。 - key {String} 放入Data中数据的键值 - val {val} [可选] 放入Data中的数据 - return {Bollean} 是否添加成功 传入key + val 和 传入 {key: val}的方式等价,可以选择自己喜欢的方式,键值的方式更清晰,作者推荐前一种,记住只使用同一种方式会让事情变得简单。 demo //传入值类型 D.set('a', 1); D.get('a');//1 //传入引用类型 D.set('a', {b: 1}); D.get('a.b');//1 D.set('a.b.c', 1); D.set('a', {b: {c: 1}}});//这两种功能一样 ###key key值是Data的基石,key是一个字符串,Data的key支持任何utf-8编码的字符,js支持的就可以 - 字母 abc - 数字 123 - 特殊字符 _-+$;'"... - 甚至是汉字 颜海镜 Data都可以完美支持,同时key还有类似对象属性的特性,a.b.c是获取a下的b下的c,其中.号是分隔符,可以想像成js中的对象(其实Data内部确实是按对象处理)。 D.set('a', {}); D.set('a.b', 1); D.set('a.c', [1]); D.set('a.1.1', 1);//此处会创建数组 `D.get('a')`的输出如下: { 1: [1], b:1, c:[undefined ,1] } Data可以将传入的键,智能转换为对应的空间,支持对象和数组。 ##sub* sub方法是Data的核心方法,用来订阅消息,订阅指定键值的指定事件,在对应的值发生变化时,会得到通知(当传入对象和数组时,消息会下发到其子元素)。 - type {String} 订阅消息的类型 (可选值:set, add, update, delete 分别代表 设置,添加,更新,删除,其中set是通用类型,其他三个为细分类型,并且互斥) - key {String} 订阅消息的键值 - callback {Function} 消息接受函数 - return {Number} 消息的同意id用于取消订阅事件用 demo D.sub('set', 'a', function (e) {console.log(e)}); D.set('a', 1);//a值更新,会调用回调函数 ###e - type {String} 消息的类型 - key {String} 消息的建 - data {val} 设置的值 ##unsub 取消订阅的消息。 - type {String} 取消订阅消息的类型 (可选值:set, add, update, delete 分别代表 设置,添加,更新,删除,其中set是通用类型,其他三个为细分类型,并且互斥) - key {String} 取消订阅消息的键值 - id {Number} [可选] sub是返回的消息的id - return {Bollean} 是否取消成功 若id为空则会删除所有对应键值和类型的所有事件。 demo var id = D.sub('set', 'a', function (e) {console.log(e)}); D.set('a', 1);//a值更新,会调用回调函数 D.unsub('set', 'a', id); D.set('a', 1);//不会在收到通知 ##注意事项 由于Data设计之初希望支持跨平台,所以要支持ecmascript类型数据,Data希望放入的是数据,期望的是原生数据,支持 Number,Bollean,String,Object,null,undefined,Array。对于Object和Array会是其深拷贝值,并且会创造层级。 对于其他类型对象js都默认为值类型,如dom节点,仅简单赋值其引用,所以消息无法下发到dom的子元素上,但get接口可以取到其子元素。其他类型对象还包括: - window - document - dom - dom list - node list 请不要将复杂对象和引用自身的对象放入Data中,会造成性能的严重下降,和不可预知的问题。复杂对象包括如下: - jquery对象 建议放入原生数据,对于jquery对象可传入其查询字符串。 ================================================ FILE: gulpfile.js ================================================ /** * @file gulp file * @author yanhaijing.com * @date 2016年1月13日 15:55:16 */ var gulp = require('gulp'); var jshint = require('gulp-jshint'); gulp.task('lint', function() { return gulp.src('data.js') .pipe(jshint('.jshintrc')) .pipe(jshint.reporter('default')); }); ================================================ FILE: lib/es5-shim.js ================================================ /*! * https://github.com/es-shims/es5-shim * @license es5-shim Copyright 2009-2015 by contributors, MIT License * see https://github.com/es-shims/es5-shim/blob/master/LICENSE */ // vim: ts=4 sts=4 sw=4 expandtab // Add semicolon to prevent IIFE from being passed as argument to concatenated code. ; // UMD (Universal Module Definition) // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js (function (root, factory) { 'use strict'; /* global define, exports, module */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.returnExports = factory(); } }(this, function () { /** * Brings an environment as close to ECMAScript 5 compliance * as is possible with the facilities of erstwhile engines. * * Annotated ES5: http://es5.github.com/ (specific links below) * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ */ // Shortcut to an often accessed properties, in order to avoid multiple // dereference that costs universally. This also holds a reference to known-good // functions. var $Array = Array; var ArrayPrototype = $Array.prototype; var $Object = Object; var ObjectPrototype = $Object.prototype; var FunctionPrototype = Function.prototype; var $String = String; var StringPrototype = $String.prototype; var $Number = Number; var NumberPrototype = $Number.prototype; var array_slice = ArrayPrototype.slice; var array_splice = ArrayPrototype.splice; var array_push = ArrayPrototype.push; var array_unshift = ArrayPrototype.unshift; var array_concat = ArrayPrototype.concat; var call = FunctionPrototype.call; var apply = FunctionPrototype.apply; var max = Math.max; var min = Math.min; // Having a toString local variable name breaks in Opera so use to_string. var to_string = ObjectPrototype.toString; var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; }; var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; }; var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; }; /* inlined from http://npmjs.com/define-properties */ var supportsDescriptors = $Object.defineProperty && (function () { try { var obj = {}; $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); for (var _ in obj) { return false; } return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var defineProperties = (function (has) { // Define configurable, writable, and non-enumerable props // if they don't exist. var defineProperty; if (supportsDescriptors) { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } $Object.defineProperty(object, name, { configurable: true, enumerable: false, writable: true, value: method }); }; } else { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } object[name] = method; }; } return function defineProperties(object, map, forceAssign) { for (var name in map) { if (has.call(map, name)) { defineProperty(object, name, map[name], forceAssign); } } }; }(ObjectPrototype.hasOwnProperty)); // // Util // ====== // /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ var isPrimitive = function isPrimitive(input) { var type = typeof input; return input === null || (type !== 'object' && type !== 'function'); }; var isActualNaN = $Number.isNaN || function (x) { return x !== x; }; var ES = { // ES5 9.4 // http://es5.github.com/#x9.4 // http://jsperf.com/to-integer /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */ ToInteger: function ToInteger(num) { var n = +num; if (isActualNaN(n)) { n = 0; } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } return n; }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */ ToPrimitive: function ToPrimitive(input) { var val, valueOf, toStr; if (isPrimitive(input)) { return input; } valueOf = input.valueOf; if (isCallable(valueOf)) { val = valueOf.call(input); if (isPrimitive(val)) { return val; } } toStr = input.toString; if (isCallable(toStr)) { val = toStr.call(input); if (isPrimitive(val)) { return val; } } throw new TypeError(); }, // ES5 9.9 // http://es5.github.com/#x9.9 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */ ToObject: function (o) { if (o == null) { // this matches both null and undefined throw new TypeError("can't convert " + o + ' to object'); } return $Object(o); }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ ToUint32: function ToUint32(x) { return x >>> 0; } }; // // Function // ======== // // ES-5 15.3.4.5 // http://es5.github.com/#x15.3.4.5 var Empty = function Empty() {}; defineProperties(FunctionPrototype, { bind: function bind(that) { // .length is 1 // 1. Let Target be the this value. var target = this; // 2. If IsCallable(Target) is false, throw a TypeError exception. if (!isCallable(target)) { throw new TypeError('Function.prototype.bind called on incompatible ' + target); } // 3. Let A be a new (possibly empty) internal list of all of the // argument values provided after thisArg (arg1, arg2 etc), in order. // XXX slicedArgs will stand in for "A" if used var args = array_slice.call(arguments, 1); // for normal call // 4. Let F be a new native ECMAScript object. // 11. Set the [[Prototype]] internal property of F to the standard // built-in Function prototype object as specified in 15.3.3.1. // 12. Set the [[Call]] internal property of F as described in // 15.3.4.5.1. // 13. Set the [[Construct]] internal property of F as described in // 15.3.4.5.2. // 14. Set the [[HasInstance]] internal property of F as described in // 15.3.4.5.3. var bound; var binder = function () { if (this instanceof bound) { // 15.3.4.5.2 [[Construct]] // When the [[Construct]] internal method of a function object, // F that was created using the bind function is called with a // list of arguments ExtraArgs, the following steps are taken: // 1. Let target be the value of F's [[TargetFunction]] // internal property. // 2. If target has no [[Construct]] internal method, a // TypeError exception is thrown. // 3. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Construct]] internal // method of target providing args as the arguments. var result = target.apply( this, array_concat.call(args, array_slice.call(arguments)) ); if ($Object(result) === result) { return result; } return this; } else { // 15.3.4.5.1 [[Call]] // When the [[Call]] internal method of a function object, F, // which was created using the bind function is called with a // this value and a list of arguments ExtraArgs, the following // steps are taken: // 1. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 2. Let boundThis be the value of F's [[BoundThis]] internal // property. // 3. Let target be the value of F's [[TargetFunction]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Call]] internal method // of target providing boundThis as the this value and // providing args as the arguments. // equiv: target.call(this, ...boundArgs, ...args) return target.apply( that, array_concat.call(args, array_slice.call(arguments)) ); } }; // 15. If the [[Class]] internal property of Target is "Function", then // a. Let L be the length property of Target minus the length of A. // b. Set the length own property of F to either 0 or L, whichever is // larger. // 16. Else set the length own property of F to 0. var boundLength = max(0, target.length - args.length); // 17. Set the attributes of the length own property of F to the values // specified in 15.3.5.1. var boundArgs = []; for (var i = 0; i < boundLength; i++) { array_push.call(boundArgs, '$' + i); } // XXX Build a dynamic function with desired amount of arguments is the only // way to set the length property of a function. // In environments where Content Security Policies enabled (Chrome extensions, // for ex.) all use of eval or Function costructor throws an exception. // However in all of these environments Function.prototype.bind exists // and so this code will never be executed. bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder); if (target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); // Clean up dangling references. Empty.prototype = null; } // TODO // 18. Set the [[Extensible]] internal property of F to true. // TODO // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). // 20. Call the [[DefineOwnProperty]] internal method of F with // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and // false. // 21. Call the [[DefineOwnProperty]] internal method of F with // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, // and false. // TODO // NOTE Function objects created using Function.prototype.bind do not // have a prototype property or the [[Code]], [[FormalParameters]], and // [[Scope]] internal properties. // XXX can't delete prototype in pure-js. // 22. Return F. return bound; } }); // _Please note: Shortcuts are defined after `Function.prototype.bind` as we // use it in defining shortcuts. var owns = call.bind(ObjectPrototype.hasOwnProperty); var toStr = call.bind(ObjectPrototype.toString); var arraySlice = call.bind(array_slice); var arraySliceApply = apply.bind(array_slice); var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); var push = call.bind(array_push); var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); var arraySort = call.bind(ArrayPrototype.sort); // // Array // ===== // var isArray = $Array.isArray || function isArray(obj) { return toStr(obj) === '[object Array]'; }; // ES5 15.4.4.12 // http://es5.github.com/#x15.4.4.13 // Return len+argCount. // [bugfix, ielt8] // IE < 8 bug: [].unshift(0) === undefined but should be "1" var hasUnshiftReturnValueBug = [].unshift(0) !== 1; defineProperties(ArrayPrototype, { unshift: function () { array_unshift.apply(this, arguments); return this.length; } }, hasUnshiftReturnValueBug); // ES5 15.4.3.2 // http://es5.github.com/#x15.4.3.2 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray defineProperties($Array, { isArray: isArray }); // The IsCallable() check in the Array functions // has been replaced with a strict check on the // internal class of the object to trap cases where // the provided function was actually a regular // expression literal, which in V8 and // JavaScriptCore is a typeof "function". Only in // V8 are regular expression literals permitted as // reduce parameters, so it is desirable in the // general case for the shim to match the more // strict and common behavior of rejecting regular // expressions. // ES5 15.4.4.18 // http://es5.github.com/#x15.4.4.18 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach // Check failure of by-index access of string characters (IE < 9) // and failure of `0 in boxedString` (Rhino) var boxedString = $Object('a'); var splitString = boxedString[0] !== 'a' || !(0 in boxedString); var properlyBoxesContext = function properlyBoxed(method) { // Check node 0.6.21 bug where third parameter is not boxed var properlyBoxesNonStrict = true; var properlyBoxesStrict = true; if (method) { method.call('foo', function (_, __, context) { if (typeof context !== 'object') { properlyBoxesNonStrict = false; } }); method.call([1], function () { 'use strict'; properlyBoxesStrict = typeof this === 'string'; }, 'x'); } return !!method && properlyBoxesNonStrict && properlyBoxesStrict; }; defineProperties(ArrayPrototype, { forEach: function forEach(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var i = -1; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.forEach callback must be a function'); } while (++i < length) { if (i in self) { // Invoke the callback function with call, passing arguments: // context, property value, property key, thisArg object if (typeof T === 'undefined') { callbackfn(self[i], i, object); } else { callbackfn.call(T, self[i], i, object); } } } } }, !properlyBoxesContext(ArrayPrototype.forEach)); // ES5 15.4.4.19 // http://es5.github.com/#x15.4.4.19 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map defineProperties(ArrayPrototype, { map: function map(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = $Array(length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.map callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { if (typeof T === 'undefined') { result[i] = callbackfn(self[i], i, object); } else { result[i] = callbackfn.call(T, self[i], i, object); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.map)); // ES5 15.4.4.20 // http://es5.github.com/#x15.4.4.20 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter defineProperties(ArrayPrototype, { filter: function filter(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = []; var value; var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.filter callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { value = self[i]; if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { push(result, value); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.filter)); // ES5 15.4.4.16 // http://es5.github.com/#x15.4.4.16 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every defineProperties(ArrayPrototype, { every: function every(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.every callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return false; } } return true; } }, !properlyBoxesContext(ArrayPrototype.every)); // ES5 15.4.4.17 // http://es5.github.com/#x15.4.4.17 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some defineProperties(ArrayPrototype, { some: function some(callbackfn/*, thisArg */) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.some callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return true; } } return false; } }, !properlyBoxesContext(ArrayPrototype.some)); // ES5 15.4.4.21 // http://es5.github.com/#x15.4.4.21 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce var reduceCoercesToObject = false; if (ArrayPrototype.reduce) { reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduce: function reduce(callbackfn/*, initialValue*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduce callback must be a function'); } // no value to return if no initial value and an empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduce of empty array with no initial value'); } var i = 0; var result; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i++]; break; } // if array contains no values, no initial value to return if (++i >= length) { throw new TypeError('reduce of empty array with no initial value'); } } while (true); } for (; i < length; i++) { if (i in self) { result = callbackfn(result, self[i], i, object); } } return result; } }, !reduceCoercesToObject); // ES5 15.4.4.22 // http://es5.github.com/#x15.4.4.22 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight var reduceRightCoercesToObject = false; if (ArrayPrototype.reduceRight) { reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduceRight: function reduceRight(callbackfn/*, initial*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduceRight callback must be a function'); } // no value to return if no initial value, empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduceRight of empty array with no initial value'); } var result; var i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i--]; break; } // if array contains no values, no initial value to return if (--i < 0) { throw new TypeError('reduceRight of empty array with no initial value'); } } while (true); } if (i < 0) { return result; } do { if (i in self) { result = callbackfn(result, self[i], i, object); } } while (i--); return result; } }, !reduceRightCoercesToObject); // ES5 15.4.4.14 // http://es5.github.com/#x15.4.4.14 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; defineProperties(ArrayPrototype, { indexOf: function indexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = 0; if (arguments.length > 1) { i = ES.ToInteger(arguments[1]); } // handle negative indices i = i >= 0 ? i : max(0, length + i); for (; i < length; i++) { if (i in self && self[i] === searchElement) { return i; } } return -1; } }, hasFirefox2IndexOfBug); // ES5 15.4.4.15 // http://es5.github.com/#x15.4.4.15 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; defineProperties(ArrayPrototype, { lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = length - 1; if (arguments.length > 1) { i = min(i, ES.ToInteger(arguments[1])); } // handle negative indices i = i >= 0 ? i : length - Math.abs(i); for (; i >= 0; i--) { if (i in self && searchElement === self[i]) { return i; } } return -1; } }, hasFirefox2LastIndexOfBug); // ES5 15.4.4.12 // http://es5.github.com/#x15.4.4.12 var spliceNoopReturnsEmptyArray = (function () { var a = [1, 2]; var result = a.splice(); return a.length === 2 && isArray(result) && result.length === 0; }()); defineProperties(ArrayPrototype, { // Safari 5.0 bug where .splice() returns undefined splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } else { return array_splice.apply(this, arguments); } } }, !spliceNoopReturnsEmptyArray); var spliceWorksWithEmptyObject = (function () { var obj = {}; ArrayPrototype.splice.call(obj, 0, 0, 1); return obj.length === 1; }()); defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } var args = arguments; this.length = max(ES.ToInteger(this.length), 0); if (arguments.length > 0 && typeof deleteCount !== 'number') { args = arraySlice(arguments); if (args.length < 2) { push(args, this.length - start); } else { args[1] = ES.ToInteger(deleteCount); } } return array_splice.apply(this, args); } }, !spliceWorksWithEmptyObject); var spliceWorksWithLargeSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Safari 7/8 breaks with sparse arrays of size 1e5 or greater var arr = new $Array(1e5); // note: the index MUST be 8 or larger or the test will false pass arr[8] = 'x'; arr.splice(1, 1); // note: this test must be defined *after* the indexOf shim // per https://github.com/es-shims/es5-shim/issues/313 return arr.indexOf('x') === 7; }()); var spliceWorksWithSmallSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Opera 12.15 breaks on this, no idea why. var n = 256; var arr = []; arr[n] = 'a'; arr.splice(n + 1, 0, 'b'); return arr[n] === 'a'; }()); defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { var O = ES.ToObject(this); var A = []; var len = ES.ToUint32(O.length); var relativeStart = ES.ToInteger(start); var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len); var actualDeleteCount = min(max(ES.ToInteger(deleteCount), 0), len - actualStart); var k = 0; var from; while (k < actualDeleteCount) { from = $String(actualStart + k); if (owns(O, from)) { A[k] = O[from]; } k += 1; } var items = arraySlice(arguments, 2); var itemCount = items.length; var to; if (itemCount < actualDeleteCount) { k = actualStart; while (k < (len - actualDeleteCount)) { from = $String(k + actualDeleteCount); to = $String(k + itemCount); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k += 1; } k = len; while (k > (len - actualDeleteCount + itemCount)) { delete O[k - 1]; k -= 1; } } else if (itemCount > actualDeleteCount) { k = len - actualDeleteCount; while (k > actualStart) { from = $String(k + actualDeleteCount - 1); to = $String(k + itemCount - 1); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k -= 1; } } k = actualStart; for (var i = 0; i < items.length; ++i) { O[k] = items[i]; k += 1; } O.length = len - actualDeleteCount + itemCount; return A; } }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); var originalJoin = ArrayPrototype.join; var hasStringJoinBug; try { hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3'; } catch (e) { hasStringJoinBug = true; } if (hasStringJoinBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep); } }, hasStringJoinBug); } var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2'; if (hasJoinUndefinedBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(this, sep); } }, hasJoinUndefinedBug); } var pushShim = function push(item) { var O = ES.ToObject(this); var n = ES.ToUint32(O.length); var i = 0; while (i < arguments.length) { O[n + i] = arguments[i]; i += 1; } O.length = n + i; return n + i; }; var pushIsNotGeneric = (function () { var obj = {}; var result = Array.prototype.push.call(obj, undefined); return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0); }()); defineProperties(ArrayPrototype, { push: function push(item) { if (isArray(this)) { return array_push.apply(this, arguments); } return pushShim.apply(this, arguments); } }, pushIsNotGeneric); // This fixes a very weird bug in Opera 10.6 when pushing `undefined var pushUndefinedIsWeird = (function () { var arr = []; var result = arr.push(undefined); return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0); }()); defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird); // ES5 15.2.3.14 // http://es5.github.io/#x15.4.4.10 // Fix boxed string bug defineProperties(ArrayPrototype, { slice: function (start, end) { var arr = isString(this) ? strSplit(this, '') : this; return arraySliceApply(arr, arguments); } }, splitString); var sortIgnoresNonFunctions = (function () { try { [1, 2].sort(null); [1, 2].sort({}); return true; } catch (e) { /**/ } return false; }()); var sortThrowsOnRegex = (function () { // this is a problem in Firefox 4, in which `typeof /a/ === 'function'` try { [1, 2].sort(/a/); return false; } catch (e) { /**/ } return true; }()); var sortIgnoresUndefined = (function () { // applies in IE 8, for one. try { [1, 2].sort(undefined); return true; } catch (e) { /**/ } return false; }()); defineProperties(ArrayPrototype, { sort: function sort(compareFn) { if (typeof compareFn === 'undefined') { return arraySort(this); } if (!isCallable(compareFn)) { throw new TypeError('Array.prototype.sort callback must be a function'); } return arraySort(this, compareFn); } }, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex); // // Object // ====== // // ES5 15.2.3.14 // http://es5.github.com/#x15.2.3.14 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'); var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); var hasStringEnumBug = !owns('x', '0'); var equalsConstructorPrototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var blacklistedKeys = { $window: true, $console: true, $parent: true, $self: true, $frame: true, $frames: true, $frameElement: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $external: true }; var hasAutomationEqualityBug = (function () { /* globals window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!blacklistedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { equalsConstructorPrototype(window[k]); } } catch (e) { return true; } } return false; }()); var equalsConstructorPrototypeIfNotBuggy = function (object) { if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(object); } try { return equalsConstructorPrototype(object); } catch (e) { return false; } }; var dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; var dontEnumsLength = dontEnums.length; // taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js // can be replaced with require('is-arguments') if we ever use a build process instead var isStandardArguments = function isArguments(value) { return toStr(value) === '[object Arguments]'; }; var isLegacyArguments = function isArguments(value) { return value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && !isArray(value) && isCallable(value.callee); }; var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments; defineProperties($Object, { keys: function keys(object) { var isFn = isCallable(object); var isArgs = isArguments(object); var isObject = object !== null && typeof object === 'object'; var isStr = isObject && isString(object); if (!isObject && !isFn && !isArgs) { throw new TypeError('Object.keys called on a non-object'); } var theKeys = []; var skipProto = hasProtoEnumBug && isFn; if ((isStr && hasStringEnumBug) || isArgs) { for (var i = 0; i < object.length; ++i) { push(theKeys, $String(i)); } } if (!isArgs) { for (var name in object) { if (!(skipProto && name === 'prototype') && owns(object, name)) { push(theKeys, $String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var j = 0; j < dontEnumsLength; j++) { var dontEnum = dontEnums[j]; if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { push(theKeys, dontEnum); } } } return theKeys; } }); var keysWorksWithArguments = $Object.keys && (function () { // Safari 5.0 bug return $Object.keys(arguments).length === 2; }(1, 2)); var keysHasArgumentsLengthBug = $Object.keys && (function () { var argKeys = $Object.keys(arguments); return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1; }(1)); var originalKeys = $Object.keys; defineProperties($Object, { keys: function keys(object) { if (isArguments(object)) { return originalKeys(arraySlice(object)); } else { return originalKeys(object); } } }, !keysWorksWithArguments || keysHasArgumentsLengthBug); // // Date // ==== // var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0; var aNegativeTestDate = new Date(-1509842289600292); var aPositiveTestDate = new Date(1449662400000); var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT'; var hasToDateStringFormatBug; var hasToStringFormatBug; var timeZoneOffset = aNegativeTestDate.getTimezoneOffset(); if (timeZoneOffset < -720) { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875'; hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString()); } else { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875'; hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString()); } var originalGetFullYear = call.bind(Date.prototype.getFullYear); var originalGetMonth = call.bind(Date.prototype.getMonth); var originalGetDate = call.bind(Date.prototype.getDate); var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear); var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth); var originalGetUTCDate = call.bind(Date.prototype.getUTCDate); var originalGetUTCDay = call.bind(Date.prototype.getUTCDay); var originalGetUTCHours = call.bind(Date.prototype.getUTCHours); var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes); var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds); var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds); var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri']; var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; var daysInMonth = function daysInMonth(month, year) { return originalGetDate(new Date(year, month, 0)); }; defineProperties(Date.prototype, { getFullYear: function getFullYear() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); if (year < 0 && originalGetMonth(this) > 11) { return year + 1; } return year; }, getMonth: function getMonth() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); var month = originalGetMonth(this); if (year < 0 && month > 11) { return 0; } return month; }, getDate: function getDate() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); var month = originalGetMonth(this); var date = originalGetDate(this); if (year < 0 && month > 11) { if (month === 12) { return date; } var days = daysInMonth(0, year + 1); return (days - date) + 1; } return date; }, getUTCFullYear: function getUTCFullYear() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); if (year < 0 && originalGetUTCMonth(this) > 11) { return year + 1; } return year; }, getUTCMonth: function getUTCMonth() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); if (year < 0 && month > 11) { return 0; } return month; }, getUTCDate: function getUTCDate() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); var date = originalGetUTCDate(this); if (year < 0 && month > 11) { if (month === 12) { return date; } var days = daysInMonth(0, year + 1); return (days - date) + 1; } return date; } }, hasNegativeMonthYearBug); defineProperties(Date.prototype, { toUTCString: function toUTCString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = originalGetUTCDay(this); var date = originalGetUTCDate(this); var month = originalGetUTCMonth(this); var year = originalGetUTCFullYear(this); var hour = originalGetUTCHours(this); var minute = originalGetUTCMinutes(this); var second = originalGetUTCSeconds(this); return dayName[day] + ', ' + (date < 10 ? '0' + date : date) + ' ' + monthName[month] + ' ' + year + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second) + ' GMT'; } }, hasNegativeMonthYearBug || hasToUTCStringFormatBug); // Opera 12 has `,` defineProperties(Date.prototype, { toDateString: function toDateString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = this.getDay(); var date = this.getDate(); var month = this.getMonth(); var year = this.getFullYear(); return dayName[day] + ' ' + monthName[month] + ' ' + (date < 10 ? '0' + date : date) + ' ' + year; } }, hasNegativeMonthYearBug || hasToDateStringFormatBug); // can't use defineProperties here because of toString enumeration issue in IE <= 8 if (hasNegativeMonthYearBug || hasToStringFormatBug) { Date.prototype.toString = function toString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = this.getDay(); var date = this.getDate(); var month = this.getMonth(); var year = this.getFullYear(); var hour = this.getHours(); var minute = this.getMinutes(); var second = this.getSeconds(); var timezoneOffset = this.getTimezoneOffset(); var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60); var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60); return dayName[day] + ' ' + monthName[month] + ' ' + (date < 10 ? '0' + date : date) + ' ' + year + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second) + ' GMT' + (timezoneOffset > 0 ? '-' : '+') + (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) + (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset); }; if (supportsDescriptors) { $Object.defineProperty(Date.prototype, 'toString', { configurable: true, enumerable: false, writable: true }); } } // ES5 15.9.5.43 // http://es5.github.com/#x15.9.5.43 // This function returns a String value represent the instance in time // represented by this Date object. The format of the String is the Date Time // string format defined in 15.9.1.15. All fields are present in the String. // The time zone is always UTC, denoted by the suffix Z. If the time value of // this object is not a finite Number a RangeError exception is thrown. var negativeDate = -62198755200000; var negativeYearString = '-000001'; var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z'; defineProperties(Date.prototype, { toISOString: function toISOString() { if (!isFinite(this)) { throw new RangeError('Date.prototype.toISOString called on non-finite value.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); // see https://github.com/es-shims/es5-shim/issues/111 year += Math.floor(month / 12); month = (month % 12 + 12) % 12; // the date time string format is specified in 15.9.1.15. var result = [month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this)]; year = ( (year < 0 ? '-' : (year > 9999 ? '+' : '')) + strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6) ); for (var i = 0; i < result.length; ++i) { // pad months, days, hours, minutes, and seconds to have two digits. result[i] = strSlice('00' + result[i], -2); } // pad milliseconds to have three digits. return ( year + '-' + arraySlice(result, 0, 2).join('-') + 'T' + arraySlice(result, 2).join(':') + '.' + strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z' ); } }, hasNegativeDateBug || hasSafari51DateBug); // ES5 15.9.5.44 // http://es5.github.com/#x15.9.5.44 // This function provides a String representation of a Date object for use by // JSON.stringify (15.12.3). var dateToJSONIsSupported = (function () { try { return Date.prototype.toJSON && new Date(NaN).toJSON() === null && new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && Date.prototype.toJSON.call({ // generic toISOString: function () { return true; } }); } catch (e) { return false; } }()); if (!dateToJSONIsSupported) { Date.prototype.toJSON = function toJSON(key) { // When the toJSON method is called with argument key, the following // steps are taken: // 1. Let O be the result of calling ToObject, giving it the this // value as its argument. // 2. Let tv be ES.ToPrimitive(O, hint Number). var O = $Object(this); var tv = ES.ToPrimitive(O); // 3. If tv is a Number and is not finite, return null. if (typeof tv === 'number' && !isFinite(tv)) { return null; } // 4. Let toISO be the result of calling the [[Get]] internal method of // O with argument "toISOString". var toISO = O.toISOString; // 5. If IsCallable(toISO) is false, throw a TypeError exception. if (!isCallable(toISO)) { throw new TypeError('toISOString property is not callable'); } // 6. Return the result of calling the [[Call]] internal method of // toISO with O as the this value and an empty argument list. return toISO.call(O); // NOTE 1 The argument is ignored. // NOTE 2 The toJSON function is intentionally generic; it does not // require that its this value be a Date object. Therefore, it can be // transferred to other kinds of objects for use as a method. However, // it does require that any such object have a toISOString method. An // object is free to use the argument key to filter its // stringification. }; } // ES5 15.9.4.2 // http://es5.github.com/#x15.9.4.2 // based on work shared by Daniel Friesen (dantman) // http://gist.github.com/303249 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z')); var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { // XXX global assignment won't work in embeddings that use // an alternate object for the context. /* global Date: true */ /* eslint-disable no-undef */ var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1; var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime()); Date = (function (NativeDate) { /* eslint-enable no-undef */ // Date.length === 7 var DateShim = function Date(Y, M, D, h, m, s, ms) { var length = arguments.length; var date; if (this instanceof NativeDate) { var seconds = s; var millis = ms; if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) { // work around a Safari 8/9 bug where it treats the seconds as signed var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; var sToShift = Math.floor(msToShift / 1e3); seconds += sToShift; millis -= sToShift * 1e3; } date = length === 1 && $String(Y) === Y ? // isString(Y) // We explicitly pass it through parse: new NativeDate(DateShim.parse(Y)) : // We have to manually make calls depending on argument // length here length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) : length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) : length >= 5 ? new NativeDate(Y, M, D, h, m) : length >= 4 ? new NativeDate(Y, M, D, h) : length >= 3 ? new NativeDate(Y, M, D) : length >= 2 ? new NativeDate(Y, M) : length >= 1 ? new NativeDate(Y) : new NativeDate(); } else { date = NativeDate.apply(this, arguments); } if (!isPrimitive(date)) { // Prevent mixups with unfixed Date object defineProperties(date, { constructor: DateShim }, true); } return date; }; // 15.9.1.15 Date Time String Format. var isoDateExpression = new RegExp('^' + '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign + // 6-digit extended year '(?:-(\\d{2})' + // optional month capture '(?:-(\\d{2})' + // optional day capture '(?:' + // capture hours:minutes:seconds.milliseconds 'T(\\d{2})' + // hours capture ':(\\d{2})' + // minutes capture '(?:' + // optional :seconds.milliseconds ':(\\d{2})' + // seconds capture '(?:(\\.\\d{1,}))?' + // milliseconds capture ')?' + '(' + // capture UTC offset component 'Z|' + // UTC capture '(?:' + // offset specifier +/-hours:minutes '([-+])' + // sign capture '(\\d{2})' + // hours offset capture ':(\\d{2})' + // minutes offset capture ')' + ')?)?)?)?' + '$'); var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; var dayFromMonth = function dayFromMonth(year, month) { var t = month > 1 ? 1 : 0; return ( months[month] + Math.floor((year - 1969 + t) / 4) - Math.floor((year - 1901 + t) / 100) + Math.floor((year - 1601 + t) / 400) + 365 * (year - 1970) ); }; var toUTC = function toUTC(t) { var s = 0; var ms = t; if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) { // work around a Safari 8/9 bug where it treats the seconds as signed var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; var sToShift = Math.floor(msToShift / 1e3); s += sToShift; ms -= sToShift * 1e3; } return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms)); }; // Copy any custom methods a 3rd party library may have added for (var key in NativeDate) { if (owns(NativeDate, key)) { DateShim[key] = NativeDate[key]; } } // Copy "native" methods explicitly; they may be non-enumerable defineProperties(DateShim, { now: NativeDate.now, UTC: NativeDate.UTC }, true); DateShim.prototype = NativeDate.prototype; defineProperties(DateShim.prototype, { constructor: DateShim }, true); // Upgrade Date.parse to handle simplified ISO 8601 strings var parseShim = function parse(string) { var match = isoDateExpression.exec(string); if (match) { // parse months, days, hours, minutes, seconds, and milliseconds // provide default values if necessary // parse the UTC offset component var year = $Number(match[1]), month = $Number(match[2] || 1) - 1, day = $Number(match[3] || 1) - 1, hour = $Number(match[4] || 0), minute = $Number(match[5] || 0), second = $Number(match[6] || 0), millisecond = Math.floor($Number(match[7] || 0) * 1000), // When time zone is missed, local offset should be used // (ES 5.1 bug) // see https://bugs.ecmascript.org/show_bug.cgi?id=112 isLocalTime = Boolean(match[4] && !match[8]), signOffset = match[9] === '-' ? 1 : -1, hourOffset = $Number(match[10] || 0), minuteOffset = $Number(match[11] || 0), result; var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0; if ( hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) && minute < 60 && second < 60 && millisecond < 1000 && month > -1 && month < 12 && hourOffset < 24 && minuteOffset < 60 && // detect invalid offsets day > -1 && day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month)) ) { result = ( (dayFromMonth(year, month) + day) * 24 + hour + hourOffset * signOffset ) * 60; result = ( (result + minute + minuteOffset * signOffset) * 60 + second ) * 1000 + millisecond; if (isLocalTime) { result = toUTC(result); } if (-8.64e15 <= result && result <= 8.64e15) { return result; } } return NaN; } return NativeDate.parse.apply(this, arguments); }; defineProperties(DateShim, { parse: parseShim }); return DateShim; }(Date)); /* global Date: false */ } // ES5 15.9.4.4 // http://es5.github.com/#x15.9.4.4 if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } // // Number // ====== // // ES5.1 15.7.4.5 // http://es5.github.com/#x15.7.4.5 var hasToFixedBugs = NumberPrototype.toFixed && ( (0.00008).toFixed(3) !== '0.000' || (0.9).toFixed(0) !== '1' || (1.255).toFixed(2) !== '1.25' || (1000000000000000128).toFixed(0) !== '1000000000000000128' ); var toFixedHelpers = { base: 1e7, size: 6, data: [0, 0, 0, 0, 0, 0], multiply: function multiply(n, c) { var i = -1; var c2 = c; while (++i < toFixedHelpers.size) { c2 += n * toFixedHelpers.data[i]; toFixedHelpers.data[i] = c2 % toFixedHelpers.base; c2 = Math.floor(c2 / toFixedHelpers.base); } }, divide: function divide(n) { var i = toFixedHelpers.size, c = 0; while (--i >= 0) { c += toFixedHelpers.data[i]; toFixedHelpers.data[i] = Math.floor(c / n); c = (c % n) * toFixedHelpers.base; } }, numToString: function numToString() { var i = toFixedHelpers.size; var s = ''; while (--i >= 0) { if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { var t = $String(toFixedHelpers.data[i]); if (s === '') { s = t; } else { s += strSlice('0000000', 0, 7 - t.length) + t; } } } return s; }, pow: function pow(x, n, acc) { return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); }, log: function log(x) { var n = 0; var x2 = x; while (x2 >= 4096) { n += 12; x2 /= 4096; } while (x2 >= 2) { n += 1; x2 /= 2; } return n; } }; var toFixedShim = function toFixed(fractionDigits) { var f, x, s, m, e, z, j, k; // Test for NaN and round fractionDigits down f = $Number(fractionDigits); f = isActualNaN(f) ? 0 : Math.floor(f); if (f < 0 || f > 20) { throw new RangeError('Number.toFixed called with invalid number of decimals'); } x = $Number(this); if (isActualNaN(x)) { return 'NaN'; } // If it is too big or small, return the string value of the number if (x <= -1e21 || x >= 1e21) { return $String(x); } s = ''; if (x < 0) { s = '-'; x = -x; } m = '0'; if (x > 1e-21) { // 1e-21 < x < 1e21 // -70 < log2(x) < 70 e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); z *= 0x10000000000000; // Math.pow(2, 52); e = 52 - e; // -18 < e < 122 // x = z / 2 ^ e if (e > 0) { toFixedHelpers.multiply(0, z); j = f; while (j >= 7) { toFixedHelpers.multiply(1e7, 0); j -= 7; } toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); j = e - 1; while (j >= 23) { toFixedHelpers.divide(1 << 23); j -= 23; } toFixedHelpers.divide(1 << j); toFixedHelpers.multiply(1, 1); toFixedHelpers.divide(2); m = toFixedHelpers.numToString(); } else { toFixedHelpers.multiply(0, z); toFixedHelpers.multiply(1 << (-e), 0); m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f); } } if (f > 0) { k = m.length; if (k <= f) { m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m; } else { m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f); } } else { m = s + m; } return m; }; defineProperties(NumberPrototype, { toFixed: toFixedShim }, hasToFixedBugs); var hasToPrecisionUndefinedBug = (function () { try { return 1.0.toPrecision(undefined) === '1'; } catch (e) { return true; } }()); var originalToPrecision = NumberPrototype.toPrecision; defineProperties(NumberPrototype, { toPrecision: function toPrecision(precision) { return typeof precision === 'undefined' ? originalToPrecision.call(this) : originalToPrecision.call(this, precision); } }, hasToPrecisionUndefinedBug); // // String // ====== // // ES5 15.5.4.14 // http://es5.github.com/#x15.5.4.14 // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] // Many browsers do not split properly with regular expressions or they // do not perform the split correctly under obscure conditions. // See http://blog.stevenlevithan.com/archives/cross-browser-split // I've tested in many browsers and this seems to cover the deviant ones: // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not // [undefined, "t", undefined, "e", ...] // ''.split(/.?/) should be [], not [""] // '.'.split(/()()/) should be ["."], not ["", "", "."] if ( 'ab'.split(/(?:ab)*/).length !== 2 || '.'.split(/(.?)(.?)/).length !== 4 || 'tesst'.split(/(s)*/)[1] === 't' || 'test'.split(/(?:)/, -1).length !== 4 || ''.split(/.?/).length || '.'.split(/()()/).length > 1 ) { (function () { var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group var maxSafe32BitInt = Math.pow(2, 32) - 1; StringPrototype.split = function (separator, limit) { var string = String(this); if (typeof separator === 'undefined' && limit === 0) { return []; } // If `separator` is not a regex, use native split if (!isRegex(separator)) { return strSplit(this, separator, limit); } var output = []; var flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.unicode ? 'u' : '') + // in ES6 (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6 lastLastIndex = 0, // Make `global` and avoid `lastIndex` issues by working with a copy separator2, match, lastIndex, lastLength; var separatorCopy = new RegExp(separator.source, flags + 'g'); if (!compliantExecNpcg) { // Doesn't need flags gy, but they don't hurt separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); } /* Values for `limit`, per the spec: * If undefined: 4294967295 // maxSafe32BitInt * If 0, Infinity, or NaN: 0 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; * If negative number: 4294967296 - Math.floor(Math.abs(limit)) * If other: Type-convert, then use the above rules */ var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit); match = separatorCopy.exec(string); while (match) { // `separatorCopy.lastIndex` is not reliable cross-browser lastIndex = match.index + match[0].length; if (lastIndex > lastLastIndex) { push(output, strSlice(string, lastLastIndex, match.index)); // Fix browsers whose `exec` methods don't consistently return `undefined` for // nonparticipating capturing groups if (!compliantExecNpcg && match.length > 1) { /* eslint-disable no-loop-func */ match[0].replace(separator2, function () { for (var i = 1; i < arguments.length - 2; i++) { if (typeof arguments[i] === 'undefined') { match[i] = void 0; } } }); /* eslint-enable no-loop-func */ } if (match.length > 1 && match.index < string.length) { array_push.apply(output, arraySlice(match, 1)); } lastLength = match[0].length; lastLastIndex = lastIndex; if (output.length >= splitLimit) { break; } } if (separatorCopy.lastIndex === match.index) { separatorCopy.lastIndex++; // Avoid an infinite loop } match = separatorCopy.exec(string); } if (lastLastIndex === string.length) { if (lastLength || !separatorCopy.test('')) { push(output, ''); } } else { push(output, strSlice(string, lastLastIndex)); } return output.length > splitLimit ? strSlice(output, 0, splitLimit) : output; }; }()); // [bugfix, chrome] // If separator is undefined, then the result array contains just one String, // which is the this value (converted to a String). If limit is not undefined, // then the output array is truncated so that it contains no more than limit // elements. // "0".split(undefined, 0) -> [] } else if ('0'.split(void 0, 0).length) { StringPrototype.split = function split(separator, limit) { if (typeof separator === 'undefined' && limit === 0) { return []; } return strSplit(this, separator, limit); }; } var str_replace = StringPrototype.replace; var replaceReportsGroupsCorrectly = (function () { var groups = []; 'x'.replace(/x(.)?/g, function (match, group) { push(groups, group); }); return groups.length === 1 && typeof groups[0] === 'undefined'; }()); if (!replaceReportsGroupsCorrectly) { StringPrototype.replace = function replace(searchValue, replaceValue) { var isFn = isCallable(replaceValue); var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); if (!isFn || !hasCapturingGroups) { return str_replace.call(this, searchValue, replaceValue); } else { var wrappedReplaceValue = function (match) { var length = arguments.length; var originalLastIndex = searchValue.lastIndex; searchValue.lastIndex = 0; var args = searchValue.exec(match) || []; searchValue.lastIndex = originalLastIndex; push(args, arguments[length - 2], arguments[length - 1]); return replaceValue.apply(this, args); }; return str_replace.call(this, searchValue, wrappedReplaceValue); } }; } // ECMA-262, 3rd B.2.3 // Not an ECMAScript standard, although ECMAScript 3rd Edition has a // non-normative section suggesting uniform semantics and it should be // normalized across all browsers // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE var string_substr = StringPrototype.substr; var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; defineProperties(StringPrototype, { substr: function substr(start, length) { var normalizedStart = start; if (start < 0) { normalizedStart = max(this.length + start, 0); } return string_substr.call(this, normalizedStart, length); } }, hasNegativeSubstrBug); // ES5 15.5.4.20 // whitespace from: http://es5.github.io/#x15.5.4.20 var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; var zeroWidth = '\u200b'; var wsRegexChars = '[' + ws + ']'; var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); defineProperties(StringPrototype, { // http://blog.stevenlevithan.com/archives/faster-trim-javascript // http://perfectionkills.com/whitespace-deviations/ trim: function trim() { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); } }, hasTrimWhitespaceBug); var trim = call.bind(String.prototype.trim); var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1; defineProperties(StringPrototype, { lastIndexOf: function lastIndexOf(searchString) { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } var S = $String(this); var searchStr = $String(searchString); var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN; var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos); var start = min(max(pos, 0), S.length); var searchLen = searchStr.length; var k = start + searchLen; while (k > 0) { k = max(0, k - searchLen); var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr); if (index !== -1) { return k + index; } } return -1; } }, hasLastIndexBug); var originalLastIndexOf = StringPrototype.lastIndexOf; defineProperties(StringPrototype, { lastIndexOf: function lastIndexOf(searchString) { return originalLastIndexOf.apply(this, arguments); } }, StringPrototype.lastIndexOf.length !== 1); // ES-5 15.1.2.2 /* eslint-disable radix */ if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { /* eslint-enable radix */ /* global parseInt: true */ parseInt = (function (origParseInt) { var hexRegex = /^[\-+]?0[xX]/; return function parseInt(str, radix) { var string = trim(str); var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); return origParseInt(string, defaultedRadix); }; }(parseInt)); } // https://es5.github.io/#x15.1.2.3 if (1 / parseFloat(-0) !== -Infinity) { /* global parseFloat: true */ parseFloat = (function (origParseFloat) { return function parseFloat(string) { var inputString = trim(string); var result = origParseFloat(inputString); return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result; }; }(parseFloat)); } if (String(new RangeError('test')) !== 'RangeError: test') { var errorToStringShim = function toString() { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } var name = this.name; if (typeof name === 'undefined') { name = 'Error'; } else if (typeof name !== 'string') { name = $String(name); } var msg = this.message; if (typeof msg === 'undefined') { msg = ''; } else if (typeof msg !== 'string') { msg = $String(msg); } if (!name) { return msg; } if (!msg) { return name; } return name + ': ' + msg; }; // can't use defineProperties here because of toString enumeration issue in IE <= 8 Error.prototype.toString = errorToStringShim; } if (supportsDescriptors) { var ensureNonEnumerable = function (obj, prop) { if (isEnum(obj, prop)) { var desc = Object.getOwnPropertyDescriptor(obj, prop); desc.enumerable = false; Object.defineProperty(obj, prop, desc); } }; ensureNonEnumerable(Error.prototype, 'message'); if (Error.prototype.message !== '') { Error.prototype.message = ''; } ensureNonEnumerable(Error.prototype, 'name'); } if (String(/a/mig) !== '/a/gim') { var regexToString = function toString() { var str = '/' + this.source + '/'; if (this.global) { str += 'g'; } if (this.ignoreCase) { str += 'i'; } if (this.multiline) { str += 'm'; } return str; }; // can't use defineProperties here because of toString enumeration issue in IE <= 8 RegExp.prototype.toString = regexToString; } })); ================================================ FILE: package.json ================================================ { "name": "data_js", "description": "data.js 是带有消息通知的数据中心,我称其为会说话的数据。旨在让编程变得简单,世界变得美好。", "version": "0.3.0", "homepage": "https://github.com/yanhaijing/data.js", "author": { "name": "yanhaijing", "email": "yanhaijing@yeah.net", "url": "http://yanhaijing.com" }, "repository": { "type": "git", "url": "git://github.com/yanhaijing/data.js.git" }, "bugs": { "url": "https://github.com/yanhaijing/data.js/issues" }, "licenses": [ { "type": "MIT", "url": "https://github.com/yanhaijing/data.js/blob/master/MIT-LICENSE.txt" } ], "engines": { "node": ">= 0.8.0" }, "scripts": { "test": "mocha test" }, "devDependencies": { "expect.js": "~0.3.1", "gulp": "~3.9.0", "gulp-jshint": "~2.0.0", "jshint": "~2.9.1-rc3" }, "keywords": [ "data", "data.js", "Data" ], "main": "data.js", "spm": { "main": "data.js", "ignore": [ "demo", "doc", "test" ] } } ================================================ FILE: test/browser/expect.js ================================================ (function (global, module) { var exports = module.exports; /** * Exports. */ module.exports = expect; expect.Assertion = Assertion; /** * Exports version. */ expect.version = '0.3.1'; /** * Possible assertion flags. */ var flags = { not: ['to', 'be', 'have', 'include', 'only'] , to: ['be', 'have', 'include', 'only', 'not'] , only: ['have'] , have: ['own'] , be: ['an'] }; function expect (obj) { return new Assertion(obj); } /** * Constructor * * @api private */ function Assertion (obj, flag, parent) { this.obj = obj; this.flags = {}; if (undefined != parent) { this.flags[flag] = true; for (var i in parent.flags) { if (parent.flags.hasOwnProperty(i)) { this.flags[i] = true; } } } var $flags = flag ? flags[flag] : keys(flags) , self = this; if ($flags) { for (var i = 0, l = $flags.length; i < l; i++) { // avoid recursion if (this.flags[$flags[i]]) continue; var name = $flags[i] , assertion = new Assertion(this.obj, name, this) if ('function' == typeof Assertion.prototype[name]) { // clone the function, make sure we dont touch the prot reference var old = this[name]; this[name] = function () { return old.apply(self, arguments); }; for (var fn in Assertion.prototype) { if (Assertion.prototype.hasOwnProperty(fn) && fn != name) { this[name][fn] = bind(assertion[fn], assertion); } } } else { this[name] = assertion; } } } } /** * Performs an assertion * * @api private */ Assertion.prototype.assert = function (truth, msg, error, expected) { var msg = this.flags.not ? error : msg , ok = this.flags.not ? !truth : truth , err; if (!ok) { err = new Error(msg.call(this)); if (arguments.length > 3) { err.actual = this.obj; err.expected = expected; err.showDiff = true; } throw err; } this.and = new Assertion(this.obj); }; /** * Check if the value is truthy * * @api public */ Assertion.prototype.ok = function () { this.assert( !!this.obj , function(){ return 'expected ' + i(this.obj) + ' to be truthy' } , function(){ return 'expected ' + i(this.obj) + ' to be falsy' }); }; /** * Creates an anonymous function which calls fn with arguments. * * @api public */ Assertion.prototype.withArgs = function() { expect(this.obj).to.be.a('function'); var fn = this.obj; var args = Array.prototype.slice.call(arguments); return expect(function() { fn.apply(null, args); }); }; /** * Assert that the function throws. * * @param {Function|RegExp} callback, or regexp to match error string against * @api public */ Assertion.prototype.throwError = Assertion.prototype.throwException = function (fn) { expect(this.obj).to.be.a('function'); var thrown = false , not = this.flags.not; try { this.obj(); } catch (e) { if (isRegExp(fn)) { var subject = 'string' == typeof e ? e : e.message; if (not) { expect(subject).to.not.match(fn); } else { expect(subject).to.match(fn); } } else if ('function' == typeof fn) { fn(e); } thrown = true; } if (isRegExp(fn) && not) { // in the presence of a matcher, ensure the `not` only applies to // the matching. this.flags.not = false; } var name = this.obj.name || 'fn'; this.assert( thrown , function(){ return 'expected ' + name + ' to throw an exception' } , function(){ return 'expected ' + name + ' not to throw an exception' }); }; /** * Checks if the array is empty. * * @api public */ Assertion.prototype.empty = function () { var expectation; if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) { if ('number' == typeof this.obj.length) { expectation = !this.obj.length; } else { expectation = !keys(this.obj).length; } } else { if ('string' != typeof this.obj) { expect(this.obj).to.be.an('object'); } expect(this.obj).to.have.property('length'); expectation = !this.obj.length; } this.assert( expectation , function(){ return 'expected ' + i(this.obj) + ' to be empty' } , function(){ return 'expected ' + i(this.obj) + ' to not be empty' }); return this; }; /** * Checks if the obj exactly equals another. * * @api public */ Assertion.prototype.be = Assertion.prototype.equal = function (obj) { this.assert( obj === this.obj , function(){ return 'expected ' + i(this.obj) + ' to equal ' + i(obj) } , function(){ return 'expected ' + i(this.obj) + ' to not equal ' + i(obj) }); return this; }; /** * Checks if the obj sortof equals another. * * @api public */ Assertion.prototype.eql = function (obj) { this.assert( expect.eql(this.obj, obj) , function(){ return 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) } , function(){ return 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj) } , obj); return this; }; /** * Assert within start to finish (inclusive). * * @param {Number} start * @param {Number} finish * @api public */ Assertion.prototype.within = function (start, finish) { var range = start + '..' + finish; this.assert( this.obj >= start && this.obj <= finish , function(){ return 'expected ' + i(this.obj) + ' to be within ' + range } , function(){ return 'expected ' + i(this.obj) + ' to not be within ' + range }); return this; }; /** * Assert typeof / instance of * * @api public */ Assertion.prototype.a = Assertion.prototype.an = function (type) { if ('string' == typeof type) { // proper english in error msg var n = /^[aeiou]/.test(type) ? 'n' : ''; // typeof with support for 'array' this.assert( 'array' == type ? isArray(this.obj) : 'regexp' == type ? isRegExp(this.obj) : 'object' == type ? 'object' == typeof this.obj && null !== this.obj : type == typeof this.obj , function(){ return 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type } , function(){ return 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type }); } else { // instanceof var name = type.name || 'supplied constructor'; this.assert( this.obj instanceof type , function(){ return 'expected ' + i(this.obj) + ' to be an instance of ' + name } , function(){ return 'expected ' + i(this.obj) + ' not to be an instance of ' + name }); } return this; }; /** * Assert numeric value above _n_. * * @param {Number} n * @api public */ Assertion.prototype.greaterThan = Assertion.prototype.above = function (n) { this.assert( this.obj > n , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n } , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n }); return this; }; /** * Assert numeric value below _n_. * * @param {Number} n * @api public */ Assertion.prototype.lessThan = Assertion.prototype.below = function (n) { this.assert( this.obj < n , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n } , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n }); return this; }; /** * Assert string value matches _regexp_. * * @param {RegExp} regexp * @api public */ Assertion.prototype.match = function (regexp) { this.assert( regexp.exec(this.obj) , function(){ return 'expected ' + i(this.obj) + ' to match ' + regexp } , function(){ return 'expected ' + i(this.obj) + ' not to match ' + regexp }); return this; }; /** * Assert property "length" exists and has value of _n_. * * @param {Number} n * @api public */ Assertion.prototype.length = function (n) { expect(this.obj).to.have.property('length'); var len = this.obj.length; this.assert( n == len , function(){ return 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len } , function(){ return 'expected ' + i(this.obj) + ' to not have a length of ' + len }); return this; }; /** * Assert property _name_ exists, with optional _val_. * * @param {String} name * @param {Mixed} val * @api public */ Assertion.prototype.property = function (name, val) { if (this.flags.own) { this.assert( Object.prototype.hasOwnProperty.call(this.obj, name) , function(){ return 'expected ' + i(this.obj) + ' to have own property ' + i(name) } , function(){ return 'expected ' + i(this.obj) + ' to not have own property ' + i(name) }); return this; } if (this.flags.not && undefined !== val) { if (undefined === this.obj[name]) { throw new Error(i(this.obj) + ' has no property ' + i(name)); } } else { var hasProp; try { hasProp = name in this.obj } catch (e) { hasProp = undefined !== this.obj[name] } this.assert( hasProp , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) } , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) }); } if (undefined !== val) { this.assert( val === this.obj[name] , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) + ' of ' + i(val) + ', but got ' + i(this.obj[name]) } , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) + ' of ' + i(val) }); } this.obj = this.obj[name]; return this; }; /** * Assert that the array contains _obj_ or string contains _obj_. * * @param {Mixed} obj|string * @api public */ Assertion.prototype.string = Assertion.prototype.contain = function (obj) { if ('string' == typeof this.obj) { this.assert( ~this.obj.indexOf(obj) , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) } , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) }); } else { this.assert( ~indexOf(this.obj, obj) , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) } , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) }); } return this; }; /** * Assert exact keys or inclusion of keys by using * the `.own` modifier. * * @param {Array|String ...} keys * @api public */ Assertion.prototype.key = Assertion.prototype.keys = function ($keys) { var str , ok = true; $keys = isArray($keys) ? $keys : Array.prototype.slice.call(arguments); if (!$keys.length) throw new Error('keys required'); var actual = keys(this.obj) , len = $keys.length; // Inclusion ok = every($keys, function (key) { return ~indexOf(actual, key); }); // Strict if (!this.flags.not && this.flags.only) { ok = ok && $keys.length == actual.length; } // Key string if (len > 1) { $keys = map($keys, function (key) { return i(key); }); var last = $keys.pop(); str = $keys.join(', ') + ', and ' + last; } else { str = i($keys[0]); } // Form str = (len > 1 ? 'keys ' : 'key ') + str; // Have / include str = (!this.flags.only ? 'include ' : 'only have ') + str; // Assertion this.assert( ok , function(){ return 'expected ' + i(this.obj) + ' to ' + str } , function(){ return 'expected ' + i(this.obj) + ' to not ' + str }); return this; }; /** * Assert a failure. * * @param {String ...} custom message * @api public */ Assertion.prototype.fail = function (msg) { var error = function() { return msg || "explicit failure"; } this.assert(false, error, error); return this; }; /** * Function bind implementation. */ function bind (fn, scope) { return function () { return fn.apply(scope, arguments); } } /** * Array every compatibility * * @see bit.ly/5Fq1N2 * @api public */ function every (arr, fn, thisObj) { var scope = thisObj || global; for (var i = 0, j = arr.length; i < j; ++i) { if (!fn.call(scope, arr[i], i, arr)) { return false; } } return true; } /** * Array indexOf compatibility. * * @see bit.ly/a5Dxa2 * @api public */ function indexOf (arr, o, i) { if (Array.prototype.indexOf) { return Array.prototype.indexOf.call(arr, o, i); } if (arr.length === undefined) { return -1; } for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0 ; i < j && arr[i] !== o; i++); return j <= i ? -1 : i; } // https://gist.github.com/1044128/ var getOuterHTML = function(element) { if ('outerHTML' in element) return element.outerHTML; var ns = "http://www.w3.org/1999/xhtml"; var container = document.createElementNS(ns, '_'); var xmlSerializer = new XMLSerializer(); var html; if (document.xmlVersion) { return xmlSerializer.serializeToString(element); } else { container.appendChild(element.cloneNode(false)); html = container.innerHTML.replace('><', '>' + element.innerHTML + '<'); container.innerHTML = ''; return html; } }; // Returns true if object is a DOM element. var isDOMElement = function (object) { if (typeof HTMLElement === 'object') { return object instanceof HTMLElement; } else { return object && typeof object === 'object' && object.nodeType === 1 && typeof object.nodeName === 'string'; } }; /** * Inspects an object. * * @see taken from node.js `util` module (copyright Joyent, MIT license) * @api private */ function i (obj, showHidden, depth) { var seen = []; function stylize (str) { return str; } function format (value, recurseTimes) { // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it if (value && typeof value.inspect === 'function' && // Filter out the util module, it's inspect function is special value !== exports && // Also filter out any prototype objects using the circular check. !(value.constructor && value.constructor.prototype === value)) { return value.inspect(recurseTimes); } // Primitive types cannot have properties switch (typeof value) { case 'undefined': return stylize('undefined', 'undefined'); case 'string': var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; return stylize(simple, 'string'); case 'number': return stylize('' + value, 'number'); case 'boolean': return stylize('' + value, 'boolean'); } // For some reason typeof null is "object", so special case here. if (value === null) { return stylize('null', 'null'); } if (isDOMElement(value)) { return getOuterHTML(value); } // Look up the keys of the object. var visible_keys = keys(value); var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys; // Functions without properties can be shortcutted. if (typeof value === 'function' && $keys.length === 0) { if (isRegExp(value)) { return stylize('' + value, 'regexp'); } else { var name = value.name ? ': ' + value.name : ''; return stylize('[Function' + name + ']', 'special'); } } // Dates without properties can be shortcutted if (isDate(value) && $keys.length === 0) { return stylize(value.toUTCString(), 'date'); } // Error objects can be shortcutted if (value instanceof Error) { return stylize("["+value.toString()+"]", 'Error'); } var base, type, braces; // Determine the object type if (isArray(value)) { type = 'Array'; braces = ['[', ']']; } else { type = 'Object'; braces = ['{', '}']; } // Make functions say that they are functions if (typeof value === 'function') { var n = value.name ? ': ' + value.name : ''; base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; } else { base = ''; } // Make dates with properties first say the date if (isDate(value)) { base = ' ' + value.toUTCString(); } if ($keys.length === 0) { return braces[0] + base + braces[1]; } if (recurseTimes < 0) { if (isRegExp(value)) { return stylize('' + value, 'regexp'); } else { return stylize('[Object]', 'special'); } } seen.push(value); var output = map($keys, function (key) { var name, str; if (value.__lookupGetter__) { if (value.__lookupGetter__(key)) { if (value.__lookupSetter__(key)) { str = stylize('[Getter/Setter]', 'special'); } else { str = stylize('[Getter]', 'special'); } } else { if (value.__lookupSetter__(key)) { str = stylize('[Setter]', 'special'); } } } if (indexOf(visible_keys, key) < 0) { name = '[' + key + ']'; } if (!str) { if (indexOf(seen, value[key]) < 0) { if (recurseTimes === null) { str = format(value[key]); } else { str = format(value[key], recurseTimes - 1); } if (str.indexOf('\n') > -1) { if (isArray(value)) { str = map(str.split('\n'), function (line) { return ' ' + line; }).join('\n').substr(2); } else { str = '\n' + map(str.split('\n'), function (line) { return ' ' + line; }).join('\n'); } } } else { str = stylize('[Circular]', 'special'); } } if (typeof name === 'undefined') { if (type === '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 = stylize(name, 'name'); } else { name = name.replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'"); name = stylize(name, 'string'); } } return name + ': ' + str; }); seen.pop(); var numLinesEst = 0; var length = reduce(output, function (prev, cur) { numLinesEst++; if (indexOf(cur, '\n') >= 0) numLinesEst++; return prev + cur.length + 1; }, 0); if (length > 50) { output = braces[0] + (base === '' ? '' : base + '\n ') + ' ' + output.join(',\n ') + ' ' + braces[1]; } else { output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } return output; } return format(obj, (typeof depth === 'undefined' ? 2 : depth)); } expect.stringify = i; function isArray (ar) { return Object.prototype.toString.call(ar) === '[object Array]'; } function isRegExp(re) { var s; try { s = '' + re; } catch (e) { return false; } return re instanceof RegExp || // easy case // duck-type for context-switching evalcx case typeof(re) === 'function' && re.constructor.name === 'RegExp' && re.compile && re.test && re.exec && s.match(/^\/.*\/[gim]{0,3}$/); } function isDate(d) { return d instanceof Date; } function keys (obj) { if (Object.keys) { return Object.keys(obj); } var keys = []; for (var i in obj) { if (Object.prototype.hasOwnProperty.call(obj, i)) { keys.push(i); } } return keys; } function map (arr, mapper, that) { if (Array.prototype.map) { return Array.prototype.map.call(arr, mapper, that); } var other= new Array(arr.length); for (var i= 0, n = arr.length; i= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) rv = fun.call(null, rv, this[i], i, this); } return rv; } /** * Asserts deep equality * * @see taken from node.js `assert` module (copyright Joyent, MIT license) * @api private */ expect.eql = function eql(actual, expected) { // 7.1. All identical values are equivalent, as determined by ===. if (actual === expected) { return true; } else if ('undefined' != typeof Buffer && Buffer.isBuffer(actual) && Buffer.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 (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 actual == expected; // If both are regular expression use the special `regExpEquiv` method // to determine equivalence. } else if (isRegExp(actual) && isRegExp(expected)) { return regExpEquiv(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); } }; function isUndefinedOrNull (value) { return value === null || value === undefined; } function isArguments (object) { return Object.prototype.toString.call(object) == '[object Arguments]'; } function regExpEquiv (a, b) { return a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; } function objEquiv (a, b) { 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 expect.eql(a, b); } try{ var ka = keys(a), kb = keys(b), key, i; } 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 (!expect.eql(a[key], b[key])) return false; } return true; } var json = (function () { "use strict"; if ('object' == typeof JSON && JSON.parse && JSON.stringify) { return { parse: nativeJSON.parse , stringify: nativeJSON.stringify } } var JSON = {}; function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } function date(d, key) { return isFinite(d.valueOf()) ? d.getUTCFullYear() + '-' + f(d.getUTCMonth() + 1) + '-' + f(d.getUTCDate()) + 'T' + f(d.getUTCHours()) + ':' + f(d.getUTCMinutes()) + ':' + f(d.getUTCSeconds()) + 'Z' : null; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { // table of character substitutions '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }, rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { // Produce a string from holder[key]. var i, // The loop counter. k, // The member key. v, // The member value. length, mind = gap, partial, value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value instanceof Date) { value = date(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === 'function') { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case 'string': return quote(value); case 'number': // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce 'null'. The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is 'object', we might be dealing with an object or an array or // null. case 'object': // Due to a specification blunder in ECMAScript, typeof null is 'object', // so watch out for that case. if (!value) { return 'null'; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === '[object Array]') { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { if (typeof rep[i] === 'string') { k = rep[i]; v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ''; indent = ''; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === 'string') { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } // Make a fake root object containing our value under the key of ''. // Return the result of stringifying the value. return str('', {'': value}); }; // If the JSON object does not yet have a parse method, give it one. JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with '()' and 'new' // because they can cause invocation, and '=' because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we // replace all simple value tokens with ']' characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or ']' or // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. if (/^[\],:{}\s]*$/ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The '{' operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval('(' + text + ')'); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return typeof reviver === 'function' ? walk({'': j}, '') : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError('JSON.parse'); }; return JSON; })(); if ('undefined' != typeof window) { window.expect = module.exports; } })( this , 'undefined' != typeof module ? module : {exports: {}} ); ================================================ FILE: test/browser/index.html ================================================ Mocha
================================================ FILE: test/browser/mocha.css ================================================ @charset "utf-8"; body { margin:0; } #mocha { font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; margin: 60px 50px; } #mocha ul, #mocha li { margin: 0; padding: 0; } #mocha ul { list-style: none; } #mocha h1, #mocha h2 { margin: 0; } #mocha h1 { margin-top: 15px; font-size: 1em; font-weight: 200; } #mocha h1 a { text-decoration: none; color: inherit; } #mocha h1 a:hover { text-decoration: underline; } #mocha .suite .suite h1 { margin-top: 0; font-size: .8em; } #mocha .hidden { display: none; } #mocha h2 { font-size: 12px; font-weight: normal; cursor: pointer; } #mocha .suite { margin-left: 15px; } #mocha .test { margin-left: 15px; overflow: hidden; } #mocha .test.pending:hover h2::after { content: '(pending)'; font-family: arial, sans-serif; } #mocha .test.pass.medium .duration { background: #c09853; } #mocha .test.pass.slow .duration { background: #b94a48; } #mocha .test.pass::before { content: '✓'; font-size: 12px; display: block; float: left; margin-right: 5px; color: #00d6b2; } #mocha .test.pass .duration { font-size: 9px; margin-left: 5px; padding: 2px 5px; color: #fff; -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); box-shadow: inset 0 1px 1px rgba(0,0,0,.2); -webkit-border-radius: 5px; -moz-border-radius: 5px; -ms-border-radius: 5px; -o-border-radius: 5px; border-radius: 5px; } #mocha .test.pass.fast .duration { display: none; } #mocha .test.pending { color: #0b97c4; } #mocha .test.pending::before { content: '◦'; color: #0b97c4; } #mocha .test.fail { color: #c00; } #mocha .test.fail pre { color: black; } #mocha .test.fail::before { content: '✖'; font-size: 12px; display: block; float: left; margin-right: 5px; color: #c00; } #mocha .test pre.error { color: #c00; max-height: 300px; overflow: auto; } #mocha .test .html-error { overflow: auto; color: black; line-height: 1.5; display: block; float: left; clear: left; font: 12px/1.5 monaco, monospace; margin: 5px; padding: 15px; border: 1px solid #eee; max-width: 85%; /*(1)*/ max-width: calc(100% - 42px); /*(2)*/ max-height: 300px; word-wrap: break-word; border-bottom-color: #ddd; -webkit-border-radius: 3px; -webkit-box-shadow: 0 1px 3px #eee; -moz-border-radius: 3px; -moz-box-shadow: 0 1px 3px #eee; border-radius: 3px; } #mocha .test .html-error pre.error { border: none; -webkit-border-radius: none; -webkit-box-shadow: none; -moz-border-radius: none; -moz-box-shadow: none; padding: 0; margin: 0; margin-top: 18px; max-height: none; } /** * (1): approximate for browsers not supporting calc * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) * ^^ seriously */ #mocha .test pre { display: block; float: left; clear: left; font: 12px/1.5 monaco, monospace; margin: 5px; padding: 15px; border: 1px solid #eee; max-width: 85%; /*(1)*/ max-width: calc(100% - 42px); /*(2)*/ word-wrap: break-word; border-bottom-color: #ddd; -webkit-border-radius: 3px; -webkit-box-shadow: 0 1px 3px #eee; -moz-border-radius: 3px; -moz-box-shadow: 0 1px 3px #eee; border-radius: 3px; } #mocha .test h2 { position: relative; } #mocha .test a.replay { position: absolute; top: 3px; right: 0; text-decoration: none; vertical-align: middle; display: block; width: 15px; height: 15px; line-height: 15px; text-align: center; background: #eee; font-size: 15px; -moz-border-radius: 15px; border-radius: 15px; -webkit-transition: opacity 200ms; -moz-transition: opacity 200ms; transition: opacity 200ms; opacity: 0.3; color: #888; } #mocha .test:hover a.replay { opacity: 1; } #mocha-report.pass .test.fail { display: none; } #mocha-report.fail .test.pass { display: none; } #mocha-report.pending .test.pass, #mocha-report.pending .test.fail { display: none; } #mocha-report.pending .test.pass.pending { display: block; } #mocha-error { color: #c00; font-size: 1.5em; font-weight: 100; letter-spacing: 1px; } #mocha-stats { position: fixed; top: 15px; right: 10px; font-size: 12px; margin: 0; color: #888; z-index: 1; } #mocha-stats .progress { float: right; padding-top: 0; } #mocha-stats em { color: black; } #mocha-stats a { text-decoration: none; color: inherit; } #mocha-stats a:hover { border-bottom: 1px solid #eee; } #mocha-stats li { display: inline-block; margin: 0 5px; list-style: none; padding-top: 11px; } #mocha-stats canvas { width: 40px; height: 40px; } #mocha code .comment { color: #ddd; } #mocha code .init { color: #2f6fad; } #mocha code .string { color: #5890ad; } #mocha code .keyword { color: #8a6343; } #mocha code .number { color: #2f6fad; } @media screen and (max-device-width: 480px) { #mocha { margin: 60px 0px; } #mocha #stats { position: absolute; } } ================================================ FILE: test/browser/mocha.js ================================================ (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 1) { suites.shift(); } var suite = Suite.create(suites[0], title); suite.file = file; suites.unshift(suite); return suite; }; /** * Exclusive test-case. */ context.suite.only = function(title, fn) { var suite = context.suite(title, fn); mocha.grep(suite.fullTitle()); }; /** * Describe a specification or test-case * with the given `title` and callback `fn` * acting as a thunk. */ context.test = function(title, fn) { var test = new Test(title, fn); test.file = file; suites[0].addTest(test); return test; }; /** * Exclusive test-case. */ context.test.only = function(title, fn) { var test = context.test(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); }; context.test.skip = common.test.skip; }); }; },{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":68}],13:[function(require,module,exports){ /** * Module dependencies. */ var Suite = require('../suite'); var Test = require('../test'); var escapeRe = require('escape-string-regexp'); /** * TDD-style interface: * * suite('Array', function() { * suite('#indexOf()', function() { * suiteSetup(function() { * * }); * * test('should return -1 when not present', function() { * * }); * * test('should return the index when present', function() { * * }); * * suiteTeardown(function() { * * }); * }); * }); * * @param {Suite} suite Root suite. */ module.exports = function(suite) { var suites = [suite]; suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context); context.setup = common.beforeEach; context.teardown = common.afterEach; context.suiteSetup = common.before; context.suiteTeardown = common.after; context.run = mocha.options.delay && common.runWithSuite(suite); /** * Describe a "suite" with the given `title` and callback `fn` containing * nested suites and/or tests. */ context.suite = function(title, fn) { var suite = Suite.create(suites[0], title); suite.file = file; suites.unshift(suite); fn.call(suite); suites.shift(); return suite; }; /** * Pending suite. */ context.suite.skip = function(title, fn) { var suite = Suite.create(suites[0], title); suite.pending = true; suites.unshift(suite); fn.call(suite); suites.shift(); }; /** * Exclusive test-case. */ context.suite.only = function(title, fn) { var suite = context.suite(title, fn); mocha.grep(suite.fullTitle()); }; /** * Describe a specification or test-case with the given `title` and * callback `fn` acting as a thunk. */ context.test = function(title, fn) { var suite = suites[0]; if (suite.pending) { fn = null; } var test = new Test(title, fn); test.file = file; suite.addTest(test); return test; }; /** * Exclusive test-case. */ context.test.only = function(title, fn) { var test = context.test(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); }; context.test.skip = common.test.skip; }); }; },{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":68}],14:[function(require,module,exports){ (function (process,global,__dirname){ /*! * mocha * Copyright(c) 2011 TJ Holowaychuk * MIT Licensed */ /** * Module dependencies. */ var escapeRe = require('escape-string-regexp'); var path = require('path'); var reporters = require('./reporters'); var utils = require('./utils'); /** * Expose `Mocha`. */ exports = module.exports = Mocha; /** * To require local UIs and reporters when running in node. */ if (!process.browser) { var cwd = process.cwd(); module.paths.push(cwd, path.join(cwd, 'node_modules')); } /** * Expose internals. */ exports.utils = utils; exports.interfaces = require('./interfaces'); exports.reporters = reporters; exports.Runnable = require('./runnable'); exports.Context = require('./context'); exports.Runner = require('./runner'); exports.Suite = require('./suite'); exports.Hook = require('./hook'); exports.Test = require('./test'); /** * Return image `name` path. * * @api private * @param {string} name * @return {string} */ function image(name) { return path.join(__dirname, '../images', name + '.png'); } /** * Set up mocha with `options`. * * Options: * * - `ui` name "bdd", "tdd", "exports" etc * - `reporter` reporter instance, defaults to `mocha.reporters.spec` * - `globals` array of accepted globals * - `timeout` timeout in milliseconds * - `bail` bail on the first test failure * - `slow` milliseconds to wait before considering a test slow * - `ignoreLeaks` ignore global leaks * - `fullTrace` display the full stack-trace on failing * - `grep` string or regexp to filter tests with * * @param {Object} options * @api public */ function Mocha(options) { options = options || {}; this.files = []; this.options = options; if (options.grep) { this.grep(new RegExp(options.grep)); } if (options.fgrep) { this.grep(options.fgrep); } this.suite = new exports.Suite('', new exports.Context()); this.ui(options.ui); this.bail(options.bail); this.reporter(options.reporter, options.reporterOptions); if (typeof options.timeout !== 'undefined' && options.timeout !== null) { this.timeout(options.timeout); } this.useColors(options.useColors); if (options.enableTimeouts !== null) { this.enableTimeouts(options.enableTimeouts); } if (options.slow) { this.slow(options.slow); } this.suite.on('pre-require', function(context) { exports.afterEach = context.afterEach || context.teardown; exports.after = context.after || context.suiteTeardown; exports.beforeEach = context.beforeEach || context.setup; exports.before = context.before || context.suiteSetup; exports.describe = context.describe || context.suite; exports.it = context.it || context.test; exports.setup = context.setup || context.beforeEach; exports.suiteSetup = context.suiteSetup || context.before; exports.suiteTeardown = context.suiteTeardown || context.after; exports.suite = context.suite || context.describe; exports.teardown = context.teardown || context.afterEach; exports.test = context.test || context.it; exports.run = context.run; }); } /** * Enable or disable bailing on the first failure. * * @api public * @param {boolean} [bail] */ Mocha.prototype.bail = function(bail) { if (!arguments.length) { bail = true; } this.suite.bail(bail); return this; }; /** * Add test `file`. * * @api public * @param {string} file */ Mocha.prototype.addFile = function(file) { this.files.push(file); return this; }; /** * Set reporter to `reporter`, defaults to "spec". * * @param {String|Function} reporter name or constructor * @param {Object} reporterOptions optional options * @api public * @param {string|Function} reporter name or constructor * @param {Object} reporterOptions optional options */ Mocha.prototype.reporter = function(reporter, reporterOptions) { if (typeof reporter === 'function') { this._reporter = reporter; } else { reporter = reporter || 'spec'; var _reporter; // Try to load a built-in reporter. if (reporters[reporter]) { _reporter = reporters[reporter]; } // Try to load reporters from process.cwd() and node_modules if (!_reporter) { try { _reporter = require(reporter); } catch (err) { err.message.indexOf('Cannot find module') !== -1 ? console.warn('"' + reporter + '" reporter not found') : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); } } if (!_reporter && reporter === 'teamcity') { console.warn('The Teamcity reporter was moved to a package named ' + 'mocha-teamcity-reporter ' + '(https://npmjs.org/package/mocha-teamcity-reporter).'); } if (!_reporter) { throw new Error('invalid reporter "' + reporter + '"'); } this._reporter = _reporter; } this.options.reporterOptions = reporterOptions; return this; }; /** * Set test UI `name`, defaults to "bdd". * * @api public * @param {string} bdd */ Mocha.prototype.ui = function(name) { name = name || 'bdd'; this._ui = exports.interfaces[name]; if (!this._ui) { try { this._ui = require(name); } catch (err) { throw new Error('invalid interface "' + name + '"'); } } this._ui = this._ui(this.suite); return this; }; /** * Load registered files. * * @api private */ Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; var pending = this.files.length; this.files.forEach(function(file) { file = path.resolve(file); suite.emit('pre-require', global, file, self); suite.emit('require', require(file), file, self); suite.emit('post-require', global, file, self); --pending || (fn && fn()); }); }; /** * Enable growl support. * * @api private */ Mocha.prototype._growl = function(runner, reporter) { var notify = require('growl'); runner.on('end', function() { var stats = reporter.stats; if (stats.failures) { var msg = stats.failures + ' of ' + runner.total + ' tests failed'; notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); } else { notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { name: 'mocha', title: 'Passed', image: image('ok') }); } }); }; /** * Add regexp to grep, if `re` is a string it is escaped. * * @param {RegExp|String} re * @return {Mocha} * @api public * @param {RegExp|string} re * @return {Mocha} */ Mocha.prototype.grep = function(re) { this.options.grep = typeof re === 'string' ? new RegExp(escapeRe(re)) : re; return this; }; /** * Invert `.grep()` matches. * * @return {Mocha} * @api public */ Mocha.prototype.invert = function() { this.options.invert = true; return this; }; /** * Ignore global leaks. * * @param {Boolean} ignore * @return {Mocha} * @api public * @param {boolean} ignore * @return {Mocha} */ Mocha.prototype.ignoreLeaks = function(ignore) { this.options.ignoreLeaks = Boolean(ignore); return this; }; /** * Enable global leak checking. * * @return {Mocha} * @api public */ Mocha.prototype.checkLeaks = function() { this.options.ignoreLeaks = false; return this; }; /** * Display long stack-trace on failing * * @return {Mocha} * @api public */ Mocha.prototype.fullTrace = function() { this.options.fullStackTrace = true; return this; }; /** * Enable growl support. * * @return {Mocha} * @api public */ Mocha.prototype.growl = function() { this.options.growl = true; return this; }; /** * Ignore `globals` array or string. * * @param {Array|String} globals * @return {Mocha} * @api public * @param {Array|string} globals * @return {Mocha} */ Mocha.prototype.globals = function(globals) { this.options.globals = (this.options.globals || []).concat(globals); return this; }; /** * Emit color output. * * @param {Boolean} colors * @return {Mocha} * @api public * @param {boolean} colors * @return {Mocha} */ Mocha.prototype.useColors = function(colors) { if (colors !== undefined) { this.options.useColors = colors; } return this; }; /** * Use inline diffs rather than +/-. * * @param {Boolean} inlineDiffs * @return {Mocha} * @api public * @param {boolean} inlineDiffs * @return {Mocha} */ Mocha.prototype.useInlineDiffs = function(inlineDiffs) { this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; return this; }; /** * Set the timeout in milliseconds. * * @param {Number} timeout * @return {Mocha} * @api public * @param {number} timeout * @return {Mocha} */ Mocha.prototype.timeout = function(timeout) { this.suite.timeout(timeout); return this; }; /** * Set slowness threshold in milliseconds. * * @param {Number} slow * @return {Mocha} * @api public * @param {number} slow * @return {Mocha} */ Mocha.prototype.slow = function(slow) { this.suite.slow(slow); return this; }; /** * Enable timeouts. * * @param {Boolean} enabled * @return {Mocha} * @api public * @param {boolean} enabled * @return {Mocha} */ Mocha.prototype.enableTimeouts = function(enabled) { this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); return this; }; /** * Makes all tests async (accepting a callback) * * @return {Mocha} * @api public */ Mocha.prototype.asyncOnly = function() { this.options.asyncOnly = true; return this; }; /** * Disable syntax highlighting (in browser). * * @api public */ Mocha.prototype.noHighlighting = function() { this.options.noHighlighting = true; return this; }; /** * Enable uncaught errors to propagate (in browser). * * @return {Mocha} * @api public */ Mocha.prototype.allowUncaught = function() { this.options.allowUncaught = true; return this; }; /** * Delay root suite execution. * @returns {Mocha} */ Mocha.prototype.delay = function delay() { this.options.delay = true; return this; }; /** * Run tests and invoke `fn()` when complete. * * @api public * @param {Function} fn * @return {Runner} */ Mocha.prototype.run = function(fn) { if (this.files.length) { this.loadFiles(); } var suite = this.suite; var options = this.options; options.files = this.files; var runner = new exports.Runner(suite, options.delay); var reporter = new this._reporter(runner, options); runner.ignoreLeaks = options.ignoreLeaks !== false; runner.fullStackTrace = options.fullStackTrace; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; if (options.grep) { runner.grep(options.grep, options.invert); } if (options.globals) { runner.globals(options.globals); } if (options.growl) { this._growl(runner, reporter); } if (options.useColors !== undefined) { exports.reporters.Base.useColors = options.useColors; } exports.reporters.Base.inlineDiffs = options.useInlineDiffs; function done(failures) { if (reporter.done) { reporter.done(failures, fn); } else { fn && fn(failures); } } return runner.run(done); }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") },{"./context":6,"./hook":7,"./interfaces":11,"./reporters":22,"./runnable":35,"./runner":36,"./suite":37,"./test":38,"./utils":39,"_process":51,"escape-string-regexp":68,"growl":69,"path":41}],15:[function(require,module,exports){ /** * Helpers. */ var s = 1000; var m = s * 60; var h = m * 60; var d = h * 24; var y = d * 365.25; /** * Parse or format the given `val`. * * Options: * * - `long` verbose formatting [false] * * @api public * @param {string|number} val * @param {Object} options * @return {string|number} */ module.exports = function(val, options) { options = options || {}; if (typeof val === 'string') { return parse(val); } // https://github.com/mochajs/mocha/pull/1035 return options['long'] ? longFormat(val) : shortFormat(val); }; /** * Parse the given `str` and return milliseconds. * * @api private * @param {string} str * @return {number} */ function parse(str) { var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); if (!match) { return; } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { case 'years': case 'year': case 'y': return n * y; case 'days': case 'day': case 'd': return n * d; case 'hours': case 'hour': case 'h': return n * h; case 'minutes': case 'minute': case 'm': return n * m; case 'seconds': case 'second': case 's': return n * s; case 'ms': return n; default: // No default case } } /** * Short format for `ms`. * * @api private * @param {number} ms * @return {string} */ function shortFormat(ms) { if (ms >= d) { return Math.round(ms / d) + 'd'; } if (ms >= h) { return Math.round(ms / h) + 'h'; } if (ms >= m) { return Math.round(ms / m) + 'm'; } if (ms >= s) { return Math.round(ms / s) + 's'; } return ms + 'ms'; } /** * Long format for `ms`. * * @api private * @param {number} ms * @return {string} */ function longFormat(ms) { return plural(ms, d, 'day') || plural(ms, h, 'hour') || plural(ms, m, 'minute') || plural(ms, s, 'second') || ms + ' ms'; } /** * Pluralization helper. * * @api private * @param {number} ms * @param {number} n * @param {string} name */ function plural(ms, n, name) { if (ms < n) { return; } if (ms < n * 1.5) { return Math.floor(ms / n) + ' ' + name; } return Math.ceil(ms / n) + ' ' + name + 's'; } },{}],16:[function(require,module,exports){ /** * Expose `Pending`. */ module.exports = Pending; /** * Initialize a new `Pending` error with the given message. * * @param {string} message */ function Pending(message) { this.message = message; } },{}],17:[function(require,module,exports){ (function (process,global){ /** * Module dependencies. */ var tty = require('tty'); var diff = require('diff'); var ms = require('../ms'); var utils = require('../utils'); var supportsColor = process.browser ? null : require('supports-color'); /** * Expose `Base`. */ exports = module.exports = Base; /** * Save timer references to avoid Sinon interfering. * See: https://github.com/mochajs/mocha/issues/237 */ /* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; /* eslint-enable no-unused-vars, no-native-reassign */ /** * Check if both stdio streams are associated with a tty. */ var isatty = tty.isatty(1) && tty.isatty(2); /** * Enable coloring by default, except in the browser interface. */ exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined)); /** * Inline diffs instead of +/- */ exports.inlineDiffs = false; /** * Default color map. */ exports.colors = { pass: 90, fail: 31, 'bright pass': 92, 'bright fail': 91, 'bright yellow': 93, pending: 36, suite: 0, 'error title': 0, 'error message': 31, 'error stack': 90, checkmark: 32, fast: 90, medium: 33, slow: 31, green: 32, light: 90, 'diff gutter': 90, 'diff added': 32, 'diff removed': 31 }; /** * Default symbol map. */ exports.symbols = { ok: '✓', err: '✖', dot: '․' }; // With node.js on Windows: use symbols available in terminal default fonts if (process.platform === 'win32') { exports.symbols.ok = '\u221A'; exports.symbols.err = '\u00D7'; exports.symbols.dot = '.'; } /** * Color `str` with the given `type`, * allowing colors to be disabled, * as well as user-defined color * schemes. * * @param {string} type * @param {string} str * @return {string} * @api private */ var color = exports.color = function(type, str) { if (!exports.useColors) { return String(str); } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; }; /** * Expose term window size, with some defaults for when stderr is not a tty. */ exports.window = { width: 75 }; if (isatty) { exports.window.width = process.stdout.getWindowSize ? process.stdout.getWindowSize(1)[0] : tty.getWindowSize()[1]; } /** * Expose some basic cursor interactions that are common among reporters. */ exports.cursor = { hide: function() { isatty && process.stdout.write('\u001b[?25l'); }, show: function() { isatty && process.stdout.write('\u001b[?25h'); }, deleteLine: function() { isatty && process.stdout.write('\u001b[2K'); }, beginningOfLine: function() { isatty && process.stdout.write('\u001b[0G'); }, CR: function() { if (isatty) { exports.cursor.deleteLine(); exports.cursor.beginningOfLine(); } else { process.stdout.write('\r'); } } }; /** * Outut the given `failures` as a list. * * @param {Array} failures * @api public */ exports.list = function(failures) { console.log(); failures.forEach(function(test, i) { // format var fmt = color('error title', ' %s) %s:\n') + color('error message', ' %s') + color('error stack', '\n%s\n'); // msg var msg; var err = test.err; var message; if (err.message) { message = err.message; } else if (typeof err.inspect === 'function') { message = err.inspect() + ''; } else { message = ''; } var stack = err.stack || message; var index = stack.indexOf(message); var actual = err.actual; var expected = err.expected; var escape = true; if (index === -1) { msg = message; } else { index += message.length; msg = stack.slice(0, index); // remove msg from stack stack = stack.slice(index + 1); } // uncaught if (err.uncaught) { msg = 'Uncaught ' + msg; } // explicitly show diff if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { escape = false; if (!(utils.isString(actual) && utils.isString(expected))) { err.actual = actual = utils.stringify(actual); err.expected = expected = utils.stringify(expected); } fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); var match = message.match(/^([^:]+): expected/); msg = '\n ' + color('error message', match ? match[1] : msg); if (exports.inlineDiffs) { msg += inlineDiff(err, escape); } else { msg += unifiedDiff(err, escape); } } // indent stack trace stack = stack.replace(/^/gm, ' '); console.log(fmt, (i + 1), test.fullTitle(), msg, stack); }); }; /** * Initialize a new `Base` reporter. * * All other reporters generally * inherit from this reporter, providing * stats such as test duration, number * of tests passed / failed etc. * * @param {Runner} runner * @api public */ function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } this.runner = runner; runner.stats = stats; runner.on('start', function() { stats.start = new Date(); }); runner.on('suite', function(suite) { stats.suites = stats.suites || 0; suite.root || stats.suites++; }); runner.on('test end', function() { stats.tests = stats.tests || 0; stats.tests++; }); runner.on('pass', function(test) { stats.passes = stats.passes || 0; if (test.duration > test.slow()) { test.speed = 'slow'; } else if (test.duration > test.slow() / 2) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function(test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function() { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function() { stats.pending++; }); } /** * Output common epilogue used by many of * the bundled reporters. * * @api public */ Base.prototype.epilogue = function() { var stats = this.stats; var fmt; console.log(); // passes fmt = color('bright pass', ' ') + color('green', ' %d passing') + color('light', ' (%s)'); console.log(fmt, stats.passes || 0, ms(stats.duration)); // pending if (stats.pending) { fmt = color('pending', ' ') + color('pending', ' %d pending'); console.log(fmt, stats.pending); } // failures if (stats.failures) { fmt = color('fail', ' %d failing'); console.log(fmt, stats.failures); Base.list(this.failures); console.log(); } console.log(); }; /** * Pad the given `str` to `len`. * * @api private * @param {string} str * @param {string} len * @return {string} */ function pad(str, len) { str = String(str); return Array(len - str.length + 1).join(' ') + str; } /** * Returns an inline diff between 2 strings with coloured ANSI output * * @api private * @param {Error} err with actual/expected * @param {boolean} escape * @return {string} Diff */ function inlineDiff(err, escape) { var msg = errorDiff(err, 'WordsWithSpace', escape); // linenos var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; msg = lines.map(function(str, i) { return pad(++i, width) + ' |' + ' ' + str; }).join('\n'); } // legend msg = '\n' + color('diff removed', 'actual') + ' ' + color('diff added', 'expected') + '\n\n' + msg + '\n'; // indent msg = msg.replace(/^/gm, ' '); return msg; } /** * Returns a unified diff between two strings. * * @api private * @param {Error} err with actual/expected * @param {boolean} escape * @return {string} The diff. */ function unifiedDiff(err, escape) { var indent = ' '; function cleanUp(line) { if (escape) { line = escapeInvisibles(line); } if (line[0] === '+') { return indent + colorLines('diff added', line); } if (line[0] === '-') { return indent + colorLines('diff removed', line); } if (line.match(/\@\@/)) { return null; } if (line.match(/\\ No newline/)) { return null; } return indent + line; } function notBlank(line) { return typeof line !== 'undefined' && line !== null; } var msg = diff.createPatch('string', err.actual, err.expected); var lines = msg.split('\n').splice(4); return '\n ' + colorLines('diff added', '+ expected') + ' ' + colorLines('diff removed', '- actual') + '\n\n' + lines.map(cleanUp).filter(notBlank).join('\n'); } /** * Return a character diff for `err`. * * @api private * @param {Error} err * @param {string} type * @param {boolean} escape * @return {string} */ function errorDiff(err, type, escape) { var actual = escape ? escapeInvisibles(err.actual) : err.actual; var expected = escape ? escapeInvisibles(err.expected) : err.expected; return diff['diff' + type](actual, expected).map(function(str) { if (str.added) { return colorLines('diff added', str.value); } if (str.removed) { return colorLines('diff removed', str.value); } return str.value; }).join(''); } /** * Returns a string with all invisible characters in plain text * * @api private * @param {string} line * @return {string} */ function escapeInvisibles(line) { return line.replace(/\t/g, '') .replace(/\r/g, '') .replace(/\n/g, '\n'); } /** * Color lines for `str`, using the color `name`. * * @api private * @param {string} name * @param {string} str * @return {string} */ function colorLines(name, str) { return str.split('\n').map(function(str) { return color(name, str); }).join('\n'); } /** * Object#toString reference. */ var objToString = Object.prototype.toString; /** * Check that a / b have the same type. * * @api private * @param {Object} a * @param {Object} b * @return {boolean} */ function sameType(a, b) { return objToString.call(a) === objToString.call(b); } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../ms":15,"../utils":39,"_process":51,"diff":67,"supports-color":41,"tty":5}],18:[function(require,module,exports){ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); /** * Expose `Doc`. */ exports = module.exports = Doc; /** * Initialize a new `Doc` reporter. * * @param {Runner} runner * @api public */ function Doc(runner) { Base.call(this, runner); var indents = 2; function indent() { return Array(indents).join(' '); } runner.on('suite', function(suite) { if (suite.root) { return; } ++indents; console.log('%s
', indent()); ++indents; console.log('%s

%s

', indent(), utils.escape(suite.title)); console.log('%s
', indent()); }); runner.on('suite end', function(suite) { if (suite.root) { return; } console.log('%s
', indent()); --indents; console.log('%s
', indent()); --indents; }); runner.on('pass', function(test) { console.log('%s
%s
', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.fn.toString())); console.log('%s
%s
', indent(), code); }); runner.on('fail', function(test, err) { console.log('%s
%s
', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.fn.toString())); console.log('%s
%s
', indent(), code); console.log('%s
%s
', indent(), utils.escape(err)); }); } },{"../utils":39,"./base":17}],19:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; var color = Base.color; /** * Expose `Dot`. */ exports = module.exports = Dot; /** * Initialize a new `Dot` matrix test reporter. * * @api public * @param {Runner} runner */ function Dot(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * .75 | 0; var n = -1; runner.on('start', function() { process.stdout.write('\n'); }); runner.on('pending', function() { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('pending', Base.symbols.dot)); }); runner.on('pass', function(test) { if (++n % width === 0) { process.stdout.write('\n '); } if (test.speed === 'slow') { process.stdout.write(color('bright yellow', Base.symbols.dot)); } else { process.stdout.write(color(test.speed, Base.symbols.dot)); } }); runner.on('fail', function() { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('fail', Base.symbols.dot)); }); runner.on('end', function() { console.log(); self.epilogue(); }); } /** * Inherit from `Base.prototype`. */ inherits(Dot, Base); }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],20:[function(require,module,exports){ (function (process,__dirname){ /** * Module dependencies. */ var JSONCov = require('./json-cov'); var readFileSync = require('fs').readFileSync; var join = require('path').join; /** * Expose `HTMLCov`. */ exports = module.exports = HTMLCov; /** * Initialize a new `JsCoverage` reporter. * * @api public * @param {Runner} runner */ function HTMLCov(runner) { var jade = require('jade'); var file = join(__dirname, '/templates/coverage.jade'); var str = readFileSync(file, 'utf8'); var fn = jade.compile(str, { filename: file }); var self = this; JSONCov.call(this, runner, false); runner.on('end', function() { process.stdout.write(fn({ cov: self.cov, coverageClass: coverageClass })); }); } /** * Return coverage class for a given coverage percentage. * * @api private * @param {number} coveragePctg * @return {string} */ function coverageClass(coveragePctg) { if (coveragePctg >= 75) { return 'high'; } if (coveragePctg >= 50) { return 'medium'; } if (coveragePctg >= 25) { return 'low'; } return 'terrible'; } }).call(this,require('_process'),"/lib/reporters") },{"./json-cov":23,"_process":51,"fs":41,"jade":41,"path":41}],21:[function(require,module,exports){ (function (global){ /* eslint-env browser */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); var Progress = require('../browser/progress'); var escapeRe = require('escape-string-regexp'); var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ /* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; /* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `HTML`. */ exports = module.exports = HTML; /** * Stats template. */ var statsTemplate = ''; /** * Initialize a new `HTML` reporter. * * @api public * @param {Runner} runner */ function HTML(runner) { Base.call(this, runner); var self = this; var stats = this.stats; var stat = fragment(statsTemplate); var items = stat.getElementsByTagName('li'); var passes = items[1].getElementsByTagName('em')[0]; var passesLink = items[1].getElementsByTagName('a')[0]; var failures = items[2].getElementsByTagName('em')[0]; var failuresLink = items[2].getElementsByTagName('a')[0]; var duration = items[3].getElementsByTagName('em')[0]; var canvas = stat.getElementsByTagName('canvas')[0]; var report = fragment('
    '); var stack = [report]; var progress; var ctx; var root = document.getElementById('mocha'); if (canvas.getContext) { var ratio = window.devicePixelRatio || 1; canvas.style.width = canvas.width; canvas.style.height = canvas.height; canvas.width *= ratio; canvas.height *= ratio; ctx = canvas.getContext('2d'); ctx.scale(ratio, ratio); progress = new Progress(); } if (!root) { return error('#mocha div missing, add it to your document'); } // pass toggle on(passesLink, 'click', function() { unhide(); var name = (/pass/).test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test pass'); } }); // failure toggle on(failuresLink, 'click', function() { unhide(); var name = (/fail/).test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test fail'); } }); root.appendChild(stat); root.appendChild(report); if (progress) { progress.size(40); } runner.on('suite', function(suite) { if (suite.root) { return; } // suite var url = self.suiteURL(suite); var el = fragment('
  • %s

  • ', url, escape(suite.title)); // container stack[0].appendChild(el); stack.unshift(document.createElement('ul')); el.appendChild(stack[0]); }); runner.on('suite end', function(suite) { if (suite.root) { return; } stack.shift(); }); runner.on('fail', function(test) { if (test.type === 'hook') { runner.emit('test end', test); } }); runner.on('test end', function(test) { // TODO: add to stats var percent = stats.tests / this.total * 100 | 0; if (progress) { progress.update(percent).draw(ctx); } // update stats var ms = new Date() - stats.start; text(passes, stats.passes); text(failures, stats.failures); text(duration, (ms / 1000).toFixed(2)); // test var el; if (test.state === 'passed') { var url = self.testURL(test); el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, url); } else if (test.pending) { el = fragment('
  • %e

  • ', test.title); } else { el = fragment('
  • %e

  • ', test.title, self.testURL(test)); var stackString; // Note: Includes leading newline var message = test.err.toString(); // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we // check for the result of the stringifying. if (message === '[object Error]') { message = test.err.message; } if (test.err.stack) { var indexOfMessage = test.err.stack.indexOf(test.err.message); if (indexOfMessage === -1) { stackString = test.err.stack; } else { stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; } stackString = stackString || ''; if (test.err.htmlMessage && stackString) { el.appendChild(fragment('
    %s\n
    %e
    ', test.err.htmlMessage, stackString)); } else if (test.err.htmlMessage) { el.appendChild(fragment('
    %s
    ', test.err.htmlMessage)); } else { el.appendChild(fragment('
    %e%e
    ', message, stackString)); } } // toggle code // TODO: defer if (!test.pending) { var h2 = el.getElementsByTagName('h2')[0]; on(h2, 'click', function() { pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; }); var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); el.appendChild(pre); pre.style.display = 'none'; } // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. if (stack[0]) { stack[0].appendChild(el); } }); } /** * Makes a URL, preserving querystring ("search") parameters. * * @param {string} s * @return {string} A new URL. */ function makeUrl(s) { var search = window.location.search; // Remove previous grep query parameter if present if (search) { search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); } return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s)); } /** * Provide suite URL. * * @param {Object} [suite] */ HTML.prototype.suiteURL = function(suite) { return makeUrl(suite.fullTitle()); }; /** * Provide test URL. * * @param {Object} [test] */ HTML.prototype.testURL = function(test) { return makeUrl(test.fullTitle()); }; /** * Display error `msg`. * * @param {string} msg */ function error(msg) { document.body.appendChild(fragment('
    %s
    ', msg)); } /** * Return a DOM fragment from `html`. * * @param {string} html */ function fragment(html) { var args = arguments; var div = document.createElement('div'); var i = 1; div.innerHTML = html.replace(/%([se])/g, function(_, type) { switch (type) { case 's': return String(args[i++]); case 'e': return escape(args[i++]); // no default } }); return div.firstChild; } /** * Check for suites that do not have elements * with `classname`, and hide them. * * @param {text} classname */ function hideSuitesWithout(classname) { var suites = document.getElementsByClassName('suite'); for (var i = 0; i < suites.length; i++) { var els = suites[i].getElementsByClassName(classname); if (!els.length) { suites[i].className += ' hidden'; } } } /** * Unhide .hidden suites. */ function unhide() { var els = document.getElementsByClassName('suite hidden'); for (var i = 0; i < els.length; ++i) { els[i].className = els[i].className.replace('suite hidden', 'suite'); } } /** * Set an element's text contents. * * @param {HTMLElement} el * @param {string} contents */ function text(el, contents) { if (el.textContent) { el.textContent = contents; } else { el.innerText = contents; } } /** * Listen on `event` with callback `fn`. */ function on(el, event, fn) { if (el.addEventListener) { el.addEventListener(event, fn, false); } else { el.attachEvent('on' + event, fn); } } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../browser/progress":4,"../utils":39,"./base":17,"escape-string-regexp":68}],22:[function(require,module,exports){ // Alias exports to a their normalized format Mocha#reporter to prevent a need // for dynamic (try/catch) requires, which Browserify doesn't handle. exports.Base = exports.base = require('./base'); exports.Dot = exports.dot = require('./dot'); exports.Doc = exports.doc = require('./doc'); exports.TAP = exports.tap = require('./tap'); exports.JSON = exports.json = require('./json'); exports.HTML = exports.html = require('./html'); exports.List = exports.list = require('./list'); exports.Min = exports.min = require('./min'); exports.Spec = exports.spec = require('./spec'); exports.Nyan = exports.nyan = require('./nyan'); exports.XUnit = exports.xunit = require('./xunit'); exports.Markdown = exports.markdown = require('./markdown'); exports.Progress = exports.progress = require('./progress'); exports.Landing = exports.landing = require('./landing'); exports.JSONCov = exports['json-cov'] = require('./json-cov'); exports.HTMLCov = exports['html-cov'] = require('./html-cov'); exports.JSONStream = exports['json-stream'] = require('./json-stream'); },{"./base":17,"./doc":18,"./dot":19,"./html":21,"./html-cov":20,"./json":25,"./json-cov":23,"./json-stream":24,"./landing":26,"./list":27,"./markdown":28,"./min":29,"./nyan":30,"./progress":31,"./spec":32,"./tap":33,"./xunit":34}],23:[function(require,module,exports){ (function (process,global){ /** * Module dependencies. */ var Base = require('./base'); /** * Expose `JSONCov`. */ exports = module.exports = JSONCov; /** * Initialize a new `JsCoverage` reporter. * * @api public * @param {Runner} runner * @param {boolean} output */ function JSONCov(runner, output) { Base.call(this, runner); output = arguments.length === 1 || output; var self = this; var tests = []; var failures = []; var passes = []; runner.on('test end', function(test) { tests.push(test); }); runner.on('pass', function(test) { passes.push(test); }); runner.on('fail', function(test) { failures.push(test); }); runner.on('end', function() { var cov = global._$jscoverage || {}; var result = self.cov = map(cov); result.stats = self.stats; result.tests = tests.map(clean); result.failures = failures.map(clean); result.passes = passes.map(clean); if (!output) { return; } process.stdout.write(JSON.stringify(result, null, 2)); }); } /** * Map jscoverage data to a JSON structure * suitable for reporting. * * @api private * @param {Object} cov * @return {Object} */ function map(cov) { var ret = { instrumentation: 'node-jscoverage', sloc: 0, hits: 0, misses: 0, coverage: 0, files: [] }; for (var filename in cov) { if (Object.prototype.hasOwnProperty.call(cov, filename)) { var data = coverage(filename, cov[filename]); ret.files.push(data); ret.hits += data.hits; ret.misses += data.misses; ret.sloc += data.sloc; } } ret.files.sort(function(a, b) { return a.filename.localeCompare(b.filename); }); if (ret.sloc > 0) { ret.coverage = (ret.hits / ret.sloc) * 100; } return ret; } /** * Map jscoverage data for a single source file * to a JSON structure suitable for reporting. * * @api private * @param {string} filename name of the source file * @param {Object} data jscoverage coverage data * @return {Object} */ function coverage(filename, data) { var ret = { filename: filename, coverage: 0, hits: 0, misses: 0, sloc: 0, source: {} }; data.source.forEach(function(line, num) { num++; if (data[num] === 0) { ret.misses++; ret.sloc++; } else if (data[num] !== undefined) { ret.hits++; ret.sloc++; } ret.source[num] = { source: line, coverage: data[num] === undefined ? '' : data[num] }; }); ret.coverage = ret.hits / ret.sloc * 100; return ret; } /** * Return a plain-object representation of `test` * free of cyclic properties etc. * * @api private * @param {Object} test * @return {Object} */ function clean(test) { return { duration: test.duration, fullTitle: test.fullTitle(), title: test.title }; } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./base":17,"_process":51}],24:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); /** * Expose `List`. */ exports = module.exports = List; /** * Initialize a new `List` test reporter. * * @api public * @param {Runner} runner */ function List(runner) { Base.call(this, runner); var self = this; var total = runner.total; runner.on('start', function() { console.log(JSON.stringify(['start', { total: total }])); }); runner.on('pass', function(test) { console.log(JSON.stringify(['pass', clean(test)])); }); runner.on('fail', function(test, err) { test = clean(test); test.err = err.message; test.stack = err.stack || null; console.log(JSON.stringify(['fail', test])); }); runner.on('end', function() { process.stdout.write(JSON.stringify(['end', self.stats])); }); } /** * Return a plain-object representation of `test` * free of cyclic properties etc. * * @api private * @param {Object} test * @return {Object} */ function clean(test) { return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration }; } }).call(this,require('_process')) },{"./base":17,"_process":51}],25:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); /** * Expose `JSON`. */ exports = module.exports = JSONReporter; /** * Initialize a new `JSON` reporter. * * @api public * @param {Runner} runner */ function JSONReporter(runner) { Base.call(this, runner); var self = this; var tests = []; var pending = []; var failures = []; var passes = []; runner.on('test end', function(test) { tests.push(test); }); runner.on('pass', function(test) { passes.push(test); }); runner.on('fail', function(test) { failures.push(test); }); runner.on('pending', function(test) { pending.push(test); }); runner.on('end', function() { var obj = { stats: self.stats, tests: tests.map(clean), pending: pending.map(clean), failures: failures.map(clean), passes: passes.map(clean) }; runner.testResults = obj; process.stdout.write(JSON.stringify(obj, null, 2)); }); } /** * Return a plain-object representation of `test` * free of cyclic properties etc. * * @api private * @param {Object} test * @return {Object} */ function clean(test) { return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, err: errorJSON(test.err || {}) }; } /** * Transform `error` into a JSON object. * * @api private * @param {Error} err * @return {Object} */ function errorJSON(err) { var res = {}; Object.getOwnPropertyNames(err).forEach(function(key) { res[key] = err[key]; }, err); return res; } }).call(this,require('_process')) },{"./base":17,"_process":51}],26:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; var cursor = Base.cursor; var color = Base.color; /** * Expose `Landing`. */ exports = module.exports = Landing; /** * Airplane color. */ Base.colors.plane = 0; /** * Airplane crash color. */ Base.colors['plane crash'] = 31; /** * Runway color. */ Base.colors.runway = 90; /** * Initialize a new `Landing` reporter. * * @api public * @param {Runner} runner */ function Landing(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * .75 | 0; var total = runner.total; var stream = process.stdout; var plane = color('plane', '✈'); var crashed = -1; var n = 0; function runway() { var buf = Array(width).join('-'); return ' ' + color('runway', buf); } runner.on('start', function() { stream.write('\n\n\n '); cursor.hide(); }); runner.on('test end', function(test) { // check if the plane crashed var col = crashed === -1 ? width * ++n / total | 0 : crashed; // show the crash if (test.state === 'failed') { plane = color('plane crash', '✈'); crashed = col; } // render landing strip stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); stream.write(runway()); stream.write('\n '); stream.write(color('runway', Array(col).join('⋅'))); stream.write(plane); stream.write(color('runway', Array(width - col).join('⋅') + '\n')); stream.write(runway()); stream.write('\u001b[0m'); }); runner.on('end', function() { cursor.show(); console.log(); self.epilogue(); }); } /** * Inherit from `Base.prototype`. */ inherits(Landing, Base); }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],27:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; var color = Base.color; var cursor = Base.cursor; /** * Expose `List`. */ exports = module.exports = List; /** * Initialize a new `List` test reporter. * * @api public * @param {Runner} runner */ function List(runner) { Base.call(this, runner); var self = this; var n = 0; runner.on('start', function() { console.log(); }); runner.on('test', function(test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); runner.on('pending', function(test) { var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); runner.on('pass', function(test) { var fmt = color('checkmark', ' ' + Base.symbols.dot) + color('pass', ' %s: ') + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); runner.on('fail', function(test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); runner.on('end', self.epilogue.bind(self)); } /** * Inherit from `Base.prototype`. */ inherits(List, Base); }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],28:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); /** * Constants */ var SUITE_PREFIX = '$'; /** * Expose `Markdown`. */ exports = module.exports = Markdown; /** * Initialize a new `Markdown` reporter. * * @api public * @param {Runner} runner */ function Markdown(runner) { Base.call(this, runner); var level = 0; var buf = ''; function title(str) { return Array(level).join('#') + ' ' + str; } function mapTOC(suite, obj) { var ret = obj; var key = SUITE_PREFIX + suite.title; obj = obj[key] = obj[key] || { suite: suite }; suite.suites.forEach(function(suite) { mapTOC(suite, obj); }); return ret; } function stringifyTOC(obj, level) { ++level; var buf = ''; var link; for (var key in obj) { if (key === 'suite') { continue; } if (key !== SUITE_PREFIX) { link = ' - [' + key.substring(1) + ']'; link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; buf += Array(level).join(' ') + link; } buf += stringifyTOC(obj[key], level); } return buf; } function generateTOC(suite) { var obj = mapTOC(suite, {}); return stringifyTOC(obj, 0); } generateTOC(runner.suite); runner.on('suite', function(suite) { ++level; var slug = utils.slug(suite.fullTitle()); buf += '' + '\n'; buf += title(suite.title) + '\n'; }); runner.on('suite end', function() { --level; }); runner.on('pass', function(test) { var code = utils.clean(test.fn.toString()); buf += test.title + '.\n'; buf += '\n```js\n'; buf += code + '\n'; buf += '```\n\n'; }); runner.on('end', function() { process.stdout.write('# TOC\n'); process.stdout.write(generateTOC(runner.suite)); process.stdout.write(buf); }); } }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],29:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; /** * Expose `Min`. */ exports = module.exports = Min; /** * Initialize a new `Min` minimal test reporter (best used with --watch). * * @api public * @param {Runner} runner */ function Min(runner) { Base.call(this, runner); runner.on('start', function() { // clear screen process.stdout.write('\u001b[2J'); // set cursor position process.stdout.write('\u001b[1;3H'); }); runner.on('end', this.epilogue.bind(this)); } /** * Inherit from `Base.prototype`. */ inherits(Min, Base); }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],30:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; /** * Expose `Dot`. */ exports = module.exports = NyanCat; /** * Initialize a new `Dot` matrix test reporter. * * @param {Runner} runner * @api public */ function NyanCat(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * .75 | 0; var nyanCatWidth = this.nyanCatWidth = 11; this.colorIndex = 0; this.numberOfLines = 4; this.rainbowColors = self.generateColors(); this.scoreboardWidth = 5; this.tick = 0; this.trajectories = [[], [], [], []]; this.trajectoryWidthMax = (width - nyanCatWidth); runner.on('start', function() { Base.cursor.hide(); self.draw(); }); runner.on('pending', function() { self.draw(); }); runner.on('pass', function() { self.draw(); }); runner.on('fail', function() { self.draw(); }); runner.on('end', function() { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); } self.epilogue(); }); } /** * Inherit from `Base.prototype`. */ inherits(NyanCat, Base); /** * Draw the nyan cat * * @api private */ NyanCat.prototype.draw = function() { this.appendRainbow(); this.drawScoreboard(); this.drawRainbow(); this.drawNyanCat(); this.tick = !this.tick; }; /** * Draw the "scoreboard" showing the number * of passes, failures and pending tests. * * @api private */ NyanCat.prototype.drawScoreboard = function() { var stats = this.stats; function draw(type, n) { write(' '); write(Base.color(type, n)); write('\n'); } draw('green', stats.passes); draw('fail', stats.failures); draw('pending', stats.pending); write('\n'); this.cursorUp(this.numberOfLines); }; /** * Append the rainbow. * * @api private */ NyanCat.prototype.appendRainbow = function() { var segment = this.tick ? '_' : '-'; var rainbowified = this.rainbowify(segment); for (var index = 0; index < this.numberOfLines; index++) { var trajectory = this.trajectories[index]; if (trajectory.length >= this.trajectoryWidthMax) { trajectory.shift(); } trajectory.push(rainbowified); } }; /** * Draw the rainbow. * * @api private */ NyanCat.prototype.drawRainbow = function() { var self = this; this.trajectories.forEach(function(line) { write('\u001b[' + self.scoreboardWidth + 'C'); write(line.join('')); write('\n'); }); this.cursorUp(this.numberOfLines); }; /** * Draw the nyan cat * * @api private */ NyanCat.prototype.drawNyanCat = function() { var self = this; var startWidth = this.scoreboardWidth + this.trajectories[0].length; var dist = '\u001b[' + startWidth + 'C'; var padding = ''; write(dist); write('_,------,'); write('\n'); write(dist); padding = self.tick ? ' ' : ' '; write('_|' + padding + '/\\_/\\ '); write('\n'); write(dist); padding = self.tick ? '_' : '__'; var tail = self.tick ? '~' : '^'; write(tail + '|' + padding + this.face() + ' '); write('\n'); write(dist); padding = self.tick ? ' ' : ' '; write(padding + '"" "" '); write('\n'); this.cursorUp(this.numberOfLines); }; /** * Draw nyan cat face. * * @api private * @return {string} */ NyanCat.prototype.face = function() { var stats = this.stats; if (stats.failures) { return '( x .x)'; } else if (stats.pending) { return '( o .o)'; } else if (stats.passes) { return '( ^ .^)'; } return '( - .-)'; }; /** * Move cursor up `n`. * * @api private * @param {number} n */ NyanCat.prototype.cursorUp = function(n) { write('\u001b[' + n + 'A'); }; /** * Move cursor down `n`. * * @api private * @param {number} n */ NyanCat.prototype.cursorDown = function(n) { write('\u001b[' + n + 'B'); }; /** * Generate rainbow colors. * * @api private * @return {Array} */ NyanCat.prototype.generateColors = function() { var colors = []; for (var i = 0; i < (6 * 7); i++) { var pi3 = Math.floor(Math.PI / 3); var n = (i * (1.0 / 6)); var r = Math.floor(3 * Math.sin(n) + 3); var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); colors.push(36 * r + 6 * g + b + 16); } return colors; }; /** * Apply rainbow to the given `str`. * * @api private * @param {string} str * @return {string} */ NyanCat.prototype.rainbowify = function(str) { if (!Base.useColors) { return str; } var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; this.colorIndex += 1; return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; }; /** * Stdout helper. * * @param {string} string A message to write to stdout. */ function write(string) { process.stdout.write(string); } }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],31:[function(require,module,exports){ (function (process){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; var color = Base.color; var cursor = Base.cursor; /** * Expose `Progress`. */ exports = module.exports = Progress; /** * General progress bar color. */ Base.colors.progress = 90; /** * Initialize a new `Progress` bar test reporter. * * @api public * @param {Runner} runner * @param {Object} options */ function Progress(runner, options) { Base.call(this, runner); var self = this; var width = Base.window.width * .50 | 0; var total = runner.total; var complete = 0; var lastN = -1; // default chars options = options || {}; options.open = options.open || '['; options.complete = options.complete || '▬'; options.incomplete = options.incomplete || Base.symbols.dot; options.close = options.close || ']'; options.verbose = false; // tests started runner.on('start', function() { console.log(); cursor.hide(); }); // tests complete runner.on('test end', function() { complete++; var percent = complete / total; var n = width * percent | 0; var i = width - n; if (n === lastN && !options.verbose) { // Don't re-render the line if it hasn't changed return; } lastN = n; cursor.CR(); process.stdout.write('\u001b[J'); process.stdout.write(color('progress', ' ' + options.open)); process.stdout.write(Array(n).join(options.complete)); process.stdout.write(Array(i).join(options.incomplete)); process.stdout.write(color('progress', options.close)); if (options.verbose) { process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); } }); // tests are complete, output some stats // and the failures if any runner.on('end', function() { cursor.show(); console.log(); self.epilogue(); }); } /** * Inherit from `Base.prototype`. */ inherits(Progress, Base); }).call(this,require('_process')) },{"../utils":39,"./base":17,"_process":51}],32:[function(require,module,exports){ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; var color = Base.color; var cursor = Base.cursor; /** * Expose `Spec`. */ exports = module.exports = Spec; /** * Initialize a new `Spec` test reporter. * * @api public * @param {Runner} runner */ function Spec(runner) { Base.call(this, runner); var self = this; var indents = 0; var n = 0; function indent() { return Array(indents).join(' '); } runner.on('start', function() { console.log(); }); runner.on('suite', function(suite) { ++indents; console.log(color('suite', '%s%s'), indent(), suite.title); }); runner.on('suite end', function() { --indents; if (indents === 1) { console.log(); } }); runner.on('pending', function(test) { var fmt = indent() + color('pending', ' - %s'); console.log(fmt, test.title); }); runner.on('pass', function(test) { var fmt; if (test.speed === 'fast') { fmt = indent() + color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s'); cursor.CR(); console.log(fmt, test.title); } else { fmt = indent() + color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s') + color(test.speed, ' (%dms)'); cursor.CR(); console.log(fmt, test.title, test.duration); } }); runner.on('fail', function(test) { cursor.CR(); console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); runner.on('end', self.epilogue.bind(self)); } /** * Inherit from `Base.prototype`. */ inherits(Spec, Base); },{"../utils":39,"./base":17}],33:[function(require,module,exports){ /** * Module dependencies. */ var Base = require('./base'); /** * Expose `TAP`. */ exports = module.exports = TAP; /** * Initialize a new `TAP` reporter. * * @api public * @param {Runner} runner */ function TAP(runner) { Base.call(this, runner); var n = 1; var passes = 0; var failures = 0; runner.on('start', function() { var total = runner.grepTotal(runner.suite); console.log('%d..%d', 1, total); }); runner.on('test end', function() { ++n; }); runner.on('pending', function(test) { console.log('ok %d %s # SKIP -', n, title(test)); }); runner.on('pass', function(test) { passes++; console.log('ok %d %s', n, title(test)); }); runner.on('fail', function(test, err) { failures++; console.log('not ok %d %s', n, title(test)); if (err.stack) { console.log(err.stack.replace(/^/gm, ' ')); } }); runner.on('end', function() { console.log('# tests ' + (passes + failures)); console.log('# pass ' + passes); console.log('# fail ' + failures); }); } /** * Return a TAP-safe title of `test` * * @api private * @param {Object} test * @return {String} */ function title(test) { return test.fullTitle().replace(/#/g, ''); } },{"./base":17}],34:[function(require,module,exports){ (function (global){ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); var inherits = utils.inherits; var fs = require('fs'); var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ /* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; /* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `XUnit`. */ exports = module.exports = XUnit; /** * Initialize a new `XUnit` reporter. * * @api public * @param {Runner} runner */ function XUnit(runner, options) { Base.call(this, runner); var stats = this.stats; var tests = []; var self = this; if (options.reporterOptions && options.reporterOptions.output) { if (!fs.createWriteStream) { throw new Error('file output not supported in browser'); } self.fileStream = fs.createWriteStream(options.reporterOptions.output); } runner.on('pending', function(test) { tests.push(test); }); runner.on('pass', function(test) { tests.push(test); }); runner.on('fail', function(test) { tests.push(test); }); runner.on('end', function() { self.write(tag('testsuite', { name: 'Mocha Tests', tests: stats.tests, failures: stats.failures, errors: stats.failures, skipped: stats.tests - stats.failures - stats.passes, timestamp: (new Date()).toUTCString(), time: (stats.duration / 1000) || 0 }, false)); tests.forEach(function(t) { self.test(t); }); self.write(''); }); } /** * Inherit from `Base.prototype`. */ inherits(XUnit, Base); /** * Override done to close the stream (if it's a file). * * @param failures * @param {Function} fn */ XUnit.prototype.done = function(failures, fn) { if (this.fileStream) { this.fileStream.end(function() { fn(failures); }); } else { fn(failures); } }; /** * Write out the given line. * * @param {string} line */ XUnit.prototype.write = function(line) { if (this.fileStream) { this.fileStream.write(line + '\n'); } else { console.log(line); } }; /** * Output tag for the given `test.` * * @param {Test} test */ XUnit.prototype.test = function(test) { var attrs = { classname: test.parent.fullTitle(), name: test.title, time: (test.duration / 1000) || 0 }; if (test.state === 'failed') { var err = test.err; this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + '\n' + err.stack)))); } else if (test.pending) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { this.write(tag('testcase', attrs, true)); } }; /** * HTML tag helper. * * @param name * @param attrs * @param close * @param content * @return {string} */ function tag(name, attrs, close, content) { var end = close ? '/>' : '>'; var pairs = []; var tag; for (var key in attrs) { if (Object.prototype.hasOwnProperty.call(attrs, key)) { pairs.push(key + '="' + escape(attrs[key]) + '"'); } } tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; if (content) { tag += content + ''; } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../utils":39,"./base":17,"fs":41}],35:[function(require,module,exports){ (function (global){ /** * Module dependencies. */ var EventEmitter = require('events').EventEmitter; var Pending = require('./pending'); var debug = require('debug')('mocha:runnable'); var milliseconds = require('./ms'); var utils = require('./utils'); var inherits = utils.inherits; /** * Save timer references to avoid Sinon interfering (see GH-237). */ /* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; /* eslint-enable no-unused-vars, no-native-reassign */ /** * Object#toString(). */ var toString = Object.prototype.toString; /** * Expose `Runnable`. */ module.exports = Runnable; /** * Initialize a new `Runnable` with the given `title` and callback `fn`. * * @param {String} title * @param {Function} fn * @api private * @param {string} title * @param {Function} fn */ function Runnable(title, fn) { this.title = title; this.fn = fn; this.async = fn && fn.length; this.sync = !this.async; this._timeout = 2000; this._slow = 75; this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); } /** * Inherit from `EventEmitter.prototype`. */ inherits(Runnable, EventEmitter); /** * Set & get timeout `ms`. * * @api private * @param {number|string} ms * @return {Runnable|number} ms or Runnable instance. */ Runnable.prototype.timeout = function(ms) { if (!arguments.length) { return this._timeout; } if (ms === 0) { this._enableTimeouts = false; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._timeout = ms; if (this.timer) { this.resetTimeout(); } return this; }; /** * Set & get slow `ms`. * * @api private * @param {number|string} ms * @return {Runnable|number} ms or Runnable instance. */ Runnable.prototype.slow = function(ms) { if (!arguments.length) { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._slow = ms; return this; }; /** * Set and get whether timeout is `enabled`. * * @api private * @param {boolean} enabled * @return {Runnable|boolean} enabled or Runnable instance. */ Runnable.prototype.enableTimeouts = function(enabled) { if (!arguments.length) { return this._enableTimeouts; } debug('enableTimeouts %s', enabled); this._enableTimeouts = enabled; return this; }; /** * Halt and mark as pending. * * @api private */ Runnable.prototype.skip = function() { throw new Pending(); }; /** * Return the full title generated by recursively concatenating the parent's * full title. * * @api public * @return {string} */ Runnable.prototype.fullTitle = function() { return this.parent.fullTitle() + ' ' + this.title; }; /** * Clear the timeout. * * @api private */ Runnable.prototype.clearTimeout = function() { clearTimeout(this.timer); }; /** * Inspect the runnable void of private properties. * * @api private * @return {string} */ Runnable.prototype.inspect = function() { return JSON.stringify(this, function(key, val) { if (key[0] === '_') { return; } if (key === 'parent') { return '#'; } if (key === 'ctx') { return '#'; } return val; }, 2); }; /** * Reset the timeout. * * @api private */ Runnable.prototype.resetTimeout = function() { var self = this; var ms = this.timeout() || 1e9; if (!this._enableTimeouts) { return; } this.clearTimeout(); this.timer = setTimeout(function() { if (!self._enableTimeouts) { return; } self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.')); self.timedOut = true; }, ms); }; /** * Whitelist a list of globals for this test run. * * @api private * @param {string[]} globals */ Runnable.prototype.globals = function(globals) { this._allowedGlobals = globals; }; /** * Run the test and invoke `fn(err)`. * * @param {Function} fn * @api private */ Runnable.prototype.run = function(fn) { var self = this; var start = new Date(); var ctx = this.ctx; var finished; var emitted; // Sometimes the ctx exists, but it is not runnable if (ctx && ctx.runnable) { ctx.runnable(this); } // called multiple times function multiple(err) { if (emitted) { return; } emitted = true; self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); } // finished function done(err) { var ms = self.timeout(); if (self.timedOut) { return; } if (finished) { return multiple(err || self._trace); } self.clearTimeout(); self.duration = new Date() - start; finished = true; if (!err && self.duration > ms && self._enableTimeouts) { err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); } fn(err); } // for .resetTimeout() this.callback = done; // explicit async with `done` argument if (this.async) { this.resetTimeout(); if (this.allowUncaught) { return callFnAsync(this.fn); } try { callFnAsync(this.fn); } catch (err) { done(utils.getError(err)); } return; } if (this.allowUncaught) { callFn(this.fn); done(); return; } // sync or promise-returning try { if (this.pending) { done(); } else { callFn(this.fn); } } catch (err) { done(utils.getError(err)); } function callFn(fn) { var result = fn.call(ctx); if (result && typeof result.then === 'function') { self.resetTimeout(); result .then(function() { done(); }, function(reason) { done(reason || new Error('Promise rejected with no or falsy reason')); }); } else { if (self.asyncOnly) { return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); } done(); } } function callFnAsync(fn) { fn.call(ctx, function(err) { if (err instanceof Error || toString.call(err) === '[object Error]') { return done(err); } if (err) { if (Object.prototype.toString.call(err) === '[object Object]') { return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err))); } return done(new Error('done() invoked with non-Error: ' + err)); } done(); }); } }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./ms":15,"./pending":16,"./utils":39,"debug":2,"events":3}],36:[function(require,module,exports){ (function (process,global){ /** * Module dependencies. */ var EventEmitter = require('events').EventEmitter; var Pending = require('./pending'); var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:runner'); var Runnable = require('./runnable'); var filter = utils.filter; var indexOf = utils.indexOf; var keys = utils.keys; var stackFilter = utils.stackTraceFilter(); var stringify = utils.stringify; var type = utils.type; var undefinedError = utils.undefinedError; /** * Non-enumerable globals. */ var globals = [ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'XMLHttpRequest', 'Date', 'setImmediate', 'clearImmediate' ]; /** * Expose `Runner`. */ module.exports = Runner; /** * Initialize a `Runner` for the given `suite`. * * Events: * * - `start` execution started * - `end` execution complete * - `suite` (suite) test suite execution started * - `suite end` (suite) all tests (and sub-suites) have finished * - `test` (test) test execution started * - `test end` (test) test completed * - `hook` (hook) hook execution started * - `hook end` (hook) hook complete * - `pass` (test) test passed * - `fail` (test, err) test failed * - `pending` (test) test pending * * @api public * @param {Suite} suite Root suite * @param {boolean} [delay] Whether or not to delay execution of root suite * until ready. */ function Runner(suite, delay) { var self = this; this._globals = []; this._abort = false; this._delay = delay; this.suite = suite; this.started = false; this.total = suite.total(); this.failures = 0; this.on('test end', function(test) { self.checkGlobals(test); }); this.on('hook end', function(hook) { self.checkGlobals(hook); }); this._defaultGrep = /.*/; this.grep(this._defaultGrep); this.globals(this.globalProps().concat(extraGlobals())); } /** * Wrapper for setImmediate, process.nextTick, or browser polyfill. * * @param {Function} fn * @api private */ Runner.immediately = global.setImmediate || process.nextTick; /** * Inherit from `EventEmitter.prototype`. */ inherits(Runner, EventEmitter); /** * Run tests with full titles matching `re`. Updates runner.total * with number of tests matched. * * @param {RegExp} re * @param {Boolean} invert * @return {Runner} for chaining * @api public * @param {RegExp} re * @param {boolean} invert * @return {Runner} Runner instance. */ Runner.prototype.grep = function(re, invert) { debug('grep %s', re); this._grep = re; this._invert = invert; this.total = this.grepTotal(this.suite); return this; }; /** * Returns the number of tests matching the grep search for the * given suite. * * @param {Suite} suite * @return {Number} * @api public * @param {Suite} suite * @return {number} */ Runner.prototype.grepTotal = function(suite) { var self = this; var total = 0; suite.eachTest(function(test) { var match = self._grep.test(test.fullTitle()); if (self._invert) { match = !match; } if (match) { total++; } }); return total; }; /** * Return a list of global properties. * * @return {Array} * @api private */ Runner.prototype.globalProps = function() { var props = keys(global); // non-enumerables for (var i = 0; i < globals.length; ++i) { if (~indexOf(props, globals[i])) { continue; } props.push(globals[i]); } return props; }; /** * Allow the given `arr` of globals. * * @param {Array} arr * @return {Runner} for chaining * @api public * @param {Array} arr * @return {Runner} Runner instance. */ Runner.prototype.globals = function(arr) { if (!arguments.length) { return this._globals; } debug('globals %j', arr); this._globals = this._globals.concat(arr); return this; }; /** * Check for global variable leaks. * * @api private */ Runner.prototype.checkGlobals = function(test) { if (this.ignoreLeaks) { return; } var ok = this._globals; var globals = this.globalProps(); var leaks; if (test) { ok = ok.concat(test._allowedGlobals || []); } if (this.prevGlobalsLength === globals.length) { return; } this.prevGlobalsLength = globals.length; leaks = filterLeaks(ok, globals); this._globals = this._globals.concat(leaks); if (leaks.length > 1) { this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); } else if (leaks.length) { this.fail(test, new Error('global leak detected: ' + leaks[0])); } }; /** * Fail the given `test`. * * @api private * @param {Test} test * @param {Error} err */ Runner.prototype.fail = function(test, err) { ++this.failures; test.state = 'failed'; if (!(err instanceof Error || err && typeof err.message === 'string')) { err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); } err.stack = (this.fullStackTrace || !err.stack) ? err.stack : stackFilter(err.stack); this.emit('fail', test, err); }; /** * Fail the given `hook` with `err`. * * Hook failures work in the following pattern: * - If bail, then exit * - Failed `before` hook skips all tests in a suite and subsuites, * but jumps to corresponding `after` hook * - Failed `before each` hook skips remaining tests in a * suite and jumps to corresponding `after each` hook, * which is run only once * - Failed `after` hook does not alter * execution order * - Failed `after each` hook skips remaining tests in a * suite and subsuites, but executes other `after each` * hooks * * @api private * @param {Hook} hook * @param {Error} err */ Runner.prototype.failHook = function(hook, err) { if (hook.ctx && hook.ctx.currentTest) { hook.originalTitle = hook.originalTitle || hook.title; hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; } this.fail(hook, err); if (this.suite.bail()) { this.emit('end'); } }; /** * Run hook `name` callbacks and then invoke `fn()`. * * @api private * @param {string} name * @param {Function} fn */ Runner.prototype.hook = function(name, fn) { var suite = this.suite; var hooks = suite['_' + name]; var self = this; function next(i) { var hook = hooks[i]; if (!hook) { return fn(); } self.currentRunnable = hook; hook.ctx.currentTest = self.test; self.emit('hook', hook); if (!hook.listeners('error').length) { hook.on('error', function(err) { self.failHook(hook, err); }); } hook.run(function(err) { var testError = hook.error(); if (testError) { self.fail(self.test, testError); } if (err) { if (err instanceof Pending) { suite.pending = true; } else { self.failHook(hook, err); // stop executing hooks, notify callee of hook err return fn(err); } } self.emit('hook end', hook); delete hook.ctx.currentTest; next(++i); }); } Runner.immediately(function() { next(0); }); }; /** * Run hook `name` for the given array of `suites` * in order, and callback `fn(err, errSuite)`. * * @api private * @param {string} name * @param {Array} suites * @param {Function} fn */ Runner.prototype.hooks = function(name, suites, fn) { var self = this; var orig = this.suite; function next(suite) { self.suite = suite; if (!suite) { self.suite = orig; return fn(); } self.hook(name, function(err) { if (err) { var errSuite = self.suite; self.suite = orig; return fn(err, errSuite); } next(suites.pop()); }); } next(suites.pop()); }; /** * Run hooks from the top level down. * * @param {String} name * @param {Function} fn * @api private */ Runner.prototype.hookUp = function(name, fn) { var suites = [this.suite].concat(this.parents()).reverse(); this.hooks(name, suites, fn); }; /** * Run hooks from the bottom up. * * @param {String} name * @param {Function} fn * @api private */ Runner.prototype.hookDown = function(name, fn) { var suites = [this.suite].concat(this.parents()); this.hooks(name, suites, fn); }; /** * Return an array of parent Suites from * closest to furthest. * * @return {Array} * @api private */ Runner.prototype.parents = function() { var suite = this.suite; var suites = []; while (suite.parent) { suite = suite.parent; suites.push(suite); } return suites; }; /** * Run the current test and callback `fn(err)`. * * @param {Function} fn * @api private */ Runner.prototype.runTest = function(fn) { var self = this; var test = this.test; if (this.asyncOnly) { test.asyncOnly = true; } if (this.allowUncaught) { test.allowUncaught = true; return test.run(fn); } try { test.on('error', function(err) { self.fail(test, err); }); test.run(fn); } catch (err) { fn(err); } }; /** * Run tests in the given `suite` and invoke the callback `fn()` when complete. * * @api private * @param {Suite} suite * @param {Function} fn */ Runner.prototype.runTests = function(suite, fn) { var self = this; var tests = suite.tests.slice(); var test; function hookErr(_, errSuite, after) { // before/after Each hook for errSuite failed: var orig = self.suite; // for failed 'after each' hook start from errSuite parent, // otherwise start from errSuite itself self.suite = after ? errSuite.parent : errSuite; if (self.suite) { // call hookUp afterEach self.hookUp('afterEach', function(err2, errSuite2) { self.suite = orig; // some hooks may fail even now if (err2) { return hookErr(err2, errSuite2, true); } // report error suite fn(errSuite); }); } else { // there is no need calling other 'after each' hooks self.suite = orig; fn(errSuite); } } function next(err, errSuite) { // if we bail after first err if (self.failures && suite._bail) { return fn(); } if (self._abort) { return fn(); } if (err) { return hookErr(err, errSuite, true); } // next test test = tests.shift(); // all done if (!test) { return fn(); } // grep var match = self._grep.test(test.fullTitle()); if (self._invert) { match = !match; } if (!match) { // Run immediately only if we have defined a grep. When we // define a grep — It can cause maximum callstack error if // the grep is doing a large recursive loop by neglecting // all tests. The run immediately function also comes with // a performance cost. So we don't want to run immediately // if we run the whole test suite, because running the whole // test suite don't do any immediate recursive loops. Thus, // allowing a JS runtime to breathe. if (self._grep !== self._defaultGrep) { Runner.immediately(next); } else { next(); } return; } // pending if (test.pending) { self.emit('pending', test); self.emit('test end', test); return next(); } // execute test and hook(s) self.emit('test', self.test = test); self.hookDown('beforeEach', function(err, errSuite) { if (suite.pending) { self.emit('pending', test); self.emit('test end', test); return next(); } if (err) { return hookErr(err, errSuite, false); } self.currentRunnable = self.test; self.runTest(function(err) { test = self.test; if (err) { if (err instanceof Pending) { self.emit('pending', test); } else { self.fail(test, err); } self.emit('test end', test); if (err instanceof Pending) { return next(); } return self.hookUp('afterEach', next); } test.state = 'passed'; self.emit('pass', test); self.emit('test end', test); self.hookUp('afterEach', next); }); }); } this.next = next; this.hookErr = hookErr; next(); }; /** * Run the given `suite` and invoke the callback `fn()` when complete. * * @api private * @param {Suite} suite * @param {Function} fn */ Runner.prototype.runSuite = function(suite, fn) { var i = 0; var self = this; var total = this.grepTotal(suite); var afterAllHookCalled = false; debug('run suite %s', suite.fullTitle()); if (!total || (self.failures && suite._bail)) { return fn(); } this.emit('suite', this.suite = suite); function next(errSuite) { if (errSuite) { // current suite failed on a hook from errSuite if (errSuite === suite) { // if errSuite is current suite // continue to the next sibling suite return done(); } // errSuite is among the parents of current suite // stop execution of errSuite and all sub-suites return done(errSuite); } if (self._abort) { return done(); } var curr = suite.suites[i++]; if (!curr) { return done(); } // Avoid grep neglecting large number of tests causing a // huge recursive loop and thus a maximum call stack error. // See comment in `this.runTests()` for more information. if (self._grep !== self._defaultGrep) { Runner.immediately(function() { self.runSuite(curr, next); }); } else { self.runSuite(curr, next); } } function done(errSuite) { self.suite = suite; self.nextSuite = next; if (afterAllHookCalled) { fn(errSuite); } else { // mark that the afterAll block has been called once // and so can be skipped if there is an error in it. afterAllHookCalled = true; self.hook('afterAll', function() { self.emit('suite end', suite); fn(errSuite); }); } } this.nextSuite = next; this.hook('beforeAll', function(err) { if (err) { return done(); } self.runTests(suite, next); }); }; /** * Handle uncaught exceptions. * * @param {Error} err * @api private */ Runner.prototype.uncaught = function(err) { if (err) { debug('uncaught exception %s', err !== function() { return this; }.call(err) ? err : (err.message || err)); } else { debug('uncaught undefined exception'); err = undefinedError(); } err.uncaught = true; var runnable = this.currentRunnable; if (!runnable) { runnable = new Runnable('Uncaught error outside test suite'); runnable.parent = this.suite; if (this.started) { this.fail(runnable, err); } else { // Can't recover from this failure this.emit('start'); this.fail(runnable, err); this.emit('end'); } return; } runnable.clearTimeout(); // Ignore errors if complete if (runnable.state) { return; } this.fail(runnable, err); // recover from test if (runnable.type === 'test') { this.emit('test end', runnable); this.hookUp('afterEach', this.next); return; } // recover from hooks if (runnable.type === 'hook') { var errSuite = this.suite; // if hook failure is in afterEach block if (runnable.fullTitle().indexOf('after each') > -1) { return this.hookErr(err, errSuite, true); } // if hook failure is in beforeEach block if (runnable.fullTitle().indexOf('before each') > -1) { return this.hookErr(err, errSuite, false); } // if hook failure is in after or before blocks return this.nextSuite(errSuite); } // bail this.emit('end'); }; /** * Run the root suite and invoke `fn(failures)` * on completion. * * @param {Function} fn * @return {Runner} for chaining * @api public * @param {Function} fn * @return {Runner} Runner instance. */ Runner.prototype.run = function(fn) { var self = this; var rootSuite = this.suite; fn = fn || function() {}; function uncaught(err) { self.uncaught(err); } function start() { self.started = true; self.emit('start'); self.runSuite(rootSuite, function() { debug('finished running'); self.emit('end'); }); } debug('start'); // callback this.on('end', function() { debug('end'); process.removeListener('uncaughtException', uncaught); fn(self.failures); }); // uncaught exception process.on('uncaughtException', uncaught); if (this._delay) { // for reporters, I guess. // might be nice to debounce some dots while we wait. this.emit('waiting', rootSuite); rootSuite.once('run', start); } else { start(); } return this; }; /** * Cleanly abort execution. * * @api public * @return {Runner} Runner instance. */ Runner.prototype.abort = function() { debug('aborting'); this._abort = true; return this; }; /** * Filter leaks with the given globals flagged as `ok`. * * @api private * @param {Array} ok * @param {Array} globals * @return {Array} */ function filterLeaks(ok, globals) { return filter(globals, function(key) { // Firefox and Chrome exposes iframes as index inside the window object if (/^d+/.test(key)) { return false; } // in firefox // if runner runs in an iframe, this iframe's window.getInterface method not init at first // it is assigned in some seconds if (global.navigator && (/^getInterface/).test(key)) { return false; } // an iframe could be approached by window[iframeIndex] // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak if (global.navigator && (/^\d+/).test(key)) { return false; } // Opera and IE expose global variables for HTML element IDs (issue #243) if (/^mocha-/.test(key)) { return false; } var matched = filter(ok, function(ok) { if (~ok.indexOf('*')) { return key.indexOf(ok.split('*')[0]) === 0; } return key === ok; }); return !matched.length && (!global.navigator || key !== 'onerror'); }); } /** * Array of globals dependent on the environment. * * @return {Array} * @api private */ function extraGlobals() { if (typeof process === 'object' && typeof process.version === 'string') { var parts = process.version.split('.'); var nodeVersion = utils.reduce(parts, function(a, v) { return a << 8 | v; }); // 'errno' was renamed to process._errno in v0.9.11. if (nodeVersion < 0x00090B) { return ['errno']; } } return []; } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./pending":16,"./runnable":35,"./utils":39,"_process":51,"debug":2,"events":3}],37:[function(require,module,exports){ /** * Module dependencies. */ var EventEmitter = require('events').EventEmitter; var Hook = require('./hook'); var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:suite'); var milliseconds = require('./ms'); /** * Expose `Suite`. */ exports = module.exports = Suite; /** * Create a new `Suite` with the given `title` and parent `Suite`. When a suite * with the same title is already present, that suite is returned to provide * nicer reporter and more flexible meta-testing. * * @api public * @param {Suite} parent * @param {string} title * @return {Suite} */ exports.create = function(parent, title) { var suite = new Suite(title, parent.ctx); suite.parent = parent; if (parent.pending) { suite.pending = true; } title = suite.fullTitle(); parent.addSuite(suite); return suite; }; /** * Initialize a new `Suite` with the given `title` and `ctx`. * * @api private * @param {string} title * @param {Context} parentContext */ function Suite(title, parentContext) { this.title = title; function Context() {} Context.prototype = parentContext; this.ctx = new Context(); this.suites = []; this.tests = []; this.pending = false; this._beforeEach = []; this._beforeAll = []; this._afterEach = []; this._afterAll = []; this.root = !title; this._timeout = 2000; this._enableTimeouts = true; this._slow = 75; this._bail = false; this.delayed = false; } /** * Inherit from `EventEmitter.prototype`. */ inherits(Suite, EventEmitter); /** * Return a clone of this `Suite`. * * @api private * @return {Suite} */ Suite.prototype.clone = function() { var suite = new Suite(this.title); debug('clone'); suite.ctx = this.ctx; suite.timeout(this.timeout()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); return suite; }; /** * Set timeout `ms` or short-hand such as "2s". * * @api private * @param {number|string} ms * @return {Suite|number} for chaining */ Suite.prototype.timeout = function(ms) { if (!arguments.length) { return this._timeout; } if (ms.toString() === '0') { this._enableTimeouts = false; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._timeout = parseInt(ms, 10); return this; }; /** * Set timeout to `enabled`. * * @api private * @param {boolean} enabled * @return {Suite|boolean} self or enabled */ Suite.prototype.enableTimeouts = function(enabled) { if (!arguments.length) { return this._enableTimeouts; } debug('enableTimeouts %s', enabled); this._enableTimeouts = enabled; return this; }; /** * Set slow `ms` or short-hand such as "2s". * * @api private * @param {number|string} ms * @return {Suite|number} for chaining */ Suite.prototype.slow = function(ms) { if (!arguments.length) { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('slow %d', ms); this._slow = ms; return this; }; /** * Sets whether to bail after first error. * * @api private * @param {boolean} bail * @return {Suite|number} for chaining */ Suite.prototype.bail = function(bail) { if (!arguments.length) { return this._bail; } debug('bail %s', bail); this._bail = bail; return this; }; /** * Run `fn(test[, done])` before running tests. * * @api private * @param {string} title * @param {Function} fn * @return {Suite} for chaining */ Suite.prototype.beforeAll = function(title, fn) { if (this.pending) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"before all" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._beforeAll.push(hook); this.emit('beforeAll', hook); return this; }; /** * Run `fn(test[, done])` after running tests. * * @api private * @param {string} title * @param {Function} fn * @return {Suite} for chaining */ Suite.prototype.afterAll = function(title, fn) { if (this.pending) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"after all" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._afterAll.push(hook); this.emit('afterAll', hook); return this; }; /** * Run `fn(test[, done])` before each test case. * * @api private * @param {string} title * @param {Function} fn * @return {Suite} for chaining */ Suite.prototype.beforeEach = function(title, fn) { if (this.pending) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"before each" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._beforeEach.push(hook); this.emit('beforeEach', hook); return this; }; /** * Run `fn(test[, done])` after each test case. * * @api private * @param {string} title * @param {Function} fn * @return {Suite} for chaining */ Suite.prototype.afterEach = function(title, fn) { if (this.pending) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"after each" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._afterEach.push(hook); this.emit('afterEach', hook); return this; }; /** * Add a test `suite`. * * @api private * @param {Suite} suite * @return {Suite} for chaining */ Suite.prototype.addSuite = function(suite) { suite.parent = this; suite.timeout(this.timeout()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); this.suites.push(suite); this.emit('suite', suite); return this; }; /** * Add a `test` to this suite. * * @api private * @param {Test} test * @return {Suite} for chaining */ Suite.prototype.addTest = function(test) { test.parent = this; test.timeout(this.timeout()); test.enableTimeouts(this.enableTimeouts()); test.slow(this.slow()); test.ctx = this.ctx; this.tests.push(test); this.emit('test', test); return this; }; /** * Return the full title generated by recursively concatenating the parent's * full title. * * @api public * @return {string} */ Suite.prototype.fullTitle = function() { if (this.parent) { var full = this.parent.fullTitle(); if (full) { return full + ' ' + this.title; } } return this.title; }; /** * Return the total number of tests. * * @api public * @return {number} */ Suite.prototype.total = function() { return utils.reduce(this.suites, function(sum, suite) { return sum + suite.total(); }, 0) + this.tests.length; }; /** * Iterates through each suite recursively to find all tests. Applies a * function in the format `fn(test)`. * * @api private * @param {Function} fn * @return {Suite} */ Suite.prototype.eachTest = function(fn) { utils.forEach(this.tests, fn); utils.forEach(this.suites, function(suite) { suite.eachTest(fn); }); return this; }; /** * This will run the root suite if we happen to be running in delayed mode. */ Suite.prototype.run = function run() { if (this.root) { this.emit('run'); } }; },{"./hook":7,"./ms":15,"./utils":39,"debug":2,"events":3}],38:[function(require,module,exports){ /** * Module dependencies. */ var Runnable = require('./runnable'); var inherits = require('./utils').inherits; /** * Expose `Test`. */ module.exports = Test; /** * Initialize a new `Test` with the given `title` and callback `fn`. * * @api private * @param {String} title * @param {Function} fn */ function Test(title, fn) { Runnable.call(this, title, fn); this.pending = !fn; this.type = 'test'; } /** * Inherit from `Runnable.prototype`. */ inherits(Test, Runnable); },{"./runnable":35,"./utils":39}],39:[function(require,module,exports){ (function (process,Buffer){ /* eslint-env browser */ /** * Module dependencies. */ var basename = require('path').basename; var debug = require('debug')('mocha:watch'); var exists = require('fs').existsSync || require('path').existsSync; var glob = require('glob'); var join = require('path').join; var readdirSync = require('fs').readdirSync; var statSync = require('fs').statSync; var watchFile = require('fs').watchFile; /** * Ignored directories. */ var ignore = ['node_modules', '.git']; exports.inherits = require('util').inherits; /** * Escape special characters in the given string of html. * * @api private * @param {string} html * @return {string} */ exports.escape = function(html) { return String(html) .replace(/&/g, '&') .replace(/"/g, '"') .replace(//g, '>'); }; /** * Array#forEach (<=IE8) * * @api private * @param {Array} arr * @param {Function} fn * @param {Object} scope */ exports.forEach = function(arr, fn, scope) { for (var i = 0, l = arr.length; i < l; i++) { fn.call(scope, arr[i], i); } }; /** * Test if the given obj is type of string. * * @api private * @param {Object} obj * @return {boolean} */ exports.isString = function(obj) { return typeof obj === 'string'; }; /** * Array#map (<=IE8) * * @api private * @param {Array} arr * @param {Function} fn * @param {Object} scope * @return {Array} */ exports.map = function(arr, fn, scope) { var result = []; for (var i = 0, l = arr.length; i < l; i++) { result.push(fn.call(scope, arr[i], i, arr)); } return result; }; /** * Array#indexOf (<=IE8) * * @api private * @param {Array} arr * @param {Object} obj to find index of * @param {number} start * @return {number} */ exports.indexOf = function(arr, obj, start) { for (var i = start || 0, l = arr.length; i < l; i++) { if (arr[i] === obj) { return i; } } return -1; }; /** * Array#reduce (<=IE8) * * @api private * @param {Array} arr * @param {Function} fn * @param {Object} val Initial value. * @return {*} */ exports.reduce = function(arr, fn, val) { var rval = val; for (var i = 0, l = arr.length; i < l; i++) { rval = fn(rval, arr[i], i, arr); } return rval; }; /** * Array#filter (<=IE8) * * @api private * @param {Array} arr * @param {Function} fn * @return {Array} */ exports.filter = function(arr, fn) { var ret = []; for (var i = 0, l = arr.length; i < l; i++) { var val = arr[i]; if (fn(val, i, arr)) { ret.push(val); } } return ret; }; /** * Object.keys (<=IE8) * * @api private * @param {Object} obj * @return {Array} keys */ exports.keys = typeof Object.keys === 'function' ? Object.keys : function(obj) { var keys = []; var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8 for (var key in obj) { if (has.call(obj, key)) { keys.push(key); } } return keys; }; /** * Watch the given `files` for changes * and invoke `fn(file)` on modification. * * @api private * @param {Array} files * @param {Function} fn */ exports.watch = function(files, fn) { var options = { interval: 100 }; files.forEach(function(file) { debug('file %s', file); watchFile(file, options, function(curr, prev) { if (prev.mtime < curr.mtime) { fn(file); } }); }); }; /** * Array.isArray (<=IE8) * * @api private * @param {Object} obj * @return {Boolean} */ var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }; /** * Buffer.prototype.toJSON polyfill. * * @type {Function} */ if (typeof Buffer !== 'undefined' && Buffer.prototype) { Buffer.prototype.toJSON = Buffer.prototype.toJSON || function() { return Array.prototype.slice.call(this, 0); }; } /** * Ignored files. * * @api private * @param {string} path * @return {boolean} */ function ignored(path) { return !~ignore.indexOf(path); } /** * Lookup files in the given `dir`. * * @api private * @param {string} dir * @param {string[]} [ext=['.js']] * @param {Array} [ret=[]] * @return {Array} */ exports.files = function(dir, ext, ret) { ret = ret || []; ext = ext || ['js']; var re = new RegExp('\\.(' + ext.join('|') + ')$'); readdirSync(dir) .filter(ignored) .forEach(function(path) { path = join(dir, path); if (statSync(path).isDirectory()) { exports.files(path, ext, ret); } else if (path.match(re)) { ret.push(path); } }); return ret; }; /** * Compute a slug from the given `str`. * * @api private * @param {string} str * @return {string} */ exports.slug = function(str) { return str .toLowerCase() .replace(/ +/g, '-') .replace(/[^-\w]/g, ''); }; /** * Strip the function definition from `str`, and re-indent for pre whitespace. * * @param {string} str * @return {string} */ exports.clean = function(str) { str = str .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') .replace(/^function *\(.*\)\s*{|\(.*\) *=> *{?/, '') .replace(/\s+\}$/, ''); var spaces = str.match(/^\n?( *)/)[1].length; var tabs = str.match(/^\n?(\t*)/)[1].length; var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); str = str.replace(re, ''); return exports.trim(str); }; /** * Trim the given `str`. * * @api private * @param {string} str * @return {string} */ exports.trim = function(str) { return str.replace(/^\s+|\s+$/g, ''); }; /** * Parse the given `qs`. * * @api private * @param {string} qs * @return {Object} */ exports.parseQuery = function(qs) { return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair) { var i = pair.indexOf('='); var key = pair.slice(0, i); var val = pair.slice(++i); obj[key] = decodeURIComponent(val); return obj; }, {}); }; /** * Highlight the given string of `js`. * * @api private * @param {string} js * @return {string} */ function highlight(js) { return js .replace(//g, '>') .replace(/\/\/(.*)/gm, '//$1') .replace(/('.*?')/gm, '$1') .replace(/(\d+\.\d+)/gm, '$1') .replace(/(\d+)/gm, '$1') .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1'); } /** * Highlight the contents of tag `name`. * * @api private * @param {string} name */ exports.highlightTags = function(name) { var code = document.getElementById('mocha').getElementsByTagName(name); for (var i = 0, len = code.length; i < len; ++i) { code[i].innerHTML = highlight(code[i].innerHTML); } }; /** * If a value could have properties, and has none, this function is called, * which returns a string representation of the empty value. * * Functions w/ no properties return `'[Function]'` * Arrays w/ length === 0 return `'[]'` * Objects w/ no properties return `'{}'` * All else: return result of `value.toString()` * * @api private * @param {*} value The value to inspect. * @param {string} [type] The type of the value, if known. * @returns {string} */ function emptyRepresentation(value, type) { type = type || exports.type(value); switch (type) { case 'function': return '[Function]'; case 'object': return '{}'; case 'array': return '[]'; default: return value.toString(); } } /** * Takes some variable and asks `Object.prototype.toString()` what it thinks it * is. * * @api private * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString * @param {*} value The value to test. * @returns {string} * @example * type({}) // 'object' * type([]) // 'array' * type(1) // 'number' * type(false) // 'boolean' * type(Infinity) // 'number' * type(null) // 'null' * type(new Date()) // 'date' * type(/foo/) // 'regexp' * type('type') // 'string' * type(global) // 'global' */ exports.type = function type(value) { if (value === undefined) { return 'undefined'; } else if (value === null) { return 'null'; } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { return 'buffer'; } return Object.prototype.toString.call(value) .replace(/^\[.+\s(.+?)\]$/, '$1') .toLowerCase(); }; /** * Stringify `value`. Different behavior depending on type of value: * * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively. * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes. * - If `value` is an *empty* object, function, or array, return result of function * {@link emptyRepresentation}. * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of * JSON.stringify(). * * @api private * @see exports.type * @param {*} value * @return {string} */ exports.stringify = function(value) { var type = exports.type(value); if (!~exports.indexOf(['object', 'array', 'function'], type)) { if (type !== 'buffer') { return jsonStringify(value); } var json = value.toJSON(); // Based on the toJSON result return jsonStringify(json.data && json.type ? json.data : json, 2) .replace(/,(\n|$)/g, '$1'); } for (var prop in value) { if (Object.prototype.hasOwnProperty.call(value, prop)) { return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1'); } } return emptyRepresentation(value, type); }; /** * like JSON.stringify but more sense. * * @api private * @param {Object} object * @param {number=} spaces * @param {number=} depth * @returns {*} */ function jsonStringify(object, spaces, depth) { if (typeof spaces === 'undefined') { // primitive types return _stringify(object); } depth = depth || 1; var space = spaces * depth; var str = isArray(object) ? '[' : '{'; var end = isArray(object) ? ']' : '}'; var length = object.length || exports.keys(object).length; // `.repeat()` polyfill function repeat(s, n) { return new Array(n).join(s); } function _stringify(val) { switch (exports.type(val)) { case 'null': case 'undefined': val = '[' + val + ']'; break; case 'array': case 'object': val = jsonStringify(val, spaces, depth + 1); break; case 'boolean': case 'regexp': case 'number': val = val === 0 && (1 / val) === -Infinity // `-0` ? '-0' : val.toString(); break; case 'date': var sDate = isNaN(val.getTime()) // Invalid date ? val.toString() : val.toISOString(); val = '[Date: ' + sDate + ']'; break; case 'buffer': var json = val.toJSON(); // Based on the toJSON result json = json.data && json.type ? json.data : json; val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']'; break; default: val = (val === '[Function]' || val === '[Circular]') ? val : JSON.stringify(val); // string } return val; } for (var i in object) { if (!object.hasOwnProperty(i)) { continue; // not my business } --length; str += '\n ' + repeat(' ', space) + (isArray(object) ? '' : '"' + i + '": ') // key + _stringify(object[i]) // value + (length ? ',' : ''); // comma } return str // [], {} + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end); } /** * Test if a value is a buffer. * * @api private * @param {*} value The value to test. * @return {boolean} True if `value` is a buffer, otherwise false */ exports.isBuffer = function(value) { return typeof Buffer !== 'undefined' && Buffer.isBuffer(value); }; /** * Return a new Thing that has the keys in sorted order. Recursive. * * If the Thing... * - has already been seen, return string `'[Circular]'` * - is `undefined`, return string `'[undefined]'` * - is `null`, return value `null` * - is some other primitive, return the value * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()` * * @api private * @see {@link exports.stringify} * @param {*} value Thing to inspect. May or may not have properties. * @param {Array} [stack=[]] Stack of seen values * @return {(Object|Array|Function|string|undefined)} */ exports.canonicalize = function(value, stack) { var canonicalizedObj; /* eslint-disable no-unused-vars */ var prop; /* eslint-enable no-unused-vars */ var type = exports.type(value); function withStack(value, fn) { stack.push(value); fn(); stack.pop(); } stack = stack || []; if (exports.indexOf(stack, value) !== -1) { return '[Circular]'; } switch (type) { case 'undefined': case 'buffer': case 'null': canonicalizedObj = value; break; case 'array': withStack(value, function() { canonicalizedObj = exports.map(value, function(item) { return exports.canonicalize(item, stack); }); }); break; case 'function': /* eslint-disable guard-for-in */ for (prop in value) { canonicalizedObj = {}; break; } /* eslint-enable guard-for-in */ if (!canonicalizedObj) { canonicalizedObj = emptyRepresentation(value, type); break; } /* falls through */ case 'object': canonicalizedObj = canonicalizedObj || {}; withStack(value, function() { exports.forEach(exports.keys(value).sort(), function(key) { canonicalizedObj[key] = exports.canonicalize(value[key], stack); }); }); break; case 'date': case 'number': case 'regexp': case 'boolean': canonicalizedObj = value; break; default: canonicalizedObj = value.toString(); } return canonicalizedObj; }; /** * Lookup file names at the given `path`. * * @api public * @param {string} path Base path to start searching from. * @param {string[]} extensions File extensions to look for. * @param {boolean} recursive Whether or not to recurse into subdirectories. * @return {string[]} An array of paths. */ exports.lookupFiles = function lookupFiles(path, extensions, recursive) { var files = []; var re = new RegExp('\\.(' + extensions.join('|') + ')$'); if (!exists(path)) { if (exists(path + '.js')) { path += '.js'; } else { files = glob.sync(path); if (!files.length) { throw new Error("cannot resolve path (or pattern) '" + path + "'"); } return files; } } try { var stat = statSync(path); if (stat.isFile()) { return path; } } catch (err) { // ignore error return; } readdirSync(path).forEach(function(file) { file = join(path, file); try { var stat = statSync(file); if (stat.isDirectory()) { if (recursive) { files = files.concat(lookupFiles(file, extensions, recursive)); } return; } } catch (err) { // ignore error return; } if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { return; } files.push(file); }); return files; }; /** * Generate an undefined error with a message warning the user. * * @return {Error} */ exports.undefinedError = function() { return new Error('Caught undefined error, did you throw without specifying what?'); }; /** * Generate an undefined error if `err` is not defined. * * @param {Error} err * @return {Error} */ exports.getError = function(err) { return err || exports.undefinedError(); }; /** * @summary * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`) * @description * When invoking this function you get a filter function that get the Error.stack as an input, * and return a prettify output. * (i.e: strip Mocha and internal node functions from stack trace). * @returns {Function} */ exports.stackTraceFilter = function() { // TODO: Replace with `process.browser` var slash = '/'; var is = typeof document === 'undefined' ? { node: true } : { browser: true }; var cwd = is.node ? process.cwd() + slash : (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^\/]*$/, '/'); function isMochaInternal(line) { return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) || (~line.indexOf('components' + slash + 'mochajs' + slash)) || (~line.indexOf('components' + slash + 'mocha' + slash)) || (~line.indexOf(slash + 'mocha.js')); } function isNodeInternal(line) { return (~line.indexOf('(timers.js:')) || (~line.indexOf('(events.js:')) || (~line.indexOf('(node.js:')) || (~line.indexOf('(module.js:')) || (~line.indexOf('GeneratorFunctionPrototype.next (native)')) || false; } return function(stack) { stack = stack.split('\n'); stack = exports.reduce(stack, function(list, line) { if (isMochaInternal(line)) { return list; } if (is.node && isNodeInternal(line)) { return list; } // Clean up cwd(absolute) list.push(line.replace(cwd, '')); return list; }, []); return stack.join('\n'); }; }; }).call(this,require('_process'),require("buffer").Buffer) },{"_process":51,"buffer":43,"debug":2,"fs":41,"glob":41,"path":41,"util":66}],40:[function(require,module,exports){ (function (process){ var WritableStream = require('stream').Writable var inherits = require('util').inherits module.exports = BrowserStdout inherits(BrowserStdout, WritableStream) function BrowserStdout(opts) { if (!(this instanceof BrowserStdout)) return new BrowserStdout(opts) opts = opts || {} WritableStream.call(this, opts) this.label = (opts.label !== undefined) ? opts.label : 'stdout' } BrowserStdout.prototype._write = function(chunks, encoding, cb) { var output = chunks.toString ? chunks.toString() : chunks if (this.label === false) { console.log(output) } else { console.log(this.label+':', output) } process.nextTick(cb) } }).call(this,require('_process')) },{"_process":51,"stream":63,"util":66}],41:[function(require,module,exports){ },{}],42:[function(require,module,exports){ arguments[4][41][0].apply(exports,arguments) },{"dup":41}],43:[function(require,module,exports){ /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ var base64 = require('base64-js') var ieee754 = require('ieee754') var isArray = require('is-array') exports.Buffer = Buffer exports.SlowBuffer = SlowBuffer exports.INSPECT_MAX_BYTES = 50 Buffer.poolSize = 8192 // not used by this implementation var rootParent = {} /** * If `Buffer.TYPED_ARRAY_SUPPORT`: * === true Use Uint8Array implementation (fastest) * === false Use Object implementation (most compatible, even IE6) * * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, * Opera 11.6+, iOS 4.2+. * * Due to various browser bugs, sometimes the Object implementation will be used even * when the browser supports typed arrays. * * Note: * * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. * * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property * on objects. * * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. * * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of * incorrect length in some situations. * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they * get the Object implementation, which is slower but behaves correctly. */ Buffer.TYPED_ARRAY_SUPPORT = (function () { function Bar () {} try { var arr = new Uint8Array(1) arr.foo = function () { return 42 } arr.constructor = Bar return arr.foo() === 42 && // typed array instances can be augmented arr.constructor === Bar && // constructor can be set typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` } catch (e) { return false } })() function kMaxLength () { return Buffer.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff } /** * Class: Buffer * ============= * * The Buffer constructor returns instances of `Uint8Array` that are augmented * with function properties for all the node `Buffer` API functions. We use * `Uint8Array` so that square bracket notation works as expected -- it returns * a single octet. * * By augmenting the instances, we can avoid modifying the `Uint8Array` * prototype. */ function Buffer (arg) { if (!(this instanceof Buffer)) { // Avoid going through an ArgumentsAdaptorTrampoline in the common case. if (arguments.length > 1) return new Buffer(arg, arguments[1]) return new Buffer(arg) } this.length = 0 this.parent = undefined // Common case. if (typeof arg === 'number') { return fromNumber(this, arg) } // Slightly less common case. if (typeof arg === 'string') { return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') } // Unusual. return fromObject(this, arg) } function fromNumber (that, length) { that = allocate(that, length < 0 ? 0 : checked(length) | 0) if (!Buffer.TYPED_ARRAY_SUPPORT) { for (var i = 0; i < length; i++) { that[i] = 0 } } return that } function fromString (that, string, encoding) { if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' // Assumption: byteLength() return value is always < kMaxLength. var length = byteLength(string, encoding) | 0 that = allocate(that, length) that.write(string, encoding) return that } function fromObject (that, object) { if (Buffer.isBuffer(object)) return fromBuffer(that, object) if (isArray(object)) return fromArray(that, object) if (object == null) { throw new TypeError('must start with number, buffer, array or string') } if (typeof ArrayBuffer !== 'undefined') { if (object.buffer instanceof ArrayBuffer) { return fromTypedArray(that, object) } if (object instanceof ArrayBuffer) { return fromArrayBuffer(that, object) } } if (object.length) return fromArrayLike(that, object) return fromJsonObject(that, object) } function fromBuffer (that, buffer) { var length = checked(buffer.length) | 0 that = allocate(that, length) buffer.copy(that, 0, 0, length) return that } function fromArray (that, array) { var length = checked(array.length) | 0 that = allocate(that, length) for (var i = 0; i < length; i += 1) { that[i] = array[i] & 255 } return that } // Duplicate of fromArray() to keep fromArray() monomorphic. function fromTypedArray (that, array) { var length = checked(array.length) | 0 that = allocate(that, length) // Truncating the elements is probably not what people expect from typed // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior // of the old Buffer constructor. for (var i = 0; i < length; i += 1) { that[i] = array[i] & 255 } return that } function fromArrayBuffer (that, array) { if (Buffer.TYPED_ARRAY_SUPPORT) { // Return an augmented `Uint8Array` instance, for best performance array.byteLength that = Buffer._augment(new Uint8Array(array)) } else { // Fallback: Return an object instance of the Buffer class that = fromTypedArray(that, new Uint8Array(array)) } return that } function fromArrayLike (that, array) { var length = checked(array.length) | 0 that = allocate(that, length) for (var i = 0; i < length; i += 1) { that[i] = array[i] & 255 } return that } // Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. // Returns a zero-length buffer for inputs that don't conform to the spec. function fromJsonObject (that, object) { var array var length = 0 if (object.type === 'Buffer' && isArray(object.data)) { array = object.data length = checked(array.length) | 0 } that = allocate(that, length) for (var i = 0; i < length; i += 1) { that[i] = array[i] & 255 } return that } function allocate (that, length) { if (Buffer.TYPED_ARRAY_SUPPORT) { // Return an augmented `Uint8Array` instance, for best performance that = Buffer._augment(new Uint8Array(length)) } else { // Fallback: Return an object instance of the Buffer class that.length = length that._isBuffer = true } var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 if (fromPool) that.parent = rootParent return that } function checked (length) { // Note: cannot use `length < kMaxLength` here because that fails when // length is NaN (which is otherwise coerced to zero.) if (length >= kMaxLength()) { throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength().toString(16) + ' bytes') } return length | 0 } function SlowBuffer (subject, encoding) { if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) var buf = new Buffer(subject, encoding) delete buf.parent return buf } Buffer.isBuffer = function isBuffer (b) { return !!(b != null && b._isBuffer) } Buffer.compare = function compare (a, b) { if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { throw new TypeError('Arguments must be Buffers') } if (a === b) return 0 var x = a.length var y = b.length var i = 0 var len = Math.min(x, y) while (i < len) { if (a[i] !== b[i]) break ++i } if (i !== len) { x = a[i] y = b[i] } if (x < y) return -1 if (y < x) return 1 return 0 } Buffer.isEncoding = function isEncoding (encoding) { switch (String(encoding).toLowerCase()) { case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'raw': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return true default: return false } } Buffer.concat = function concat (list, length) { if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') if (list.length === 0) { return new Buffer(0) } var i if (length === undefined) { length = 0 for (i = 0; i < list.length; i++) { length += list[i].length } } var buf = new Buffer(length) var pos = 0 for (i = 0; i < list.length; i++) { var item = list[i] item.copy(buf, pos) pos += item.length } return buf } function byteLength (string, encoding) { if (typeof string !== 'string') string = '' + string var len = string.length if (len === 0) return 0 // Use a for loop to avoid recursion var loweredCase = false for (;;) { switch (encoding) { case 'ascii': case 'binary': // Deprecated case 'raw': case 'raws': return len case 'utf8': case 'utf-8': return utf8ToBytes(string).length case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return len * 2 case 'hex': return len >>> 1 case 'base64': return base64ToBytes(string).length default: if (loweredCase) return utf8ToBytes(string).length // assume utf8 encoding = ('' + encoding).toLowerCase() loweredCase = true } } } Buffer.byteLength = byteLength // pre-set for values that may exist in the future Buffer.prototype.length = undefined Buffer.prototype.parent = undefined function slowToString (encoding, start, end) { var loweredCase = false start = start | 0 end = end === undefined || end === Infinity ? this.length : end | 0 if (!encoding) encoding = 'utf8' if (start < 0) start = 0 if (end > this.length) end = this.length if (end <= start) return '' while (true) { switch (encoding) { case 'hex': return hexSlice(this, start, end) case 'utf8': case 'utf-8': return utf8Slice(this, start, end) case 'ascii': return asciiSlice(this, start, end) case 'binary': return binarySlice(this, start, end) case 'base64': return base64Slice(this, start, end) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return utf16leSlice(this, start, end) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = (encoding + '').toLowerCase() loweredCase = true } } } Buffer.prototype.toString = function toString () { var length = this.length | 0 if (length === 0) return '' if (arguments.length === 0) return utf8Slice(this, 0, length) return slowToString.apply(this, arguments) } Buffer.prototype.equals = function equals (b) { if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return true return Buffer.compare(this, b) === 0 } Buffer.prototype.inspect = function inspect () { var str = '' var max = exports.INSPECT_MAX_BYTES if (this.length > 0) { str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') if (this.length > max) str += ' ... ' } return '' } Buffer.prototype.compare = function compare (b) { if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return 0 return Buffer.compare(this, b) } Buffer.prototype.indexOf = function indexOf (val, byteOffset) { if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff else if (byteOffset < -0x80000000) byteOffset = -0x80000000 byteOffset >>= 0 if (this.length === 0) return -1 if (byteOffset >= this.length) return -1 // Negative offsets start from the end of the buffer if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) if (typeof val === 'string') { if (val.length === 0) return -1 // special case: looking for empty string always fails return String.prototype.indexOf.call(this, val, byteOffset) } if (Buffer.isBuffer(val)) { return arrayIndexOf(this, val, byteOffset) } if (typeof val === 'number') { if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { return Uint8Array.prototype.indexOf.call(this, val, byteOffset) } return arrayIndexOf(this, [ val ], byteOffset) } function arrayIndexOf (arr, val, byteOffset) { var foundIndex = -1 for (var i = 0; byteOffset + i < arr.length; i++) { if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { if (foundIndex === -1) foundIndex = i if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex } else { foundIndex = -1 } } return -1 } throw new TypeError('val must be string, number or Buffer') } // `get` is deprecated Buffer.prototype.get = function get (offset) { console.log('.get() is deprecated. Access using array indexes instead.') return this.readUInt8(offset) } // `set` is deprecated Buffer.prototype.set = function set (v, offset) { console.log('.set() is deprecated. Access using array indexes instead.') return this.writeUInt8(v, offset) } function hexWrite (buf, string, offset, length) { offset = Number(offset) || 0 var remaining = buf.length - offset if (!length) { length = remaining } else { length = Number(length) if (length > remaining) { length = remaining } } // must be an even number of digits var strLen = string.length if (strLen % 2 !== 0) throw new Error('Invalid hex string') if (length > strLen / 2) { length = strLen / 2 } for (var i = 0; i < length; i++) { var parsed = parseInt(string.substr(i * 2, 2), 16) if (isNaN(parsed)) throw new Error('Invalid hex string') buf[offset + i] = parsed } return i } function utf8Write (buf, string, offset, length) { return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) } function asciiWrite (buf, string, offset, length) { return blitBuffer(asciiToBytes(string), buf, offset, length) } function binaryWrite (buf, string, offset, length) { return asciiWrite(buf, string, offset, length) } function base64Write (buf, string, offset, length) { return blitBuffer(base64ToBytes(string), buf, offset, length) } function ucs2Write (buf, string, offset, length) { return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) } Buffer.prototype.write = function write (string, offset, length, encoding) { // Buffer#write(string) if (offset === undefined) { encoding = 'utf8' length = this.length offset = 0 // Buffer#write(string, encoding) } else if (length === undefined && typeof offset === 'string') { encoding = offset length = this.length offset = 0 // Buffer#write(string, offset[, length][, encoding]) } else if (isFinite(offset)) { offset = offset | 0 if (isFinite(length)) { length = length | 0 if (encoding === undefined) encoding = 'utf8' } else { encoding = length length = undefined } // legacy write(string, encoding, offset, length) - remove in v0.13 } else { var swap = encoding encoding = offset offset = length | 0 length = swap } var remaining = this.length - offset if (length === undefined || length > remaining) length = remaining if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { throw new RangeError('attempt to write outside buffer bounds') } if (!encoding) encoding = 'utf8' var loweredCase = false for (;;) { switch (encoding) { case 'hex': return hexWrite(this, string, offset, length) case 'utf8': case 'utf-8': return utf8Write(this, string, offset, length) case 'ascii': return asciiWrite(this, string, offset, length) case 'binary': return binaryWrite(this, string, offset, length) case 'base64': // Warning: maxLength not taken into account in base64Write return base64Write(this, string, offset, length) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return ucs2Write(this, string, offset, length) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = ('' + encoding).toLowerCase() loweredCase = true } } } Buffer.prototype.toJSON = function toJSON () { return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) } } function base64Slice (buf, start, end) { if (start === 0 && end === buf.length) { return base64.fromByteArray(buf) } else { return base64.fromByteArray(buf.slice(start, end)) } } function utf8Slice (buf, start, end) { end = Math.min(buf.length, end) var res = [] var i = start while (i < end) { var firstByte = buf[i] var codePoint = null var bytesPerSequence = (firstByte > 0xEF) ? 4 : (firstByte > 0xDF) ? 3 : (firstByte > 0xBF) ? 2 : 1 if (i + bytesPerSequence <= end) { var secondByte, thirdByte, fourthByte, tempCodePoint switch (bytesPerSequence) { case 1: if (firstByte < 0x80) { codePoint = firstByte } break case 2: secondByte = buf[i + 1] if ((secondByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) if (tempCodePoint > 0x7F) { codePoint = tempCodePoint } } break case 3: secondByte = buf[i + 1] thirdByte = buf[i + 2] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { codePoint = tempCodePoint } } break case 4: secondByte = buf[i + 1] thirdByte = buf[i + 2] fourthByte = buf[i + 3] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { codePoint = tempCodePoint } } } } if (codePoint === null) { // we did not generate a valid codePoint so insert a // replacement char (U+FFFD) and advance only 1 byte codePoint = 0xFFFD bytesPerSequence = 1 } else if (codePoint > 0xFFFF) { // encode to utf16 (surrogate pair dance) codePoint -= 0x10000 res.push(codePoint >>> 10 & 0x3FF | 0xD800) codePoint = 0xDC00 | codePoint & 0x3FF } res.push(codePoint) i += bytesPerSequence } return decodeCodePointsArray(res) } // Based on http://stackoverflow.com/a/22747272/680742, the browser with // the lowest limit is Chrome, with 0x10000 args. // We go 1 magnitude less, for safety var MAX_ARGUMENTS_LENGTH = 0x1000 function decodeCodePointsArray (codePoints) { var len = codePoints.length if (len <= MAX_ARGUMENTS_LENGTH) { return String.fromCharCode.apply(String, codePoints) // avoid extra slice() } // Decode in chunks to avoid "call stack size exceeded". var res = '' var i = 0 while (i < len) { res += String.fromCharCode.apply( String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) ) } return res } function asciiSlice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) for (var i = start; i < end; i++) { ret += String.fromCharCode(buf[i] & 0x7F) } return ret } function binarySlice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) for (var i = start; i < end; i++) { ret += String.fromCharCode(buf[i]) } return ret } function hexSlice (buf, start, end) { var len = buf.length if (!start || start < 0) start = 0 if (!end || end < 0 || end > len) end = len var out = '' for (var i = start; i < end; i++) { out += toHex(buf[i]) } return out } function utf16leSlice (buf, start, end) { var bytes = buf.slice(start, end) var res = '' for (var i = 0; i < bytes.length; i += 2) { res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) } return res } Buffer.prototype.slice = function slice (start, end) { var len = this.length start = ~~start end = end === undefined ? len : ~~end if (start < 0) { start += len if (start < 0) start = 0 } else if (start > len) { start = len } if (end < 0) { end += len if (end < 0) end = 0 } else if (end > len) { end = len } if (end < start) end = start var newBuf if (Buffer.TYPED_ARRAY_SUPPORT) { newBuf = Buffer._augment(this.subarray(start, end)) } else { var sliceLen = end - start newBuf = new Buffer(sliceLen, undefined) for (var i = 0; i < sliceLen; i++) { newBuf[i] = this[i + start] } } if (newBuf.length) newBuf.parent = this.parent || this return newBuf } /* * Need to make sure that buffer isn't trying to write out of bounds. */ function checkOffset (offset, ext, length) { if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') } Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] var mul = 1 var i = 0 while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul } return val } Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) { checkOffset(offset, byteLength, this.length) } var val = this[offset + --byteLength] var mul = 1 while (byteLength > 0 && (mul *= 0x100)) { val += this[offset + --byteLength] * mul } return val } Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { if (!noAssert) checkOffset(offset, 1, this.length) return this[offset] } Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length) return this[offset] | (this[offset + 1] << 8) } Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length) return (this[offset] << 8) | this[offset + 1] } Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return ((this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16)) + (this[offset + 3] * 0x1000000) } Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] * 0x1000000) + ((this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]) } Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] var mul = 1 var i = 0 while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul } mul *= 0x80 if (val >= mul) val -= Math.pow(2, 8 * byteLength) return val } Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var i = byteLength var mul = 1 var val = this[offset + --i] while (i > 0 && (mul *= 0x100)) { val += this[offset + --i] * mul } mul *= 0x80 if (val >= mul) val -= Math.pow(2, 8 * byteLength) return val } Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { if (!noAssert) checkOffset(offset, 1, this.length) if (!(this[offset] & 0x80)) return (this[offset]) return ((0xff - this[offset] + 1) * -1) } Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset] | (this[offset + 1] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset + 1] | (this[offset] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16) | (this[offset + 3] << 24) } Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] << 24) | (this[offset + 1] << 16) | (this[offset + 2] << 8) | (this[offset + 3]) } Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, true, 23, 4) } Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, false, 23, 4) } Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, true, 52, 8) } Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, false, 52, 8) } function checkInt (buf, value, offset, ext, max, min) { if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') if (value > max || value < min) throw new RangeError('value is out of bounds') if (offset + ext > buf.length) throw new RangeError('index out of range') } Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { value = +value offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) var mul = 1 var i = 0 this[offset] = value & 0xFF while (++i < byteLength && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF } return offset + byteLength } Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { value = +value offset = offset | 0 byteLength = byteLength | 0 if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) var i = byteLength - 1 var mul = 1 this[offset + i] = value & 0xFF while (--i >= 0 && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF } return offset + byteLength } Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) this[offset] = value return offset + 1 } function objectWriteUInt16 (buf, value, offset, littleEndian) { if (value < 0) value = 0xffff + value + 1 for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> (littleEndian ? i : 1 - i) * 8 } } Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = value this[offset + 1] = (value >>> 8) } else { objectWriteUInt16(this, value, offset, true) } return offset + 2 } Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 8) this[offset + 1] = value } else { objectWriteUInt16(this, value, offset, false) } return offset + 2 } function objectWriteUInt32 (buf, value, offset, littleEndian) { if (value < 0) value = 0xffffffff + value + 1 for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff } } Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset + 3] = (value >>> 24) this[offset + 2] = (value >>> 16) this[offset + 1] = (value >>> 8) this[offset] = value } else { objectWriteUInt32(this, value, offset, true) } return offset + 4 } Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 24) this[offset + 1] = (value >>> 16) this[offset + 2] = (value >>> 8) this[offset + 3] = value } else { objectWriteUInt32(this, value, offset, false) } return offset + 4 } Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { value = +value offset = offset | 0 if (!noAssert) { var limit = Math.pow(2, 8 * byteLength - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } var i = 0 var mul = 1 var sub = value < 0 ? 1 : 0 this[offset] = value & 0xFF while (++i < byteLength && (mul *= 0x100)) { this[offset + i] = ((value / mul) >> 0) - sub & 0xFF } return offset + byteLength } Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { value = +value offset = offset | 0 if (!noAssert) { var limit = Math.pow(2, 8 * byteLength - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } var i = byteLength - 1 var mul = 1 var sub = value < 0 ? 1 : 0 this[offset + i] = value & 0xFF while (--i >= 0 && (mul *= 0x100)) { this[offset + i] = ((value / mul) >> 0) - sub & 0xFF } return offset + byteLength } Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) if (value < 0) value = 0xff + value + 1 this[offset] = value return offset + 1 } Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = value this[offset + 1] = (value >>> 8) } else { objectWriteUInt16(this, value, offset, true) } return offset + 2 } Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 8) this[offset + 1] = value } else { objectWriteUInt16(this, value, offset, false) } return offset + 2 } Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = value this[offset + 1] = (value >>> 8) this[offset + 2] = (value >>> 16) this[offset + 3] = (value >>> 24) } else { objectWriteUInt32(this, value, offset, true) } return offset + 4 } Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { value = +value offset = offset | 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) if (value < 0) value = 0xffffffff + value + 1 if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 24) this[offset + 1] = (value >>> 16) this[offset + 2] = (value >>> 8) this[offset + 3] = value } else { objectWriteUInt32(this, value, offset, false) } return offset + 4 } function checkIEEE754 (buf, value, offset, ext, max, min) { if (value > max || value < min) throw new RangeError('value is out of bounds') if (offset + ext > buf.length) throw new RangeError('index out of range') if (offset < 0) throw new RangeError('index out of range') } function writeFloat (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) } ieee754.write(buf, value, offset, littleEndian, 23, 4) return offset + 4 } Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { return writeFloat(this, value, offset, true, noAssert) } Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { return writeFloat(this, value, offset, false, noAssert) } function writeDouble (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) } ieee754.write(buf, value, offset, littleEndian, 52, 8) return offset + 8 } Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { return writeDouble(this, value, offset, true, noAssert) } Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { return writeDouble(this, value, offset, false, noAssert) } // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function copy (target, targetStart, start, end) { if (!start) start = 0 if (!end && end !== 0) end = this.length if (targetStart >= target.length) targetStart = target.length if (!targetStart) targetStart = 0 if (end > 0 && end < start) end = start // Copy 0 bytes; we're done if (end === start) return 0 if (target.length === 0 || this.length === 0) return 0 // Fatal error conditions if (targetStart < 0) { throw new RangeError('targetStart out of bounds') } if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') if (end < 0) throw new RangeError('sourceEnd out of bounds') // Are we oob? if (end > this.length) end = this.length if (target.length - targetStart < end - start) { end = target.length - targetStart + start } var len = end - start var i if (this === target && start < targetStart && targetStart < end) { // descending copy from end for (i = len - 1; i >= 0; i--) { target[i + targetStart] = this[i + start] } } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { // ascending copy from start for (i = 0; i < len; i++) { target[i + targetStart] = this[i + start] } } else { target._set(this.subarray(start, start + len), targetStart) } return len } // fill(value, start=0, end=buffer.length) Buffer.prototype.fill = function fill (value, start, end) { if (!value) value = 0 if (!start) start = 0 if (!end) end = this.length if (end < start) throw new RangeError('end < start') // Fill 0 bytes; we're done if (end === start) return if (this.length === 0) return if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') if (end < 0 || end > this.length) throw new RangeError('end out of bounds') var i if (typeof value === 'number') { for (i = start; i < end; i++) { this[i] = value } } else { var bytes = utf8ToBytes(value.toString()) var len = bytes.length for (i = start; i < end; i++) { this[i] = bytes[i % len] } } return this } /** * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. * Added in Node 0.12. Only available in browsers that support ArrayBuffer. */ Buffer.prototype.toArrayBuffer = function toArrayBuffer () { if (typeof Uint8Array !== 'undefined') { if (Buffer.TYPED_ARRAY_SUPPORT) { return (new Buffer(this)).buffer } else { var buf = new Uint8Array(this.length) for (var i = 0, len = buf.length; i < len; i += 1) { buf[i] = this[i] } return buf.buffer } } else { throw new TypeError('Buffer.toArrayBuffer not supported in this browser') } } // HELPER FUNCTIONS // ================ var BP = Buffer.prototype /** * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods */ Buffer._augment = function _augment (arr) { arr.constructor = Buffer arr._isBuffer = true // save reference to original Uint8Array set method before overwriting arr._set = arr.set // deprecated arr.get = BP.get arr.set = BP.set arr.write = BP.write arr.toString = BP.toString arr.toLocaleString = BP.toString arr.toJSON = BP.toJSON arr.equals = BP.equals arr.compare = BP.compare arr.indexOf = BP.indexOf arr.copy = BP.copy arr.slice = BP.slice arr.readUIntLE = BP.readUIntLE arr.readUIntBE = BP.readUIntBE arr.readUInt8 = BP.readUInt8 arr.readUInt16LE = BP.readUInt16LE arr.readUInt16BE = BP.readUInt16BE arr.readUInt32LE = BP.readUInt32LE arr.readUInt32BE = BP.readUInt32BE arr.readIntLE = BP.readIntLE arr.readIntBE = BP.readIntBE arr.readInt8 = BP.readInt8 arr.readInt16LE = BP.readInt16LE arr.readInt16BE = BP.readInt16BE arr.readInt32LE = BP.readInt32LE arr.readInt32BE = BP.readInt32BE arr.readFloatLE = BP.readFloatLE arr.readFloatBE = BP.readFloatBE arr.readDoubleLE = BP.readDoubleLE arr.readDoubleBE = BP.readDoubleBE arr.writeUInt8 = BP.writeUInt8 arr.writeUIntLE = BP.writeUIntLE arr.writeUIntBE = BP.writeUIntBE arr.writeUInt16LE = BP.writeUInt16LE arr.writeUInt16BE = BP.writeUInt16BE arr.writeUInt32LE = BP.writeUInt32LE arr.writeUInt32BE = BP.writeUInt32BE arr.writeIntLE = BP.writeIntLE arr.writeIntBE = BP.writeIntBE arr.writeInt8 = BP.writeInt8 arr.writeInt16LE = BP.writeInt16LE arr.writeInt16BE = BP.writeInt16BE arr.writeInt32LE = BP.writeInt32LE arr.writeInt32BE = BP.writeInt32BE arr.writeFloatLE = BP.writeFloatLE arr.writeFloatBE = BP.writeFloatBE arr.writeDoubleLE = BP.writeDoubleLE arr.writeDoubleBE = BP.writeDoubleBE arr.fill = BP.fill arr.inspect = BP.inspect arr.toArrayBuffer = BP.toArrayBuffer return arr } var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g function base64clean (str) { // Node strips out invalid characters like \n and \t from the string, base64-js does not str = stringtrim(str).replace(INVALID_BASE64_RE, '') // Node converts strings with length < 2 to '' if (str.length < 2) return '' // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not while (str.length % 4 !== 0) { str = str + '=' } return str } function stringtrim (str) { if (str.trim) return str.trim() return str.replace(/^\s+|\s+$/g, '') } function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) } function utf8ToBytes (string, units) { units = units || Infinity var codePoint var length = string.length var leadSurrogate = null var bytes = [] for (var i = 0; i < length; i++) { codePoint = string.charCodeAt(i) // is surrogate component if (codePoint > 0xD7FF && codePoint < 0xE000) { // last char was a lead if (!leadSurrogate) { // no lead yet if (codePoint > 0xDBFF) { // unexpected trail if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) continue } else if (i + 1 === length) { // unpaired lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) continue } // valid lead leadSurrogate = codePoint continue } // 2 leads in a row if (codePoint < 0xDC00) { if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) leadSurrogate = codePoint continue } // valid surrogate pair codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000 } else if (leadSurrogate) { // valid bmp char, but last char was a lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) } leadSurrogate = null // encode utf8 if (codePoint < 0x80) { if ((units -= 1) < 0) break bytes.push(codePoint) } else if (codePoint < 0x800) { if ((units -= 2) < 0) break bytes.push( codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x10000) { if ((units -= 3) < 0) break bytes.push( codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x110000) { if ((units -= 4) < 0) break bytes.push( codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else { throw new Error('Invalid code point') } } return bytes } function asciiToBytes (str) { var byteArray = [] for (var i = 0; i < str.length; i++) { // Node's code seems to be doing this and not & 0x7F.. byteArray.push(str.charCodeAt(i) & 0xFF) } return byteArray } function utf16leToBytes (str, units) { var c, hi, lo var byteArray = [] for (var i = 0; i < str.length; i++) { if ((units -= 2) < 0) break c = str.charCodeAt(i) hi = c >> 8 lo = c % 256 byteArray.push(lo) byteArray.push(hi) } return byteArray } function base64ToBytes (str) { return base64.toByteArray(base64clean(str)) } function blitBuffer (src, dst, offset, length) { for (var i = 0; i < length; i++) { if ((i + offset >= dst.length) || (i >= src.length)) break dst[i + offset] = src[i] } return i } },{"base64-js":44,"ieee754":45,"is-array":46}],44:[function(require,module,exports){ var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; ;(function (exports) { 'use strict'; var Arr = (typeof Uint8Array !== 'undefined') ? Uint8Array : Array var PLUS = '+'.charCodeAt(0) var SLASH = '/'.charCodeAt(0) var NUMBER = '0'.charCodeAt(0) var LOWER = 'a'.charCodeAt(0) var UPPER = 'A'.charCodeAt(0) var PLUS_URL_SAFE = '-'.charCodeAt(0) var SLASH_URL_SAFE = '_'.charCodeAt(0) function decode (elt) { var code = elt.charCodeAt(0) if (code === PLUS || code === PLUS_URL_SAFE) return 62 // '+' if (code === SLASH || code === SLASH_URL_SAFE) return 63 // '/' if (code < NUMBER) return -1 //no match if (code < NUMBER + 10) return code - NUMBER + 26 + 26 if (code < UPPER + 26) return code - UPPER if (code < LOWER + 26) return code - LOWER + 26 } function b64ToByteArray (b64) { var i, j, l, tmp, placeHolders, arr if (b64.length % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // the number of equal signs (place holders) // if there are two placeholders, than the two characters before it // represent one byte // if there is only one, then the three characters before it represent 2 bytes // this is just a cheap hack to not do indexOf twice var len = b64.length placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 // base64 is 4/3 + up to two characters of the original data arr = new Arr(b64.length * 3 / 4 - placeHolders) // if there are placeholders, only get up to the last complete 4 chars l = placeHolders > 0 ? b64.length - 4 : b64.length var L = 0 function push (v) { arr[L++] = v } for (i = 0, j = 0; i < l; i += 4, j += 3) { tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) push((tmp & 0xFF0000) >> 16) push((tmp & 0xFF00) >> 8) push(tmp & 0xFF) } if (placeHolders === 2) { tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) push(tmp & 0xFF) } else if (placeHolders === 1) { tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) push((tmp >> 8) & 0xFF) push(tmp & 0xFF) } return arr } function uint8ToBase64 (uint8) { var i, extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes output = "", temp, length function encode (num) { return lookup.charAt(num) } function tripletToBase64 (num) { return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) } // go through the array every three bytes, we'll deal with trailing stuff later for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) output += tripletToBase64(temp) } // pad the end with zeros, but make sure to not forget the extra bytes switch (extraBytes) { case 1: temp = uint8[uint8.length - 1] output += encode(temp >> 2) output += encode((temp << 4) & 0x3F) output += '==' break case 2: temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) output += encode(temp >> 10) output += encode((temp >> 4) & 0x3F) output += encode((temp << 2) & 0x3F) output += '=' break } return output } exports.toByteArray = b64ToByteArray exports.fromByteArray = uint8ToBase64 }(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) },{}],45:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = nBytes * 8 - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var nBits = -7 var i = isLE ? (nBytes - 1) : 0 var d = isLE ? -1 : 1 var s = buffer[offset + i] i += d e = s & ((1 << (-nBits)) - 1) s >>= (-nBits) nBits += eLen for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} m = e & ((1 << (-nBits)) - 1) e >>= (-nBits) nBits += mLen for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} if (e === 0) { e = 1 - eBias } else if (e === eMax) { return m ? NaN : ((s ? -1 : 1) * Infinity) } else { m = m + Math.pow(2, mLen) e = e - eBias } return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { var e, m, c var eLen = nBytes * 8 - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) var i = isLE ? 0 : (nBytes - 1) var d = isLE ? 1 : -1 var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 value = Math.abs(value) if (isNaN(value) || value === Infinity) { m = isNaN(value) ? 1 : 0 e = eMax } else { e = Math.floor(Math.log(value) / Math.LN2) if (value * (c = Math.pow(2, -e)) < 1) { e-- c *= 2 } if (e + eBias >= 1) { value += rt / c } else { value += rt * Math.pow(2, 1 - eBias) } if (value * c >= 2) { e++ c /= 2 } if (e + eBias >= eMax) { m = 0 e = eMax } else if (e + eBias >= 1) { m = (value * c - 1) * Math.pow(2, mLen) e = e + eBias } else { m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) e = 0 } } for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} e = (e << mLen) | m eLen += mLen for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} buffer[offset + i - d] |= s * 128 } },{}],46:[function(require,module,exports){ /** * isArray */ var isArray = Array.isArray; /** * toString */ var str = Object.prototype.toString; /** * Whether or not the given `val` * is an array. * * example: * * isArray([]); * // > true * isArray(arguments); * // > false * isArray(''); * // > false * * @param {mixed} val * @return {bool} */ module.exports = isArray || function (val) { return !! val && '[object Array]' == str.call(val); }; },{}],47:[function(require,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; } },{}],48:[function(require,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 } } },{}],49:[function(require,module,exports){ module.exports = Array.isArray || function (arr) { return Object.prototype.toString.call(arr) == '[object Array]'; }; },{}],50:[function(require,module,exports){ exports.endianness = function () { return 'LE' }; exports.hostname = function () { if (typeof location !== 'undefined') { return location.hostname } else return ''; }; exports.loadavg = function () { return [] }; exports.uptime = function () { return 0 }; exports.freemem = function () { return Number.MAX_VALUE; }; exports.totalmem = function () { return Number.MAX_VALUE; }; exports.cpus = function () { return [] }; exports.type = function () { return 'Browser' }; exports.release = function () { if (typeof navigator !== 'undefined') { return navigator.appVersion; } return ''; }; exports.networkInterfaces = exports.getNetworkInterfaces = function () { return {} }; exports.arch = function () { return 'javascript' }; exports.platform = function () { return 'browser' }; exports.tmpdir = exports.tmpDir = function () { return '/tmp'; }; exports.EOL = '\n'; },{}],51:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = setTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; clearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { setTimeout(drainQueue, 0); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; 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'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; },{}],52:[function(require,module,exports){ module.exports = require("./lib/_stream_duplex.js") },{"./lib/_stream_duplex.js":53}],53:[function(require,module,exports){ (function (process){ // 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. // a duplex stream is just a stream that is both readable and writable. // Since JS doesn't have multiple prototypal inheritance, this class // prototypally inherits from Readable, and then parasitically from // Writable. module.exports = Duplex; /**/ var objectKeys = Object.keys || function (obj) { var keys = []; for (var key in obj) keys.push(key); return keys; } /**/ /**/ var util = require('core-util-is'); util.inherits = require('inherits'); /**/ var Readable = require('./_stream_readable'); var Writable = require('./_stream_writable'); util.inherits(Duplex, Readable); forEach(objectKeys(Writable.prototype), function(method) { if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; }); function Duplex(options) { if (!(this instanceof Duplex)) return new Duplex(options); Readable.call(this, options); Writable.call(this, options); if (options && options.readable === false) this.readable = false; if (options && options.writable === false) this.writable = false; this.allowHalfOpen = true; if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; this.once('end', onend); } // the no-half-open enforcer function onend() { // if we allow half-open state, or if the writable side ended, // then we're ok. if (this.allowHalfOpen || this._writableState.ended) return; // no more data can be written. // But allow more writes to happen in this tick. process.nextTick(this.end.bind(this)); } function forEach (xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } } }).call(this,require('_process')) },{"./_stream_readable":55,"./_stream_writable":57,"_process":51,"core-util-is":58,"inherits":48}],54:[function(require,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. // a passthrough stream. // basically just the most minimal sort of Transform stream. // Every written chunk gets output as-is. module.exports = PassThrough; var Transform = require('./_stream_transform'); /**/ var util = require('core-util-is'); util.inherits = require('inherits'); /**/ util.inherits(PassThrough, Transform); function PassThrough(options) { if (!(this instanceof PassThrough)) return new PassThrough(options); Transform.call(this, options); } PassThrough.prototype._transform = function(chunk, encoding, cb) { cb(null, chunk); }; },{"./_stream_transform":56,"core-util-is":58,"inherits":48}],55:[function(require,module,exports){ (function (process){ // 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. module.exports = Readable; /**/ var isArray = require('isarray'); /**/ /**/ var Buffer = require('buffer').Buffer; /**/ Readable.ReadableState = ReadableState; var EE = require('events').EventEmitter; /**/ if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { return emitter.listeners(type).length; }; /**/ var Stream = require('stream'); /**/ var util = require('core-util-is'); util.inherits = require('inherits'); /**/ var StringDecoder; /**/ var debug = require('util'); if (debug && debug.debuglog) { debug = debug.debuglog('stream'); } else { debug = function () {}; } /**/ util.inherits(Readable, Stream); function ReadableState(options, stream) { var Duplex = require('./_stream_duplex'); options = options || {}; // the point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" var hwm = options.highWaterMark; var defaultHwm = options.objectMode ? 16 : 16 * 1024; this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; // cast to ints. this.highWaterMark = ~~this.highWaterMark; this.buffer = []; this.length = 0; this.pipes = null; this.pipesCount = 0; this.flowing = null; this.ended = false; this.endEmitted = false; this.reading = false; // a flag to be able to tell if the onwrite cb is called immediately, // or on a later tick. We set this to true at first, because any // actions that shouldn't happen until "later" should generally also // not happen before the first write call. this.sync = true; // whenever we return null, then we set a flag to say // that we're awaiting a 'readable' event emission. this.needReadable = false; this.emittedReadable = false; this.readableListening = false; // object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away this.objectMode = !!options.objectMode; if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. this.defaultEncoding = options.defaultEncoding || 'utf8'; // when piping, we only care about 'readable' events that happen // after read()ing all the bytes and not getting any pushback. this.ranOut = false; // the number of writers that are awaiting a drain event in .pipe()s this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled this.readingMore = false; this.decoder = null; this.encoding = null; if (options.encoding) { if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; this.decoder = new StringDecoder(options.encoding); this.encoding = options.encoding; } } function Readable(options) { var Duplex = require('./_stream_duplex'); if (!(this instanceof Readable)) return new Readable(options); this._readableState = new ReadableState(options, this); // legacy this.readable = true; Stream.call(this); } // Manually shove something into the read() buffer. // This returns true if the highWaterMark has not been hit yet, // similar to how Writable.write() returns true if you should // write() some more. Readable.prototype.push = function(chunk, encoding) { var state = this._readableState; if (util.isString(chunk) && !state.objectMode) { encoding = encoding || state.defaultEncoding; if (encoding !== state.encoding) { chunk = new Buffer(chunk, encoding); encoding = ''; } } return readableAddChunk(this, state, chunk, encoding, false); }; // Unshift should *always* be something directly out of read() Readable.prototype.unshift = function(chunk) { var state = this._readableState; return readableAddChunk(this, state, chunk, '', true); }; function readableAddChunk(stream, state, chunk, encoding, addToFront) { var er = chunkInvalid(state, chunk); if (er) { stream.emit('error', er); } else if (util.isNullOrUndefined(chunk)) { state.reading = false; if (!state.ended) onEofChunk(stream, state); } else if (state.objectMode || chunk && chunk.length > 0) { if (state.ended && !addToFront) { var e = new Error('stream.push() after EOF'); stream.emit('error', e); } else if (state.endEmitted && addToFront) { var e = new Error('stream.unshift() after end event'); stream.emit('error', e); } else { if (state.decoder && !addToFront && !encoding) chunk = state.decoder.write(chunk); if (!addToFront) state.reading = false; // if we want the data now, just emit it. if (state.flowing && state.length === 0 && !state.sync) { stream.emit('data', chunk); stream.read(0); } else { // update the buffer info. state.length += state.objectMode ? 1 : chunk.length; if (addToFront) state.buffer.unshift(chunk); else state.buffer.push(chunk); if (state.needReadable) emitReadable(stream); } maybeReadMore(stream, state); } } else if (!addToFront) { state.reading = false; } return needMoreData(state); } // if it's past the high water mark, we can push in some more. // Also, if we have no data yet, we can stand some // more bytes. This is to work around cases where hwm=0, // such as the repl. Also, if the push() triggered a // readable event, and the user called read(largeNumber) such that // needReadable was set, then we ought to push more, so that another // 'readable' event will be triggered. function needMoreData(state) { return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); } // backwards compatibility. Readable.prototype.setEncoding = function(enc) { if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; this._readableState.decoder = new StringDecoder(enc); this._readableState.encoding = enc; return this; }; // Don't raise the hwm > 128MB var MAX_HWM = 0x800000; function roundUpToNextPowerOf2(n) { if (n >= MAX_HWM) { n = MAX_HWM; } else { // Get the next highest power of 2 n--; for (var p = 1; p < 32; p <<= 1) n |= n >> p; n++; } return n; } function howMuchToRead(n, state) { if (state.length === 0 && state.ended) return 0; if (state.objectMode) return n === 0 ? 0 : 1; if (isNaN(n) || util.isNull(n)) { // only flow one buffer at a time if (state.flowing && state.buffer.length) return state.buffer[0].length; else return state.length; } if (n <= 0) return 0; // If we're asking for more than the target buffer level, // then raise the water mark. Bump up to the next highest // power of 2, to prevent increasing it excessively in tiny // amounts. if (n > state.highWaterMark) state.highWaterMark = roundUpToNextPowerOf2(n); // don't have that much. return null, unless we've ended. if (n > state.length) { if (!state.ended) { state.needReadable = true; return 0; } else return state.length; } return n; } // you can override either this method, or the async _read(n) below. Readable.prototype.read = function(n) { debug('read', n); var state = this._readableState; var nOrig = n; if (!util.isNumber(n) || n > 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we // already have a bunch of data in the buffer, then just trigger // the 'readable' event and move on. if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { debug('read: emitReadable', state.length, state.ended); if (state.length === 0 && state.ended) endReadable(this); else emitReadable(this); return null; } n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up. if (n === 0 && state.ended) { if (state.length === 0) endReadable(this); return null; } // All the actual chunk generation logic needs to be // *below* the call to _read. The reason is that in certain // synthetic stream cases, such as passthrough streams, _read // may be a completely synchronous operation which may change // the state of the read buffer, providing enough data when // before there was *not* enough. // // So, the steps are: // 1. Figure out what the state of things will be after we do // a read from the buffer. // // 2. If that resulting state will trigger a _read, then call _read. // Note that this may be asynchronous, or synchronous. Yes, it is // deeply ugly to write APIs this way, but that still doesn't mean // that the Readable class should behave improperly, as streams are // designed to be sync/async agnostic. // Take note if the _read call is sync or async (ie, if the read call // has returned yet), so that we know whether or not it's safe to emit // 'readable' etc. // // 3. Actually pull the requested chunks out of the buffer and return. // if we need a readable event, then we need to do some reading. var doRead = state.needReadable; debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some if (state.length === 0 || state.length - n < state.highWaterMark) { doRead = true; debug('length less than watermark', doRead); } // however, if we've ended, then there's no point, and if we're already // reading, then it's unnecessary. if (state.ended || state.reading) { doRead = false; debug('reading or ended', doRead); } if (doRead) { debug('do read'); state.reading = true; state.sync = true; // if the length is currently zero, then we *need* a readable event. if (state.length === 0) state.needReadable = true; // call internal read method this._read(state.highWaterMark); state.sync = false; } // If _read pushed data synchronously, then `reading` will be false, // and we need to re-evaluate how much data we can return to the user. if (doRead && !state.reading) n = howMuchToRead(nOrig, state); var ret; if (n > 0) ret = fromList(n, state); else ret = null; if (util.isNull(ret)) { state.needReadable = true; n = 0; } state.length -= n; // If we have nothing in the buffer, then we want to know // as soon as we *do* get something into the buffer. if (state.length === 0 && !state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick. if (nOrig !== n && state.ended && state.length === 0) endReadable(this); if (!util.isNull(ret)) this.emit('data', ret); return ret; }; function chunkInvalid(state, chunk) { var er = null; if (!util.isBuffer(chunk) && !util.isString(chunk) && !util.isNullOrUndefined(chunk) && !state.objectMode) { er = new TypeError('Invalid non-string/buffer chunk'); } return er; } function onEofChunk(stream, state) { if (state.decoder && !state.ended) { var chunk = state.decoder.end(); if (chunk && chunk.length) { state.buffer.push(chunk); state.length += state.objectMode ? 1 : chunk.length; } } state.ended = true; // emit 'readable' now to make sure it gets picked up. emitReadable(stream); } // Don't emit readable right away in sync mode, because this can trigger // another read() call => stack overflow. This way, it might trigger // a nextTick recursion warning, but that's not so bad. function emitReadable(stream) { var state = stream._readableState; state.needReadable = false; if (!state.emittedReadable) { debug('emitReadable', state.flowing); state.emittedReadable = true; if (state.sync) process.nextTick(function() { emitReadable_(stream); }); else emitReadable_(stream); } } function emitReadable_(stream) { debug('emit readable'); stream.emit('readable'); flow(stream); } // at this point, the user has presumably seen the 'readable' event, // and called read() to consume some data. that may have triggered // in turn another _read(n) call, in which case reading = true if // it's in progress. // However, if we're not ended, or reading, and the length < hwm, // then go ahead and try to read some more preemptively. function maybeReadMore(stream, state) { if (!state.readingMore) { state.readingMore = true; process.nextTick(function() { maybeReadMore_(stream, state); }); } } function maybeReadMore_(stream, state) { var len = state.length; while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { debug('maybeReadMore read 0'); stream.read(0); if (len === state.length) // didn't get any data, stop spinning. break; else len = state.length; } state.readingMore = false; } // abstract method. to be overridden in specific implementation classes. // call cb(er, data) where data is <= n in length. // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function(n) { this.emit('error', new Error('not implemented')); }; Readable.prototype.pipe = function(dest, pipeOpts) { var src = this; var state = this._readableState; switch (state.pipesCount) { case 0: state.pipes = dest; break; case 1: state.pipes = [state.pipes, dest]; break; default: state.pipes.push(dest); break; } state.pipesCount += 1; debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; var endFn = doEnd ? onend : cleanup; if (state.endEmitted) process.nextTick(endFn); else src.once('end', endFn); dest.on('unpipe', onunpipe); function onunpipe(readable) { debug('onunpipe'); if (readable === src) { cleanup(); } } function onend() { debug('onend'); dest.end(); } // when the dest drains, it reduces the awaitDrain counter // on the source. This would be more elegant with a .once() // handler in flow(), but adding and removing repeatedly is // too slow. var ondrain = pipeOnDrain(src); dest.on('drain', ondrain); function cleanup() { debug('cleanup'); // cleanup event handlers once the pipe is broken dest.removeListener('close', onclose); dest.removeListener('finish', onfinish); dest.removeListener('drain', ondrain); dest.removeListener('error', onerror); dest.removeListener('unpipe', onunpipe); src.removeListener('end', onend); src.removeListener('end', cleanup); src.removeListener('data', ondata); // if the reader is waiting for a drain event from this // specific writer, then it would cause it to never start // flowing again. // So, if this is awaiting a drain, then we just call it now. // If we don't know, then assume that we are waiting for one. if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); } src.on('data', ondata); function ondata(chunk) { debug('ondata'); var ret = dest.write(chunk); if (false === ret) { debug('false write response, pause', src._readableState.awaitDrain); src._readableState.awaitDrain++; src.pause(); } } // if the dest has an error, then stop piping into it. // however, don't suppress the throwing behavior for this. function onerror(er) { debug('onerror', er); unpipe(); dest.removeListener('error', onerror); if (EE.listenerCount(dest, 'error') === 0) dest.emit('error', er); } // This is a brutally ugly hack to make sure that our error handler // is attached before any userland ones. NEVER DO THIS. if (!dest._events || !dest._events.error) dest.on('error', onerror); else if (isArray(dest._events.error)) dest._events.error.unshift(onerror); else dest._events.error = [onerror, dest._events.error]; // Both close and finish should trigger unpipe, but only once. function onclose() { dest.removeListener('finish', onfinish); unpipe(); } dest.once('close', onclose); function onfinish() { debug('onfinish'); dest.removeListener('close', onclose); unpipe(); } dest.once('finish', onfinish); function unpipe() { debug('unpipe'); src.unpipe(dest); } // tell the dest that it's being piped to dest.emit('pipe', src); // start the flow if it hasn't been started already. if (!state.flowing) { debug('pipe resume'); src.resume(); } return dest; }; function pipeOnDrain(src) { return function() { var state = src._readableState; debug('pipeOnDrain', state.awaitDrain); if (state.awaitDrain) state.awaitDrain--; if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) { state.flowing = true; flow(src); } }; } Readable.prototype.unpipe = function(dest) { var state = this._readableState; // if we're not piping anywhere, then do nothing. if (state.pipesCount === 0) return this; // just one destination. most common case. if (state.pipesCount === 1) { // passed in one, but it's not the right one. if (dest && dest !== state.pipes) return this; if (!dest) dest = state.pipes; // got a match. state.pipes = null; state.pipesCount = 0; state.flowing = false; if (dest) dest.emit('unpipe', this); return this; } // slow case. multiple pipe destinations. if (!dest) { // remove all. var dests = state.pipes; var len = state.pipesCount; state.pipes = null; state.pipesCount = 0; state.flowing = false; for (var i = 0; i < len; i++) dests[i].emit('unpipe', this); return this; } // try to find the right one. var i = indexOf(state.pipes, dest); if (i === -1) return this; state.pipes.splice(i, 1); state.pipesCount -= 1; if (state.pipesCount === 1) state.pipes = state.pipes[0]; dest.emit('unpipe', this); return this; }; // set up data events if they are asked for // Ensure readable listeners eventually get something Readable.prototype.on = function(ev, fn) { var res = Stream.prototype.on.call(this, ev, fn); // If listening to data, and it has not explicitly been paused, // then call resume to start the flow of data on the next tick. if (ev === 'data' && false !== this._readableState.flowing) { this.resume(); } if (ev === 'readable' && this.readable) { var state = this._readableState; if (!state.readableListening) { state.readableListening = true; state.emittedReadable = false; state.needReadable = true; if (!state.reading) { var self = this; process.nextTick(function() { debug('readable nexttick read 0'); self.read(0); }); } else if (state.length) { emitReadable(this, state); } } } return res; }; Readable.prototype.addListener = Readable.prototype.on; // pause() and resume() are remnants of the legacy readable stream API // If the user uses them, then switch into old mode. Readable.prototype.resume = function() { var state = this._readableState; if (!state.flowing) { debug('resume'); state.flowing = true; if (!state.reading) { debug('resume read 0'); this.read(0); } resume(this, state); } return this; }; function resume(stream, state) { if (!state.resumeScheduled) { state.resumeScheduled = true; process.nextTick(function() { resume_(stream, state); }); } } function resume_(stream, state) { state.resumeScheduled = false; stream.emit('resume'); flow(stream); if (state.flowing && !state.reading) stream.read(0); } Readable.prototype.pause = function() { debug('call pause flowing=%j', this._readableState.flowing); if (false !== this._readableState.flowing) { debug('pause'); this._readableState.flowing = false; this.emit('pause'); } return this; }; function flow(stream) { var state = stream._readableState; debug('flow', state.flowing); if (state.flowing) { do { var chunk = stream.read(); } while (null !== chunk && state.flowing); } } // wrap an old-style stream as the async data source. // This is *not* part of the readable stream interface. // It is an ugly unfortunate mess of history. Readable.prototype.wrap = function(stream) { var state = this._readableState; var paused = false; var self = this; stream.on('end', function() { debug('wrapped end'); if (state.decoder && !state.ended) { var chunk = state.decoder.end(); if (chunk && chunk.length) self.push(chunk); } self.push(null); }); stream.on('data', function(chunk) { debug('wrapped data'); if (state.decoder) chunk = state.decoder.write(chunk); if (!chunk || !state.objectMode && !chunk.length) return; var ret = self.push(chunk); if (!ret) { paused = true; stream.pause(); } }); // proxy all the other methods. // important when wrapping filters and duplexes. for (var i in stream) { if (util.isFunction(stream[i]) && util.isUndefined(this[i])) { this[i] = function(method) { return function() { return stream[method].apply(stream, arguments); }}(i); } } // proxy certain important events. var events = ['error', 'close', 'destroy', 'pause', 'resume']; forEach(events, function(ev) { stream.on(ev, self.emit.bind(self, ev)); }); // when we try to consume some more bytes, simply unpause the // underlying stream. self._read = function(n) { debug('wrapped _read', n); if (paused) { paused = false; stream.resume(); } }; return self; }; // exposed for testing purposes only. Readable._fromList = fromList; // Pluck off n bytes from an array of buffers. // Length is the combined lengths of all the buffers in the list. function fromList(n, state) { var list = state.buffer; var length = state.length; var stringMode = !!state.decoder; var objectMode = !!state.objectMode; var ret; // nothing in the list, definitely empty. if (list.length === 0) return null; if (length === 0) ret = null; else if (objectMode) ret = list.shift(); else if (!n || n >= length) { // read it all, truncate the array. if (stringMode) ret = list.join(''); else ret = Buffer.concat(list, length); list.length = 0; } else { // read just some of it. if (n < list[0].length) { // just take a part of the first list item. // slice is the same for buffers and strings. var buf = list[0]; ret = buf.slice(0, n); list[0] = buf.slice(n); } else if (n === list[0].length) { // first list is a perfect match ret = list.shift(); } else { // complex case. // we have enough to cover it, but it spans past the first buffer. if (stringMode) ret = ''; else ret = new Buffer(n); var c = 0; for (var i = 0, l = list.length; i < l && c < n; i++) { var buf = list[0]; var cpy = Math.min(n - c, buf.length); if (stringMode) ret += buf.slice(0, cpy); else buf.copy(ret, c, 0, cpy); if (cpy < buf.length) list[0] = buf.slice(cpy); else list.shift(); c += cpy; } } } return ret; } function endReadable(stream) { var state = stream._readableState; // If we get here before consuming all the bytes, then that is a // bug in node. Should never happen. if (state.length > 0) throw new Error('endReadable called on non-empty stream'); if (!state.endEmitted) { state.ended = true; process.nextTick(function() { // Check that we didn't get one last unshift. if (!state.endEmitted && state.length === 0) { state.endEmitted = true; stream.readable = false; stream.emit('end'); } }); } } function forEach (xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } } function indexOf (xs, x) { for (var i = 0, l = xs.length; i < l; i++) { if (xs[i] === x) return i; } return -1; } }).call(this,require('_process')) },{"./_stream_duplex":53,"_process":51,"buffer":43,"core-util-is":58,"events":47,"inherits":48,"isarray":49,"stream":63,"string_decoder/":64,"util":42}],56:[function(require,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. // a transform stream is a readable/writable stream where you do // something with the data. Sometimes it's called a "filter", // but that's not a great name for it, since that implies a thing where // some bits pass through, and others are simply ignored. (That would // be a valid example of a transform, of course.) // // While the output is causally related to the input, it's not a // necessarily symmetric or synchronous transformation. For example, // a zlib stream might take multiple plain-text writes(), and then // emit a single compressed chunk some time in the future. // // Here's how this works: // // The Transform stream has all the aspects of the readable and writable // stream classes. When you write(chunk), that calls _write(chunk,cb) // internally, and returns false if there's a lot of pending writes // buffered up. When you call read(), that calls _read(n) until // there's enough pending readable data buffered up. // // In a transform stream, the written data is placed in a buffer. When // _read(n) is called, it transforms the queued up data, calling the // buffered _write cb's as it consumes chunks. If consuming a single // written chunk would result in multiple output chunks, then the first // outputted bit calls the readcb, and subsequent chunks just go into // the read buffer, and will cause it to emit 'readable' if necessary. // // This way, back-pressure is actually determined by the reading side, // since _read has to be called to start processing a new chunk. However, // a pathological inflate type of transform can cause excessive buffering // here. For example, imagine a stream where every byte of input is // interpreted as an integer from 0-255, and then results in that many // bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in // 1kb of data being output. In this case, you could write a very small // amount of input, and end up with a very large amount of output. In // such a pathological inflating mechanism, there'd be no way to tell // the system to stop doing the transform. A single 4MB write could // cause the system to run out of memory. // // However, even in such a pathological case, only a single written chunk // would be consumed, and then the rest would wait (un-transformed) until // the results of the previous transformed chunk were consumed. module.exports = Transform; var Duplex = require('./_stream_duplex'); /**/ var util = require('core-util-is'); util.inherits = require('inherits'); /**/ util.inherits(Transform, Duplex); function TransformState(options, stream) { this.afterTransform = function(er, data) { return afterTransform(stream, er, data); }; this.needTransform = false; this.transforming = false; this.writecb = null; this.writechunk = null; } function afterTransform(stream, er, data) { var ts = stream._transformState; ts.transforming = false; var cb = ts.writecb; if (!cb) return stream.emit('error', new Error('no writecb in Transform class')); ts.writechunk = null; ts.writecb = null; if (!util.isNullOrUndefined(data)) stream.push(data); if (cb) cb(er); var rs = stream._readableState; rs.reading = false; if (rs.needReadable || rs.length < rs.highWaterMark) { stream._read(rs.highWaterMark); } } function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(options, this); // when the writable side finishes, then flush out anything remaining. var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; this.once('prefinish', function() { if (util.isFunction(this._flush)) this._flush(function(er) { done(stream, er); }); else done(stream); }); } Transform.prototype.push = function(chunk, encoding) { this._transformState.needTransform = false; return Duplex.prototype.push.call(this, chunk, encoding); }; // This is the part where you do stuff! // override this function in implementation classes. // 'chunk' is an input chunk. // // Call `push(newChunk)` to pass along transformed output // to the readable side. You may call 'push' zero or more times. // // Call `cb(err)` when you are done with this chunk. If you pass // an error, then that'll put the hurt on the whole operation. If you // never call cb(), then you'll never get another chunk. Transform.prototype._transform = function(chunk, encoding, cb) { throw new Error('not implemented'); }; Transform.prototype._write = function(chunk, encoding, cb) { var ts = this._transformState; ts.writecb = cb; ts.writechunk = chunk; ts.writeencoding = encoding; if (!ts.transforming) { var rs = this._readableState; if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); } }; // Doesn't matter what the args are here. // _transform does all the work. // That we got here means that the readable side wants more data. Transform.prototype._read = function(n) { var ts = this._transformState; if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { ts.transforming = true; this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else { // mark that we need a transform, so that any data that comes in // will get processed, now that we've asked for it. ts.needTransform = true; } }; function done(stream, er) { if (er) return stream.emit('error', er); // if there's nothing in the write buffer, then that means // that nothing more will ever be provided var ws = stream._writableState; var ts = stream._transformState; if (ws.length) throw new Error('calling transform done when ws.length != 0'); if (ts.transforming) throw new Error('calling transform done when still transforming'); return stream.push(null); } },{"./_stream_duplex":53,"core-util-is":58,"inherits":48}],57:[function(require,module,exports){ (function (process){ // 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. // A bit simpler than readable streams. // Implement an async ._write(chunk, cb), and it'll handle all // the drain event emission and buffering. module.exports = Writable; /**/ var Buffer = require('buffer').Buffer; /**/ Writable.WritableState = WritableState; /**/ var util = require('core-util-is'); util.inherits = require('inherits'); /**/ var Stream = require('stream'); util.inherits(Writable, Stream); function WriteReq(chunk, encoding, cb) { this.chunk = chunk; this.encoding = encoding; this.callback = cb; } function WritableState(options, stream) { var Duplex = require('./_stream_duplex'); options = options || {}; // the point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if // the entire buffer is not flushed immediately on write() var hwm = options.highWaterMark; var defaultHwm = options.objectMode ? 16 : 16 * 1024; this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; // object stream flag to indicate whether or not this stream // contains buffers or objects. this.objectMode = !!options.objectMode; if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // cast to ints. this.highWaterMark = ~~this.highWaterMark; this.needDrain = false; // at the start of calling end() this.ending = false; // when end() has been called, and returned this.ended = false; // when 'finish' is emitted this.finished = false; // should we decode strings into buffers before passing to _write? // this is here so that some node-core streams can optimize string // handling at a lower level. var noDecode = options.decodeStrings === false; this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement // of how much we're waiting to get pushed to some underlying // socket or file. this.length = 0; // a flag to see when we're in the middle of a write. this.writing = false; // when true all writes will be buffered until .uncork() call this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately, // or on a later tick. We set this to true at first, because any // actions that shouldn't happen until "later" should generally also // not happen before the first write call. this.sync = true; // a flag to know if we're processing previously buffered items, which // may call the _write() callback in the same tick, so that we don't // end up in an overlapped onwrite situation. this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb) this.onwrite = function(er) { onwrite(stream, er); }; // the callback that the user supplies to write(chunk,encoding,cb) this.writecb = null; // the amount that is being written when _write is called. this.writelen = 0; this.buffer = []; // number of pending user-supplied write callbacks // this must be 0 before 'finish' can be emitted this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs // This is relevant for synchronous Transform streams this.prefinished = false; // True if the error was already emitted and should not be thrown again this.errorEmitted = false; } function Writable(options) { var Duplex = require('./_stream_duplex'); // Writable ctor is applied to Duplexes, though they're not // instanceof Writable, they're instanceof Readable. if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options); this._writableState = new WritableState(options, this); // legacy. this.writable = true; Stream.call(this); } // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function() { this.emit('error', new Error('Cannot pipe. Not readable.')); }; function writeAfterEnd(stream, state, cb) { var er = new Error('write after end'); // TODO: defer error events consistently everywhere, not just the cb stream.emit('error', er); process.nextTick(function() { cb(er); }); } // If we get something that is not a buffer, string, null, or undefined, // and we're not in objectMode, then that's an error. // Otherwise stream chunks are all considered to be of length=1, and the // watermarks determine how many objects to keep in the buffer, rather than // how many bytes or characters. function validChunk(stream, state, chunk, cb) { var valid = true; if (!util.isBuffer(chunk) && !util.isString(chunk) && !util.isNullOrUndefined(chunk) && !state.objectMode) { var er = new TypeError('Invalid non-string/buffer chunk'); stream.emit('error', er); process.nextTick(function() { cb(er); }); valid = false; } return valid; } Writable.prototype.write = function(chunk, encoding, cb) { var state = this._writableState; var ret = false; if (util.isFunction(encoding)) { cb = encoding; encoding = null; } if (util.isBuffer(chunk)) encoding = 'buffer'; else if (!encoding) encoding = state.defaultEncoding; if (!util.isFunction(cb)) cb = function() {}; if (state.ended) writeAfterEnd(this, state, cb); else if (validChunk(this, state, chunk, cb)) { state.pendingcb++; ret = writeOrBuffer(this, state, chunk, encoding, cb); } return ret; }; Writable.prototype.cork = function() { var state = this._writableState; state.corked++; }; Writable.prototype.uncork = function() { var state = this._writableState; if (state.corked) { state.corked--; if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.buffer.length) clearBuffer(this, state); } }; function decodeChunk(state, chunk, encoding) { if (!state.objectMode && state.decodeStrings !== false && util.isString(chunk)) { chunk = new Buffer(chunk, encoding); } return chunk; } // if we're already writing something, then just put this // in the queue, and wait our turn. Otherwise, call _write // If we return false, then we need a drain event, so set that flag. function writeOrBuffer(stream, state, chunk, encoding, cb) { chunk = decodeChunk(state, chunk, encoding); if (util.isBuffer(chunk)) encoding = 'buffer'; var len = state.objectMode ? 1 : chunk.length; state.length += len; var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false. if (!ret) state.needDrain = true; if (state.writing || state.corked) state.buffer.push(new WriteReq(chunk, encoding, cb)); else doWrite(stream, state, false, len, chunk, encoding, cb); return ret; } function doWrite(stream, state, writev, len, chunk, encoding, cb) { state.writelen = len; state.writecb = cb; state.writing = true; state.sync = true; if (writev) stream._writev(chunk, state.onwrite); else stream._write(chunk, encoding, state.onwrite); state.sync = false; } function onwriteError(stream, state, sync, er, cb) { if (sync) process.nextTick(function() { state.pendingcb--; cb(er); }); else { state.pendingcb--; cb(er); } stream._writableState.errorEmitted = true; stream.emit('error', er); } function onwriteStateUpdate(state) { state.writing = false; state.writecb = null; state.length -= state.writelen; state.writelen = 0; } function onwrite(stream, er) { var state = stream._writableState; var sync = state.sync; var cb = state.writecb; onwriteStateUpdate(state); if (er) onwriteError(stream, state, sync, er, cb); else { // Check if we're actually ready to finish, but don't emit yet var finished = needFinish(stream, state); if (!finished && !state.corked && !state.bufferProcessing && state.buffer.length) { clearBuffer(stream, state); } if (sync) { process.nextTick(function() { afterWrite(stream, state, finished, cb); }); } else { afterWrite(stream, state, finished, cb); } } } function afterWrite(stream, state, finished, cb) { if (!finished) onwriteDrain(stream, state); state.pendingcb--; cb(); finishMaybe(stream, state); } // Must force callback to be called on nextTick, so that we don't // emit 'drain' before the write() consumer gets the 'false' return // value, and has a chance to attach a 'drain' listener. function onwriteDrain(stream, state) { if (state.length === 0 && state.needDrain) { state.needDrain = false; stream.emit('drain'); } } // if there's something in the buffer waiting, then process it function clearBuffer(stream, state) { state.bufferProcessing = true; if (stream._writev && state.buffer.length > 1) { // Fast case, write everything using _writev() var cbs = []; for (var c = 0; c < state.buffer.length; c++) cbs.push(state.buffer[c].callback); // count the one we are adding, as well. // TODO(isaacs) clean this up state.pendingcb++; doWrite(stream, state, true, state.length, state.buffer, '', function(err) { for (var i = 0; i < cbs.length; i++) { state.pendingcb--; cbs[i](err); } }); // Clear buffer state.buffer = []; } else { // Slow case, write chunks one-by-one for (var c = 0; c < state.buffer.length; c++) { var entry = state.buffer[c]; var chunk = entry.chunk; var encoding = entry.encoding; var cb = entry.callback; var len = state.objectMode ? 1 : chunk.length; doWrite(stream, state, false, len, chunk, encoding, cb); // if we didn't call the onwrite immediately, then // it means that we need to wait until it does. // also, that means that the chunk and cb are currently // being processed, so move the buffer counter past them. if (state.writing) { c++; break; } } if (c < state.buffer.length) state.buffer = state.buffer.slice(c); else state.buffer.length = 0; } state.bufferProcessing = false; } Writable.prototype._write = function(chunk, encoding, cb) { cb(new Error('not implemented')); }; Writable.prototype._writev = null; Writable.prototype.end = function(chunk, encoding, cb) { var state = this._writableState; if (util.isFunction(chunk)) { cb = chunk; chunk = null; encoding = null; } else if (util.isFunction(encoding)) { cb = encoding; encoding = null; } if (!util.isNullOrUndefined(chunk)) this.write(chunk, encoding); // .end() fully uncorks if (state.corked) { state.corked = 1; this.uncork(); } // ignore unnecessary end() calls. if (!state.ending && !state.finished) endWritable(this, state, cb); }; function needFinish(stream, state) { return (state.ending && state.length === 0 && !state.finished && !state.writing); } function prefinish(stream, state) { if (!state.prefinished) { state.prefinished = true; stream.emit('prefinish'); } } function finishMaybe(stream, state) { var need = needFinish(stream, state); if (need) { if (state.pendingcb === 0) { prefinish(stream, state); state.finished = true; stream.emit('finish'); } else prefinish(stream, state); } return need; } function endWritable(stream, state, cb) { state.ending = true; finishMaybe(stream, state); if (cb) { if (state.finished) process.nextTick(cb); else stream.once('finish', cb); } state.ended = true; } }).call(this,require('_process')) },{"./_stream_duplex":53,"_process":51,"buffer":43,"core-util-is":58,"inherits":48,"stream":63}],58:[function(require,module,exports){ (function (Buffer){ // 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. // 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; function isBuffer(arg) { return Buffer.isBuffer(arg); } exports.isBuffer = isBuffer; function objectToString(o) { return Object.prototype.toString.call(o); } }).call(this,require("buffer").Buffer) },{"buffer":43}],59:[function(require,module,exports){ module.exports = require("./lib/_stream_passthrough.js") },{"./lib/_stream_passthrough.js":54}],60:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); exports.Stream = require('stream'); exports.Readable = exports; exports.Writable = require('./lib/_stream_writable.js'); exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); },{"./lib/_stream_duplex.js":53,"./lib/_stream_passthrough.js":54,"./lib/_stream_readable.js":55,"./lib/_stream_transform.js":56,"./lib/_stream_writable.js":57,"stream":63}],61:[function(require,module,exports){ module.exports = require("./lib/_stream_transform.js") },{"./lib/_stream_transform.js":56}],62:[function(require,module,exports){ module.exports = require("./lib/_stream_writable.js") },{"./lib/_stream_writable.js":57}],63:[function(require,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. module.exports = Stream; var EE = require('events').EventEmitter; var inherits = require('inherits'); inherits(Stream, EE); Stream.Readable = require('readable-stream/readable.js'); Stream.Writable = require('readable-stream/writable.js'); Stream.Duplex = require('readable-stream/duplex.js'); Stream.Transform = require('readable-stream/transform.js'); Stream.PassThrough = require('readable-stream/passthrough.js'); // Backwards-compat with node 0.4.x Stream.Stream = Stream; // old-style streams. Note that the pipe method (the only relevant // part of this class) is overridden in the Readable class. function Stream() { EE.call(this); } Stream.prototype.pipe = function(dest, options) { var source = this; function ondata(chunk) { if (dest.writable) { if (false === dest.write(chunk) && source.pause) { source.pause(); } } } source.on('data', ondata); function ondrain() { if (source.readable && source.resume) { source.resume(); } } dest.on('drain', ondrain); // If the 'end' option is not supplied, dest.end() will be called when // source gets the 'end' or 'close' events. Only dest.end() once. if (!dest._isStdio && (!options || options.end !== false)) { source.on('end', onend); source.on('close', onclose); } var didOnEnd = false; function onend() { if (didOnEnd) return; didOnEnd = true; dest.end(); } function onclose() { if (didOnEnd) return; didOnEnd = true; if (typeof dest.destroy === 'function') dest.destroy(); } // don't leave dangling pipes when there are errors. function onerror(er) { cleanup(); if (EE.listenerCount(this, 'error') === 0) { throw er; // Unhandled stream error in pipe. } } source.on('error', onerror); dest.on('error', onerror); // remove all the event listeners that were added. function cleanup() { source.removeListener('data', ondata); dest.removeListener('drain', ondrain); source.removeListener('end', onend); source.removeListener('close', onclose); source.removeListener('error', onerror); dest.removeListener('error', onerror); source.removeListener('end', cleanup); source.removeListener('close', cleanup); dest.removeListener('close', cleanup); } source.on('end', cleanup); source.on('close', cleanup); dest.on('close', cleanup); dest.emit('pipe', source); // Allow for unix-like usage: A.pipe(B).pipe(C) return dest; }; },{"events":47,"inherits":48,"readable-stream/duplex.js":52,"readable-stream/passthrough.js":59,"readable-stream/readable.js":60,"readable-stream/transform.js":61,"readable-stream/writable.js":62}],64:[function(require,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. var Buffer = require('buffer').Buffer; var isBufferEncoding = Buffer.isEncoding || function(encoding) { switch (encoding && encoding.toLowerCase()) { case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; default: return false; } } function assertEncoding(encoding) { if (encoding && !isBufferEncoding(encoding)) { throw new Error('Unknown encoding: ' + encoding); } } // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte // characters. CESU-8 is handled as part of the UTF-8 encoding. // // @TODO Handling all encodings inside a single object makes it very difficult // to reason about this code, so it should be split up in the future. // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code // points as used by CESU-8. var StringDecoder = exports.StringDecoder = function(encoding) { this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); assertEncoding(encoding); switch (this.encoding) { case 'utf8': // CESU-8 represents each of Surrogate Pair by 3-bytes this.surrogateSize = 3; break; case 'ucs2': case 'utf16le': // UTF-16 represents each of Surrogate Pair by 2-bytes this.surrogateSize = 2; this.detectIncompleteChar = utf16DetectIncompleteChar; break; case 'base64': // Base-64 stores 3 bytes in 4 chars, and pads the remainder. this.surrogateSize = 3; this.detectIncompleteChar = base64DetectIncompleteChar; break; default: this.write = passThroughWrite; return; } // Enough space to store all bytes of a single character. UTF-8 needs 4 // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). this.charBuffer = new Buffer(6); // Number of bytes received for the current incomplete multi-byte character. this.charReceived = 0; // Number of bytes expected for the current incomplete multi-byte character. this.charLength = 0; }; // write decodes the given buffer and returns it as JS string that is // guaranteed to not contain any partial multi-byte characters. Any partial // character found at the end of the buffer is buffered up, and will be // returned when calling write again with the remaining bytes. // // Note: Converting a Buffer containing an orphan surrogate to a String // currently works, but converting a String to a Buffer (via `new Buffer`, or // Buffer#write) will replace incomplete surrogates with the unicode // replacement character. See https://codereview.chromium.org/121173009/ . StringDecoder.prototype.write = function(buffer) { var charStr = ''; // if our last write ended with an incomplete multibyte character while (this.charLength) { // determine how many remaining bytes this buffer has to offer for this char var available = (buffer.length >= this.charLength - this.charReceived) ? this.charLength - this.charReceived : buffer.length; // add the new bytes to the char buffer buffer.copy(this.charBuffer, this.charReceived, 0, available); this.charReceived += available; if (this.charReceived < this.charLength) { // still not enough chars in this buffer? wait for more ... return ''; } // remove bytes belonging to the current character from the buffer buffer = buffer.slice(available, buffer.length); // get the character that was split charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character var charCode = charStr.charCodeAt(charStr.length - 1); if (charCode >= 0xD800 && charCode <= 0xDBFF) { this.charLength += this.surrogateSize; charStr = ''; continue; } this.charReceived = this.charLength = 0; // if there are no more bytes in this buffer, just emit our char if (buffer.length === 0) { return charStr; } break; } // determine and set charLength / charReceived this.detectIncompleteChar(buffer); var end = buffer.length; if (this.charLength) { // buffer the incomplete character bytes we got buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); end -= this.charReceived; } charStr += buffer.toString(this.encoding, 0, end); var end = charStr.length - 1; var charCode = charStr.charCodeAt(end); // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character if (charCode >= 0xD800 && charCode <= 0xDBFF) { var size = this.surrogateSize; this.charLength += size; this.charReceived += size; this.charBuffer.copy(this.charBuffer, size, 0, size); buffer.copy(this.charBuffer, 0, 0, size); return charStr.substring(0, end); } // or just emit the charStr return charStr; }; // detectIncompleteChar determines if there is an incomplete UTF-8 character at // the end of the given buffer. If so, it sets this.charLength to the byte // length that character, and sets this.charReceived to the number of bytes // that are available for this character. StringDecoder.prototype.detectIncompleteChar = function(buffer) { // determine how many bytes we have to check at the end of this buffer var i = (buffer.length >= 3) ? 3 : buffer.length; // Figure out if one of the last i bytes of our buffer announces an // incomplete char. for (; i > 0; i--) { var c = buffer[buffer.length - i]; // See http://en.wikipedia.org/wiki/UTF-8#Description // 110XXXXX if (i == 1 && c >> 5 == 0x06) { this.charLength = 2; break; } // 1110XXXX if (i <= 2 && c >> 4 == 0x0E) { this.charLength = 3; break; } // 11110XXX if (i <= 3 && c >> 3 == 0x1E) { this.charLength = 4; break; } } this.charReceived = i; }; StringDecoder.prototype.end = function(buffer) { var res = ''; if (buffer && buffer.length) res = this.write(buffer); if (this.charReceived) { var cr = this.charReceived; var buf = this.charBuffer; var enc = this.encoding; res += buf.slice(0, cr).toString(enc); } return res; }; function passThroughWrite(buffer) { return buffer.toString(this.encoding); } function utf16DetectIncompleteChar(buffer) { this.charReceived = buffer.length % 2; this.charLength = this.charReceived ? 2 : 0; } function base64DetectIncompleteChar(buffer) { this.charReceived = buffer.length % 3; this.charLength = this.charReceived ? 3 : 0; } },{"buffer":43}],65:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } },{}],66:[function(require,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 = require('./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 = require('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,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./support/isBuffer":65,"_process":51,"inherits":48}],67:[function(require,module,exports){ /* See LICENSE file for terms of use */ /* * Text diff implementation. * * This library supports the following APIS: * JsDiff.diffChars: Character by character diff * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace * JsDiff.diffLines: Line based diff * * JsDiff.diffCss: Diff targeted at CSS content * * These methods are based on the implementation proposed in * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 */ (function(global, undefined) { var objectPrototypeToString = Object.prototype.toString; /*istanbul ignore next*/ function map(arr, mapper, that) { if (Array.prototype.map) { return Array.prototype.map.call(arr, mapper, that); } var other = new Array(arr.length); for (var i = 0, n = arr.length; i < n; i++) { other[i] = mapper.call(that, arr[i], i, arr); } return other; } function clonePath(path) { return { newPos: path.newPos, components: path.components.slice(0) }; } function removeEmpty(array) { var ret = []; for (var i = 0; i < array.length; i++) { if (array[i]) { ret.push(array[i]); } } return ret; } function escapeHTML(s) { var n = s; n = n.replace(/&/g, '&'); n = n.replace(//g, '>'); n = n.replace(/"/g, '"'); return n; } // This function handles the presence of circular references by bailing out when encountering an // object that is already on the "stack" of items being processed. function canonicalize(obj, stack, replacementStack) { stack = stack || []; replacementStack = replacementStack || []; var i; for (i = 0; i < stack.length; i += 1) { if (stack[i] === obj) { return replacementStack[i]; } } var canonicalizedObj; if ('[object Array]' === objectPrototypeToString.call(obj)) { stack.push(obj); canonicalizedObj = new Array(obj.length); replacementStack.push(canonicalizedObj); for (i = 0; i < obj.length; i += 1) { canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); } stack.pop(); replacementStack.pop(); } else if (typeof obj === 'object' && obj !== null) { stack.push(obj); canonicalizedObj = {}; replacementStack.push(canonicalizedObj); var sortedKeys = [], key; for (key in obj) { sortedKeys.push(key); } sortedKeys.sort(); for (i = 0; i < sortedKeys.length; i += 1) { key = sortedKeys[i]; canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); } stack.pop(); replacementStack.pop(); } else { canonicalizedObj = obj; } return canonicalizedObj; } function buildValues(components, newString, oldString, useLongestToken) { var componentPos = 0, componentLen = components.length, newPos = 0, oldPos = 0; for (; componentPos < componentLen; componentPos++) { var component = components[componentPos]; if (!component.removed) { if (!component.added && useLongestToken) { var value = newString.slice(newPos, newPos + component.count); value = map(value, function(value, i) { var oldValue = oldString[oldPos + i]; return oldValue.length > value.length ? oldValue : value; }); component.value = value.join(''); } else { component.value = newString.slice(newPos, newPos + component.count).join(''); } newPos += component.count; // Common case if (!component.added) { oldPos += component.count; } } else { component.value = oldString.slice(oldPos, oldPos + component.count).join(''); oldPos += component.count; // Reverse add and remove so removes are output first to match common convention // The diffing algorithm is tied to add then remove output and this is the simplest // route to get the desired output with minimal overhead. if (componentPos && components[componentPos - 1].added) { var tmp = components[componentPos - 1]; components[componentPos - 1] = components[componentPos]; components[componentPos] = tmp; } } } return components; } function Diff(ignoreWhitespace) { this.ignoreWhitespace = ignoreWhitespace; } Diff.prototype = { diff: function(oldString, newString, callback) { var self = this; function done(value) { if (callback) { setTimeout(function() { callback(undefined, value); }, 0); return true; } else { return value; } } // Handle the identity case (this is due to unrolling editLength == 0 if (newString === oldString) { return done([{ value: newString }]); } if (!newString) { return done([{ value: oldString, removed: true }]); } if (!oldString) { return done([{ value: newString, added: true }]); } newString = this.tokenize(newString); oldString = this.tokenize(oldString); var newLen = newString.length, oldLen = oldString.length; var editLength = 1; var maxEditLength = newLen + oldLen; var bestPath = [{ newPos: -1, components: [] }]; // Seed editLength = 0, i.e. the content starts with the same values var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { // Identity per the equality and tokenizer return done([{value: newString.join('')}]); } // Main worker method. checks all permutations of a given edit length for acceptance. function execEditLength() { for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { var basePath; var addPath = bestPath[diagonalPath - 1], removePath = bestPath[diagonalPath + 1], oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; if (addPath) { // No one else is going to attempt to use this value, clear it bestPath[diagonalPath - 1] = undefined; } var canAdd = addPath && addPath.newPos + 1 < newLen, canRemove = removePath && 0 <= oldPos && oldPos < oldLen; if (!canAdd && !canRemove) { // If this path is a terminal then prune bestPath[diagonalPath] = undefined; continue; } // Select the diagonal that we want to branch from. We select the prior // path whose position in the new string is the farthest from the origin // and does not pass the bounds of the diff graph if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { basePath = clonePath(removePath); self.pushComponent(basePath.components, undefined, true); } else { basePath = addPath; // No need to clone, we've pulled it from the list basePath.newPos++; self.pushComponent(basePath.components, true, undefined); } oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); // If we have hit the end of both strings, then we are done if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) { return done(buildValues(basePath.components, newString, oldString, self.useLongestToken)); } else { // Otherwise track this path as a potential candidate and continue. bestPath[diagonalPath] = basePath; } } editLength++; } // Performs the length of edit iteration. Is a bit fugly as this has to support the // sync and async mode which is never fun. Loops over execEditLength until a value // is produced. if (callback) { (function exec() { setTimeout(function() { // This should not happen, but we want to be safe. /*istanbul ignore next */ if (editLength > maxEditLength) { return callback(); } if (!execEditLength()) { exec(); } }, 0); }()); } else { while (editLength <= maxEditLength) { var ret = execEditLength(); if (ret) { return ret; } } } }, pushComponent: function(components, added, removed) { var last = components[components.length - 1]; if (last && last.added === added && last.removed === removed) { // We need to clone here as the component clone operation is just // as shallow array clone components[components.length - 1] = {count: last.count + 1, added: added, removed: removed }; } else { components.push({count: 1, added: added, removed: removed }); } }, extractCommon: function(basePath, newString, oldString, diagonalPath) { var newLen = newString.length, oldLen = oldString.length, newPos = basePath.newPos, oldPos = newPos - diagonalPath, commonCount = 0; while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { newPos++; oldPos++; commonCount++; } if (commonCount) { basePath.components.push({count: commonCount}); } basePath.newPos = newPos; return oldPos; }, equals: function(left, right) { var reWhitespace = /\S/; return left === right || (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)); }, tokenize: function(value) { return value.split(''); } }; var CharDiff = new Diff(); var WordDiff = new Diff(true); var WordWithSpaceDiff = new Diff(); WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { return removeEmpty(value.split(/(\s+|\b)/)); }; var CssDiff = new Diff(true); CssDiff.tokenize = function(value) { return removeEmpty(value.split(/([{}:;,]|\s+)/)); }; var LineDiff = new Diff(); var TrimmedLineDiff = new Diff(); TrimmedLineDiff.ignoreTrim = true; LineDiff.tokenize = TrimmedLineDiff.tokenize = function(value) { var retLines = [], lines = value.split(/^/m); for (var i = 0; i < lines.length; i++) { var line = lines[i], lastLine = lines[i - 1], lastLineLastChar = lastLine && lastLine[lastLine.length - 1]; // Merge lines that may contain windows new lines if (line === '\n' && lastLineLastChar === '\r') { retLines[retLines.length - 1] = retLines[retLines.length - 1].slice(0, -1) + '\r\n'; } else { if (this.ignoreTrim) { line = line.trim(); // add a newline unless this is the last line. if (i < lines.length - 1) { line += '\n'; } } retLines.push(line); } } return retLines; }; var PatchDiff = new Diff(); PatchDiff.tokenize = function(value) { var ret = [], linesAndNewlines = value.split(/(\n|\r\n)/); // Ignore the final empty token that occurs if the string ends with a new line if (!linesAndNewlines[linesAndNewlines.length - 1]) { linesAndNewlines.pop(); } // Merge the content and line separators into single tokens for (var i = 0; i < linesAndNewlines.length; i++) { var line = linesAndNewlines[i]; if (i % 2) { ret[ret.length - 1] += line; } else { ret.push(line); } } return ret; }; var SentenceDiff = new Diff(); SentenceDiff.tokenize = function(value) { return removeEmpty(value.split(/(\S.+?[.!?])(?=\s+|$)/)); }; var JsonDiff = new Diff(); // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: JsonDiff.useLongestToken = true; JsonDiff.tokenize = LineDiff.tokenize; JsonDiff.equals = function(left, right) { return LineDiff.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')); }; var JsDiff = { Diff: Diff, diffChars: function(oldStr, newStr, callback) { return CharDiff.diff(oldStr, newStr, callback); }, diffWords: function(oldStr, newStr, callback) { return WordDiff.diff(oldStr, newStr, callback); }, diffWordsWithSpace: function(oldStr, newStr, callback) { return WordWithSpaceDiff.diff(oldStr, newStr, callback); }, diffLines: function(oldStr, newStr, callback) { return LineDiff.diff(oldStr, newStr, callback); }, diffTrimmedLines: function(oldStr, newStr, callback) { return TrimmedLineDiff.diff(oldStr, newStr, callback); }, diffSentences: function(oldStr, newStr, callback) { return SentenceDiff.diff(oldStr, newStr, callback); }, diffCss: function(oldStr, newStr, callback) { return CssDiff.diff(oldStr, newStr, callback); }, diffJson: function(oldObj, newObj, callback) { return JsonDiff.diff( typeof oldObj === 'string' ? oldObj : JSON.stringify(canonicalize(oldObj), undefined, ' '), typeof newObj === 'string' ? newObj : JSON.stringify(canonicalize(newObj), undefined, ' '), callback ); }, createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) { var ret = []; if (oldFileName == newFileName) { ret.push('Index: ' + oldFileName); } ret.push('==================================================================='); ret.push('--- ' + oldFileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); ret.push('+++ ' + newFileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); var diff = PatchDiff.diff(oldStr, newStr); diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier // Formats a given set of lines for printing as context lines in a patch function contextLines(lines) { return map(lines, function(entry) { return ' ' + entry; }); } // Outputs the no newline at end of file warning if needed function eofNL(curRange, i, current) { var last = diff[diff.length - 2], isLast = i === diff.length - 2, isLastOfType = i === diff.length - 3 && current.added !== last.added; // Figure out if this is the last line for the given file and missing NL if (!(/\n$/.test(current.value)) && (isLast || isLastOfType)) { curRange.push('\\ No newline at end of file'); } } var oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1; for (var i = 0; i < diff.length; i++) { var current = diff[i], lines = current.lines || current.value.replace(/\n$/, '').split('\n'); current.lines = lines; if (current.added || current.removed) { // If we have previous context, start with that if (!oldRangeStart) { var prev = diff[i - 1]; oldRangeStart = oldLine; newRangeStart = newLine; if (prev) { curRange = contextLines(prev.lines.slice(-4)); oldRangeStart -= curRange.length; newRangeStart -= curRange.length; } } // Output our changes curRange.push.apply(curRange, map(lines, function(entry) { return (current.added ? '+' : '-') + entry; })); eofNL(curRange, i, current); // Track the updated file position if (current.added) { newLine += lines.length; } else { oldLine += lines.length; } } else { // Identical context lines. Track line changes if (oldRangeStart) { // Close out any changes that have been output (or join overlapping) if (lines.length <= 8 && i < diff.length - 2) { // Overlapping curRange.push.apply(curRange, contextLines(lines)); } else { // end the range and output var contextSize = Math.min(lines.length, 4); ret.push( '@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize) + ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize) + ' @@'); ret.push.apply(ret, curRange); ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); if (lines.length <= 4) { eofNL(ret, i, current); } oldRangeStart = 0; newRangeStart = 0; curRange = []; } } oldLine += lines.length; newLine += lines.length; } } return ret.join('\n') + '\n'; }, createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader); }, applyPatch: function(oldStr, uniDiff) { var diffstr = uniDiff.split('\n'), hunks = [], i = 0, remEOFNL = false, addEOFNL = false; // Skip to the first change hunk while (i < diffstr.length && !(/^@@/.test(diffstr[i]))) { i++; } // Parse the unified diff for (; i < diffstr.length; i++) { if (diffstr[i][0] === '@') { var chnukHeader = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); hunks.unshift({ start: chnukHeader[3], oldlength: +chnukHeader[2], removed: [], newlength: chnukHeader[4], added: [] }); } else if (diffstr[i][0] === '+') { hunks[0].added.push(diffstr[i].substr(1)); } else if (diffstr[i][0] === '-') { hunks[0].removed.push(diffstr[i].substr(1)); } else if (diffstr[i][0] === ' ') { hunks[0].added.push(diffstr[i].substr(1)); hunks[0].removed.push(diffstr[i].substr(1)); } else if (diffstr[i][0] === '\\') { if (diffstr[i - 1][0] === '+') { remEOFNL = true; } else if (diffstr[i - 1][0] === '-') { addEOFNL = true; } } } // Apply the diff to the input var lines = oldStr.split('\n'); for (i = hunks.length - 1; i >= 0; i--) { var hunk = hunks[i]; // Sanity check the input string. Bail if we don't match. for (var j = 0; j < hunk.oldlength; j++) { if (lines[hunk.start - 1 + j] !== hunk.removed[j]) { return false; } } Array.prototype.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added)); } // Handle EOFNL insertion/removal if (remEOFNL) { while (!lines[lines.length - 1]) { lines.pop(); } } else if (addEOFNL) { lines.push(''); } return lines.join('\n'); }, convertChangesToXML: function(changes) { var ret = []; for (var i = 0; i < changes.length; i++) { var change = changes[i]; if (change.added) { ret.push(''); } else if (change.removed) { ret.push(''); } ret.push(escapeHTML(change.value)); if (change.added) { ret.push(''); } else if (change.removed) { ret.push(''); } } return ret.join(''); }, // See: http://code.google.com/p/google-diff-match-patch/wiki/API convertChangesToDMP: function(changes) { var ret = [], change, operation; for (var i = 0; i < changes.length; i++) { change = changes[i]; if (change.added) { operation = 1; } else if (change.removed) { operation = -1; } else { operation = 0; } ret.push([operation, change.value]); } return ret; }, canonicalize: canonicalize }; /*istanbul ignore next */ /*global module */ if (typeof module !== 'undefined' && module.exports) { module.exports = JsDiff; } else if (typeof define === 'function' && define.amd) { /*global define */ define([], function() { return JsDiff; }); } else if (typeof global.JsDiff === 'undefined') { global.JsDiff = JsDiff; } }(this)); },{}],68:[function(require,module,exports){ 'use strict'; var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; module.exports = function (str) { if (typeof str !== 'string') { throw new TypeError('Expected a string'); } return str.replace(matchOperatorsRe, '\\$&'); }; },{}],69:[function(require,module,exports){ (function (process){ // Growl - Copyright TJ Holowaychuk (MIT Licensed) /** * Module dependencies. */ var exec = require('child_process').exec , fs = require('fs') , path = require('path') , exists = fs.existsSync || path.existsSync , os = require('os') , quote = JSON.stringify , cmd; function which(name) { var paths = process.env.PATH.split(':'); var loc; for (var i = 0, len = paths.length; i < len; ++i) { loc = path.join(paths[i], name); if (exists(loc)) return loc; } } switch(os.type()) { case 'Darwin': if (which('terminal-notifier')) { cmd = { type: "Darwin-NotificationCenter" , pkg: "terminal-notifier" , msg: '-message' , title: '-title' , subtitle: '-subtitle' , priority: { cmd: '-execute' , range: [] } }; } else { cmd = { type: "Darwin-Growl" , pkg: "growlnotify" , msg: '-m' , sticky: '--sticky' , priority: { cmd: '--priority' , range: [ -2 , -1 , 0 , 1 , 2 , "Very Low" , "Moderate" , "Normal" , "High" , "Emergency" ] } }; } break; case 'Linux': cmd = { type: "Linux" , pkg: "notify-send" , msg: '' , sticky: '-t 0' , icon: '-i' , priority: { cmd: '-u' , range: [ "low" , "normal" , "critical" ] } }; break; case 'Windows_NT': cmd = { type: "Windows" , pkg: "growlnotify" , msg: '' , sticky: '/s:true' , title: '/t:' , icon: '/i:' , priority: { cmd: '/p:' , range: [ -2 , -1 , 0 , 1 , 2 ] } }; break; } /** * Expose `growl`. */ exports = module.exports = growl; /** * Node-growl version. */ exports.version = '1.4.1' /** * Send growl notification _msg_ with _options_. * * Options: * * - title Notification title * - sticky Make the notification stick (defaults to false) * - priority Specify an int or named key (default is 0) * - name Application name (defaults to growlnotify) * - image * - path to an icon sets --iconpath * - path to an image sets --image * - capitalized word sets --appIcon * - filename uses extname as --icon * - otherwise treated as --icon * * Examples: * * growl('New email') * growl('5 new emails', { title: 'Thunderbird' }) * growl('Email sent', function(){ * // ... notification sent * }) * * @param {string} msg * @param {object} options * @param {function} fn * @api public */ function growl(msg, options, fn) { var image , args , options = options || {} , fn = fn || function(){}; // noop if (!cmd) return fn(new Error('growl not supported on this platform')); args = [cmd.pkg]; // image if (image = options.image) { switch(cmd.type) { case 'Darwin-Growl': var flag, ext = path.extname(image).substr(1) flag = flag || ext == 'icns' && 'iconpath' flag = flag || /^[A-Z]/.test(image) && 'appIcon' flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' flag = flag || ext && (image = ext) && 'icon' flag = flag || 'icon' args.push('--' + flag, quote(image)) break; case 'Linux': args.push(cmd.icon, quote(image)); // libnotify defaults to sticky, set a hint for transient notifications if (!options.sticky) args.push('--hint=int:transient:1'); break; case 'Windows': args.push(cmd.icon + quote(image)); break; } } // sticky if (options.sticky) args.push(cmd.sticky); // priority if (options.priority) { var priority = options.priority + ''; var checkindexOf = cmd.priority.range.indexOf(priority); if (~cmd.priority.range.indexOf(priority)) { args.push(cmd.priority, options.priority); } } // name if (options.name && cmd.type === "Darwin-Growl") { args.push('--name', options.name); } switch(cmd.type) { case 'Darwin-Growl': args.push(cmd.msg); args.push(quote(msg)); if (options.title) args.push(quote(options.title)); break; case 'Darwin-NotificationCenter': args.push(cmd.msg); args.push(quote(msg)); if (options.title) { args.push(cmd.title); args.push(quote(options.title)); } if (options.subtitle) { args.push(cmd.subtitle); args.push(quote(options.subtitle)); } break; case 'Darwin-Growl': args.push(cmd.msg); args.push(quote(msg)); if (options.title) args.push(quote(options.title)); break; case 'Linux': if (options.title) { args.push(quote(options.title)); args.push(cmd.msg); args.push(quote(msg)); } else { args.push(quote(msg)); } break; case 'Windows': args.push(quote(msg)); if (options.title) args.push(cmd.title + quote(options.title)); break; } // execute exec(args.join(' '), fn); }; }).call(this,require('_process')) },{"_process":51,"child_process":41,"fs":41,"os":50,"path":41}],70:[function(require,module,exports){ (function (process,global){ /** * Shim process.stdout. */ process.stdout = require('browser-stdout')(); var Mocha = require('../'); /** * Create a Mocha instance. * * @return {undefined} */ var mocha = new Mocha({ reporter: 'html' }); /** * Save timer references to avoid Sinon interfering (see GH-237). */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; var uncaughtExceptionHandlers = []; var originalOnerrorHandler = global.onerror; /** * Remove uncaughtException listener. * Revert to original onerror handler if previously defined. */ process.removeListener = function(e, fn){ if ('uncaughtException' == e) { if (originalOnerrorHandler) { global.onerror = originalOnerrorHandler; } else { global.onerror = function() {}; } var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } } }; /** * Implements uncaughtException listener. */ process.on = function(e, fn){ if ('uncaughtException' == e) { global.onerror = function(err, url, line){ fn(new Error(err + ' (' + url + ':' + line + ')')); return !mocha.allowUncaught; }; uncaughtExceptionHandlers.push(fn); } }; // The BDD UI is registered by default, but no UI will be functional in the // browser without an explicit call to the overridden `mocha.ui` (see below). // Ensure that this default UI does not expose its methods to the global scope. mocha.suite.removeAllListeners('pre-require'); var immediateQueue = [] , immediateTimeout; function timeslice() { var immediateStart = new Date().getTime(); while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { immediateQueue.shift()(); } if (immediateQueue.length) { immediateTimeout = setTimeout(timeslice, 0); } else { immediateTimeout = null; } } /** * High-performance override of Runner.immediately. */ Mocha.Runner.immediately = function(callback) { immediateQueue.push(callback); if (!immediateTimeout) { immediateTimeout = setTimeout(timeslice, 0); } }; /** * Function to allow assertion libraries to throw errors directly into mocha. * This is useful when running tests in a browser because window.onerror will * only receive the 'message' attribute of the Error. */ mocha.throwError = function(err) { Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { fn(err); }); throw err; }; /** * Override ui to ensure that the ui functions are initialized. * Normally this would happen in Mocha.prototype.loadFiles. */ mocha.ui = function(ui){ Mocha.prototype.ui.call(this, ui); this.suite.emit('pre-require', global, null, this); return this; }; /** * Setup mocha with the given setting options. */ mocha.setup = function(opts){ if ('string' == typeof opts) opts = { ui: opts }; for (var opt in opts) this[opt](opts[opt]); return this; }; /** * Run mocha, returning the Runner. */ mocha.run = function(fn){ var options = mocha.options; mocha.globals('location'); var query = Mocha.utils.parseQuery(global.location.search || ''); if (query.grep) mocha.grep(new RegExp(query.grep)); if (query.fgrep) mocha.grep(query.fgrep); if (query.invert) mocha.invert(); return Mocha.prototype.run.call(mocha, function(err){ // The DOM Document is not available in Web Workers. var document = global.document; if (document && document.getElementById('mocha') && options.noHighlighting !== true) { Mocha.utils.highlightTags('code'); } if (fn) fn(err); }); }; /** * Expose the process shim. * https://github.com/mochajs/mocha/pull/916 */ Mocha.process = process; /** * Expose mocha. */ window.Mocha = Mocha; window.mocha = mocha; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../":1,"_process":51,"browser-stdout":40}]},{},[70]); ================================================ FILE: test/get-clone-error.html ================================================ Document ================================================ FILE: test/old/qunit/qunit-1.15.0.css ================================================ /*! * QUnit 1.15.0 * http://qunitjs.com/ * * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-08-08T16:00Z */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699A4; background-color: #0D3349; font-size: 1.5em; line-height: 1em; font-weight: 400; border-radius: 5px 5px 0 0; } #qunit-header a { text-decoration: none; color: #C2CCD1; } #qunit-header a:hover, #qunit-header a:focus { color: #FFF; } #qunit-testrunner-toolbar label { display: inline-block; padding: 0 0.5em 0 0.1em; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 1em 0.5em 1em; color: #5E740B; background-color: #EEE; overflow: hidden; } #qunit-userAgent { padding: 0.5em 1em 0.5em 1em; background-color: #2B81AF; color: #FFF; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } #qunit-modulefilter-container { float: right; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 1em 0.4em 1em; border-bottom: 1px solid #FFF; list-style-position: inside; } #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { display: none; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li a { padding: 0.5em; color: #C2CCD1; text-decoration: none; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests li .runtime { float: right; font-size: smaller; } .qunit-assert-list { margin-top: 0.5em; padding: 0.5em; background-color: #FFF; border-radius: 5px; } .qunit-collapsed { display: none; } #qunit-tests table { border-collapse: collapse; margin-top: 0.2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 0.5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #E0F2BE; color: #374E0C; text-decoration: none; } #qunit-tests ins { background-color: #FFCACA; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: #000; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { padding: 5px; background-color: #FFF; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #3C510C; background-color: #FFF; border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #FFF; border-left: 10px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 5px 5px; } #qunit-tests .fail { color: #000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: #008000; } #qunit-banner.qunit-fail { background-color: #EE5757; } /** Result */ #qunit-testresult { padding: 0.5em 1em 0.5em 1em; color: #2B81AF; background-color: #D2E0E6; border-bottom: 1px solid #FFF; } #qunit-testresult .module-name { font-weight: 700; } /** Fixture */ #qunit-fixture { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } ================================================ FILE: test/old/qunit/qunit-1.15.0.js ================================================ /*! * QUnit 1.15.0 * http://qunitjs.com/ * * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-08-08T16:00Z */ (function( window ) { var QUnit, config, onErrorFnPrev, fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, // Keep a local reference to Date (GH-283) Date = window.Date, now = Date.now || function() { return new Date().getTime(); }, setTimeout = window.setTimeout, clearTimeout = window.clearTimeout, defined = { document: typeof window.document !== "undefined", setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch ( e ) { return false; } }()) }, /** * Provides a normalized error string, correcting an issue * with IE 7 (and prior) where Error.prototype.toString is * not properly implemented * * Based on http://es5.github.com/#x15.11.4.4 * * @param {String|Error} error * @return {String} error message */ errorString = function( error ) { var name, message, errorString = error.toString(); if ( errorString.substring( 0, 7 ) === "[object" ) { name = error.name ? error.name.toString() : "Error"; message = error.message ? error.message.toString() : ""; if ( name && message ) { return name + ": " + message; } else if ( name ) { return name; } else if ( message ) { return message; } else { return "Error"; } } else { return errorString; } }, /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ objectValues = function( obj ) { var key, val, vals = QUnit.is( "array", obj ) ? [] : {}; for ( key in obj ) { if ( hasOwn.call( obj, key ) ) { val = obj[ key ]; vals[ key ] = val === Object( val ) ? objectValues( val ) : val; } } return vals; }; // Root QUnit object. // `QUnit` initialized at top of scope QUnit = { // call on start of module test to prepend name to all tests module: function( name, testEnvironment ) { config.currentModule = name; config.currentModuleTestEnvironment = testEnvironment; config.modules[ name ] = true; }, asyncTest: function( testName, expected, callback ) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test( testName, expected, callback, true ); }, test: function( testName, expected, callback, async ) { var test; if ( arguments.length === 2 ) { callback = expected; expected = null; } test = new Test({ testName: testName, expected: expected, async: async, callback: callback, module: config.currentModule, moduleTestEnvironment: config.currentModuleTestEnvironment, stack: sourceFromStacktrace( 2 ) }); if ( !validTest( test ) ) { return; } test.queue(); }, start: function( count ) { var message; // QUnit hasn't been initialized yet. // Note: RequireJS (et al) may delay onLoad if ( config.semaphore === undefined ) { QUnit.begin(function() { // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first setTimeout(function() { QUnit.start( count ); }); }); return; } config.semaphore -= count || 1; // don't start until equal number of stop-calls if ( config.semaphore > 0 ) { return; } // Set the starting time when the first test is run QUnit.config.started = QUnit.config.started || now(); // ignore if start is called more often then stop if ( config.semaphore < 0 ) { config.semaphore = 0; message = "Called start() while already started (QUnit.config.semaphore was 0 already)"; if ( config.current ) { QUnit.pushFailure( message, sourceFromStacktrace( 2 ) ); } else { throw new Error( message ); } return; } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { setTimeout(function() { if ( config.semaphore > 0 ) { return; } if ( config.timeout ) { clearTimeout( config.timeout ); } config.blocking = false; process( true ); }, 13 ); } else { config.blocking = false; process( true ); } }, stop: function( count ) { config.semaphore += count || 1; config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); config.timeout = setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); }, config.testTimeout ); } } }; // We use the prototype to distinguish between properties that should // be exposed as globals (and in exports) and those that shouldn't (function() { function F() {} F.prototype = QUnit; QUnit = new F(); // Make F QUnit's constructor so that we can add to the prototype later QUnit.constructor = F; }()); /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // when enabled, show only failing tests // gets persisted through sessionStorage and can be changed in UI via checkbox hidepassed: false, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, // by default, scroll to top of the page when suite is done scrolltop: true, // when enabled, all tests must call expect() requireExpects: false, // add checkboxes that are persisted in the query-string // when enabled, the id is set to `true` as a `QUnit.config` property urlConfig: [ { id: "noglobals", label: "Check for Globals", tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." }, { id: "notrycatch", label: "No try-catch", tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." } ], // Set of all modules. modules: {}, callbacks: {} }; // Initialize more QUnit.config and QUnit.urlParams (function() { var i, current, location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}; if ( params[ 0 ] ) { for ( i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; if ( urlParams[ current[ 0 ] ] ) { urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); } else { urlParams[ current[ 0 ] ] = current[ 1 ]; } } } QUnit.urlParams = urlParams; // String search anywhere in moduleName+testName config.filter = urlParams.filter; // Exact match of the module name config.module = urlParams.module; config.testNumber = []; if ( urlParams.testNumber ) { // Ensure that urlParams.testNumber is an array urlParams.testNumber = [].concat( urlParams.testNumber ); for ( i = 0; i < urlParams.testNumber.length; i++ ) { current = urlParams.testNumber[ i ]; config.testNumber.push( parseInt( current, 10 ) ); } } // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; }()); extend( QUnit, { config: config, // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) === type; }, objectType: function( obj ) { if ( typeof obj === "undefined" ) { return "undefined"; } // Consider: typeof null === object if ( obj === null ) { return "null"; } var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), type = match && match[ 1 ] || ""; switch ( type ) { case "Number": if ( isNaN( obj ) ) { return "nan"; } return "number"; case "String": case "Boolean": case "Array": case "Date": case "RegExp": case "Function": return type.toLowerCase(); } if ( typeof obj === "object" ) { return "object"; } return undefined; }, url: function( params ) { params = extend( extend( {}, QUnit.urlParams ), params ); var key, querystring = "?"; for ( key in params ) { if ( hasOwn.call( params, key ) ) { querystring += encodeURIComponent( key ) + "=" + encodeURIComponent( params[ key ] ) + "&"; } } return window.location.protocol + "//" + window.location.host + window.location.pathname + querystring.slice( 0, -1 ); }, extend: extend }); /** * @deprecated: Created for backwards compatibility with test runner that set the hook function * into QUnit.{hook}, instead of invoking it and passing the hook function. * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. * Doing this allows us to tell if the following methods have been overwritten on the actual * QUnit object. */ extend( QUnit.constructor.prototype, { // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes begin: registerLoggingCallback( "begin" ), // done: { failed, passed, total, runtime } done: registerLoggingCallback( "done" ), // log: { result, actual, expected, message } log: registerLoggingCallback( "log" ), // testStart: { name } testStart: registerLoggingCallback( "testStart" ), // testDone: { name, failed, passed, total, runtime } testDone: registerLoggingCallback( "testDone" ), // moduleStart: { name } moduleStart: registerLoggingCallback( "moduleStart" ), // moduleDone: { name, failed, passed, total } moduleDone: registerLoggingCallback( "moduleDone" ) }); QUnit.load = function() { runLoggingCallbacks( "begin", { totalTests: Test.count }); // Initialize the configuration options extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: 0, updateRate: 1000, autostart: true, filter: "", semaphore: 1 }, true ); config.blocking = false; if ( config.autostart ) { QUnit.start(); } }; // `onErrorFnPrev` initialized at top of scope // Preserve other handlers onErrorFnPrev = window.onerror; // Cover uncaught exceptions // Returning true will suppress the default browser handler, // returning false will let it run. window.onerror = function( error, filePath, linerNr ) { var ret = false; if ( onErrorFnPrev ) { ret = onErrorFnPrev( error, filePath, linerNr ); } // Treat return value as window.onerror itself does, // Only do our handling if not suppressed. if ( ret !== true ) { if ( QUnit.config.current ) { if ( QUnit.config.current.ignoreGlobalErrors ) { return true; } QUnit.pushFailure( error, filePath + ":" + linerNr ); } else { QUnit.test( "global failure", extend(function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); }, { validTest: validTest } ) ); } return false; } return ret; }; function done() { config.autorun = true; // Log the last module results if ( config.previousModule ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all }); } delete config.previousModule; var runtime = now() - config.started, passed = config.stats.all - config.stats.bad; runLoggingCallbacks( "done", { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime }); } /** @return Boolean: true if this test should be ran */ function validTest( test ) { var include, filter = config.filter && config.filter.toLowerCase(), module = config.module && config.module.toLowerCase(), fullName = ( test.module + ": " + test.testName ).toLowerCase(); // Internally-generated tests are always valid if ( test.callback && test.callback.validTest === validTest ) { delete test.callback.validTest; return true; } if ( config.testNumber.length > 0 ) { if ( inArray( test.testNumber, config.testNumber ) < 0 ) { return false; } } if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { return false; } if ( !filter ) { return true; } include = filter.charAt( 0 ) !== "!"; if ( !include ) { filter = filter.slice( 1 ); } // If the filter matches, we need to honour include if ( fullName.indexOf( filter ) !== -1 ) { return include; } // Otherwise, do the opposite return !include; } // Doesn't support IE6 to IE9 // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset === undefined ? 4 : offset; var stack, include, i; if ( e.stacktrace ) { // Opera 12.x return e.stacktrace.split( "\n" )[ offset + 3 ]; } else if ( e.stack ) { // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node stack = e.stack.split( "\n" ); if ( /^error$/i.test( stack[ 0 ] ) ) { stack.shift(); } if ( fileName ) { include = []; for ( i = offset; i < stack.length; i++ ) { if ( stack[ i ].indexOf( fileName ) !== -1 ) { break; } include.push( stack[ i ] ); } if ( include.length ) { return include.join( "\n" ); } } return stack[ offset ]; } else if ( e.sourceURL ) { // Safari < 6 // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } // for actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } function sourceFromStacktrace( offset ) { try { throw new Error(); } catch ( e ) { return extractStacktrace( e, offset ); } } function synchronize( callback, last ) { config.queue.push( callback ); if ( config.autorun && !config.blocking ) { process( last ); } } function process( last ) { function next() { process( last ); } var start = now(); config.depth = config.depth ? config.depth + 1 : 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) { config.queue.shift()(); } else { setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function saveGlobal() { config.pollution = []; if ( config.noglobals ) { for ( var key in window ) { if ( hasOwn.call( window, key ) ) { // in Opera sometimes DOM element ids show up here, ignore them if ( /^qunit-test-output/.test( key ) ) { continue; } config.pollution.push( key ); } } } } function checkPollution() { var newGlobals, deletedGlobals, old = config.pollution; saveGlobal(); newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); } deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); } } // returns a new Array with the elements that are in a but not in b function diff( a, b ) { var i, j, result = a.slice(); for ( i = 0; i < result.length; i++ ) { for ( j = 0; j < b.length; j++ ) { if ( result[ i ] === b[ j ] ) { result.splice( i, 1 ); i--; break; } } } return result; } function extend( a, b, undefOnly ) { for ( var prop in b ) { if ( hasOwn.call( b, prop ) ) { // Avoid "Member not found" error in IE8 caused by messing with window.constructor if ( !( prop === "constructor" && a === window ) ) { if ( b[ prop ] === undefined ) { delete a[ prop ]; } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { a[ prop ] = b[ prop ]; } } } } return a; } function registerLoggingCallback( key ) { // Initialize key collection of logging callback if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) { config.callbacks[ key ] = []; } return function( callback ) { config.callbacks[ key ].push( callback ); }; } function runLoggingCallbacks( key, args ) { var i, l, callbacks; callbacks = config.callbacks[ key ]; for ( i = 0, l = callbacks.length; i < l; i++ ) { callbacks[ i ]( args ); } } // from jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; } function Test( settings ) { extend( this, settings ); this.assert = new Assert( this ); this.assertions = []; this.testNumber = ++Test.count; } Test.count = 0; Test.prototype = { setup: function() { if ( // Emit moduleStart when we're switching from one module to another this.module !== config.previousModule || // They could be equal (both undefined) but if the previousModule property doesn't // yet exist it means this is the first test in a suite that isn't wrapped in a // module, in which case we'll just emit a moduleStart event for 'undefined'. // Without this, reporters can get testStart before moduleStart which is a problem. !hasOwn.call( config, "previousModule" ) ) { if ( hasOwn.call( config, "previousModule" ) ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all }); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0 }; runLoggingCallbacks( "moduleStart", { name: this.module }); } config.current = this; this.testEnvironment = extend({ setup: function() {}, teardown: function() {} }, this.moduleTestEnvironment ); this.started = now(); runLoggingCallbacks( "testStart", { name: this.testName, module: this.module, testNumber: this.testNumber }); if ( !config.pollution ) { saveGlobal(); } if ( config.notrycatch ) { this.testEnvironment.setup.call( this.testEnvironment, this.assert ); return; } try { this.testEnvironment.setup.call( this.testEnvironment, this.assert ); } catch ( e ) { this.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); } }, run: function() { config.current = this; if ( this.async ) { QUnit.stop(); } this.callbackStarted = now(); if ( config.notrycatch ) { this.callback.call( this.testEnvironment, this.assert ); this.callbackRuntime = now() - this.callbackStarted; return; } try { this.callback.call( this.testEnvironment, this.assert ); this.callbackRuntime = now() - this.callbackStarted; } catch ( e ) { this.callbackRuntime = now() - this.callbackStarted; this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); // else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { QUnit.start(); } } }, teardown: function() { config.current = this; if ( config.notrycatch ) { if ( typeof this.callbackRuntime === "undefined" ) { this.callbackRuntime = now() - this.callbackStarted; } this.testEnvironment.teardown.call( this.testEnvironment, this.assert ); return; } else { try { this.testEnvironment.teardown.call( this.testEnvironment, this.assert ); } catch ( e ) { this.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); } } checkPollution(); }, finish: function() { config.current = this; if ( config.requireExpects && this.expected === null ) { this.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); } else if ( this.expected !== null && this.expected !== this.assertions.length ) { this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); } else if ( this.expected === null && !this.assertions.length ) { this.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); } var i, bad = 0; this.runtime = now() - this.started; config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[ i ].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } runLoggingCallbacks( "testDone", { name: this.testName, module: this.module, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, runtime: this.runtime, // HTML Reporter use assertions: this.assertions, testNumber: this.testNumber, // DEPRECATED: this property will be removed in 2.0.0, use runtime instead duration: this.runtime }); config.current = undefined; }, queue: function() { var bad, test = this; function run() { // each of these can by async synchronize(function() { test.setup(); }); synchronize(function() { test.run(); }); synchronize(function() { test.teardown(); }); synchronize(function() { test.finish(); }); } // `bad` initialized at top of scope // defer when previous test run passed, if storage is available bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); if ( bad ) { run(); } else { synchronize( run, true ); } }, push: function( result, actual, expected, message ) { var source, details = { module: this.module, name: this.testName, result: result, message: message, actual: actual, expected: expected, testNumber: this.testNumber }; if ( !result ) { source = sourceFromStacktrace(); if ( source ) { details.source = source; } } runLoggingCallbacks( "log", details ); this.assertions.push({ result: !!result, message: message }); }, pushFailure: function( message, source, actual ) { if ( !this instanceof Test ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) ); } var details = { module: this.module, name: this.testName, result: false, message: message || "error", actual: actual || null, testNumber: this.testNumber }; if ( source ) { details.source = source; } runLoggingCallbacks( "log", details ); this.assertions.push({ result: false, message: message }); } }; QUnit.pushFailure = function() { if ( !QUnit.config.current ) { throw new Error( "pushFailure() assertion outside test context, in " + sourceFromStacktrace( 2 ) ); } // Gets current test obj var currentTest = QUnit.config.current.assert.test; return currentTest.pushFailure.apply( currentTest, arguments ); }; function Assert( testContext ) { this.test = testContext; } // Assert helpers QUnit.assert = Assert.prototype = { // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. expect: function( asserts ) { if ( arguments.length === 1 ) { this.test.expected = asserts; } else { return this.test.expected; } }, // Exports test.push() to the user API push: function() { var assert = this; // Backwards compatibility fix. // Allows the direct use of global exported assertions and QUnit.assert.* // Although, it's use is not recommended as it can leak assertions // to other tests from async tests, because we only get a reference to the current test, // not exactly the test where assertion were intended to be called. if ( !QUnit.config.current ) { throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) ); } if ( !( assert instanceof Assert ) ) { assert = QUnit.config.current.assert; } return assert.test.push.apply( assert.test, arguments ); }, /** * Asserts rough true-ish result. * @name ok * @function * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); */ ok: function( result, message ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + QUnit.dump.parse( result ) ); if ( !!result ) { this.push( true, result, true, message ); } else { this.test.pushFailure( message, null, result ); } }, /** * Assert that the first two arguments are equal, with an optional message. * Prints out both actual and expected values. * @name equal * @function * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); */ equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected == actual, actual, expected, message ); }, /** * @name notEqual * @function */ notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected != actual, actual, expected, message ); }, /** * @name propEqual * @function */ propEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, /** * @name notPropEqual * @function */ notPropEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, /** * @name deepEqual * @function */ deepEqual: function( actual, expected, message ) { this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, /** * @name notDeepEqual * @function */ notDeepEqual: function( actual, expected, message ) { this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, /** * @name strictEqual * @function */ strictEqual: function( actual, expected, message ) { this.push( expected === actual, actual, expected, message ); }, /** * @name notStrictEqual * @function */ notStrictEqual: function( actual, expected, message ) { this.push( expected !== actual, actual, expected, message ); }, "throws": function( block, expected, message ) { var actual, expectedType, expectedOutput = expected, ok = false; // 'expected' is optional unless doing string comparison if ( message == null && typeof expected === "string" ) { message = expected; expected = null; } this.test.ignoreGlobalErrors = true; try { block.call( this.test.testEnvironment ); } catch (e) { actual = e; } this.test.ignoreGlobalErrors = false; if ( actual ) { expectedType = QUnit.objectType( expected ); // we don't want to validate thrown error if ( !expected ) { ok = true; expectedOutput = null; // expected is a regexp } else if ( expectedType === "regexp" ) { ok = expected.test( errorString( actual ) ); // expected is a string } else if ( expectedType === "string" ) { ok = expected === errorString( actual ); // expected is a constructor, maybe an Error constructor } else if ( expectedType === "function" && actual instanceof expected ) { ok = true; // expected is an Error object } else if ( expectedType === "object" ) { ok = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message; // expected is a validation function which returns true if validation passed } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { expectedOutput = null; ok = true; } this.push( ok, actual, expectedOutput, message ); } else { this.test.pushFailure( message, null, "No exception was thrown." ); } } }; // Test for equality any JavaScript type. // Author: Philippe Rath QUnit.equiv = (function() { // Call the o related callback with the given arguments. function bindCallbacks( o, callbacks, args ) { var prop = QUnit.objectType( o ); if ( prop ) { if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { return callbacks[ prop ].apply( callbacks, args ); } else { return callbacks[ prop ]; // or undefined } } } // the real equiv function var innerEquiv, // stack to decide between skip/abort functions callers = [], // stack to avoiding loops from circular referencing parents = [], parentsB = [], getProto = Object.getPrototypeOf || function( obj ) { /* jshint camelcase: false, proto: true */ return obj.__proto__; }, callbacks = (function() { // for string, boolean, number and null function useStrictEquality( b, a ) { /*jshint eqeqeq:false */ if ( b instanceof a.constructor || a instanceof b.constructor ) { // to catch short annotation VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); return a == b; } else { return a === b; } } return { "string": useStrictEquality, "boolean": useStrictEquality, "number": useStrictEquality, "null": useStrictEquality, "undefined": useStrictEquality, "nan": function( b ) { return isNaN( b ); }, "date": function( b, a ) { return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); }, "regexp": function( b, a ) { return QUnit.objectType( b ) === "regexp" && // the regex itself a.source === b.source && // and its modifiers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky; }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function": function() { var caller = callers[ callers.length - 1 ]; return caller !== Object && typeof caller !== "undefined"; }, "array": function( b, a ) { var i, j, len, loop, aCircular, bCircular; // b could be an object literal here if ( QUnit.objectType( b ) !== "array" ) { return false; } len = a.length; if ( len !== b.length ) { // safe and faster return false; } // track reference to avoid circular references parents.push( a ); parentsB.push( b ); for ( i = 0; i < len; i++ ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { parents.pop(); parentsB.pop(); return false; } } } if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { parents.pop(); parentsB.pop(); return false; } } parents.pop(); parentsB.pop(); return true; }, "object": function( b, a ) { /*jshint forin:false */ var i, j, loop, aCircular, bCircular, // Default to true eq = true, aProperties = [], bProperties = []; // comparing constructors is more strict than using // instanceof if ( a.constructor !== b.constructor ) { // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) || ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) { return false; } } // stack constructor before traversing properties callers.push( a.constructor ); // track reference to avoid circular references parents.push( a ); parentsB.push( b ); // be strict: don't ensure hasOwnProperty and go deep for ( i in a ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { eq = false; break; } } } aProperties.push( i ); if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { eq = false; break; } } parents.pop(); parentsB.pop(); callers.pop(); // unstack, we are done for ( i in b ) { bProperties.push( i ); // collect b's properties } // Ensures identical properties name return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); } }; }()); innerEquiv = function() { // can take multiple arguments var args = [].slice.apply( arguments ); if ( args.length < 2 ) { return true; // end transition } return ( (function( a, b ) { if ( a === b ) { return true; // catch the most you can } else if ( a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType( a ) !== QUnit.objectType( b ) ) { // don't lose time with error prone cases return false; } else { return bindCallbacks( a, callbacks, [ b, a ] ); } // apply transition with (1..n) arguments }( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); }; return innerEquiv; }()); // Based on jsDump by Ariel Flesler // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html QUnit.dump = (function() { function quote( str ) { return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; } function literal( o ) { return o + ""; } function join( pre, arr, post ) { var s = dump.separator(), base = dump.indent(), inner = dump.indent( 1 ); if ( arr.join ) { arr = arr.join( "," + s + inner ); } if ( !arr ) { return pre + post; } return [ pre, inner + arr, base + post ].join( s ); } function array( arr, stack ) { var i = arr.length, ret = new Array( i ); this.up(); while ( i-- ) { ret[ i ] = this.parse( arr[ i ], undefined, stack ); } this.down(); return join( "[", ret, "]" ); } var reName = /^function (\w+)/, dump = { // type is used mostly internally, you can fix a (custom)type in advance parse: function( obj, type, stack ) { stack = stack || []; var inStack, res, parser = this.parsers[ type || this.typeOf( obj ) ]; type = typeof parser; inStack = inArray( obj, stack ); if ( inStack !== -1 ) { return "recursion(" + ( inStack - stack.length ) + ")"; } if ( type === "function" ) { stack.push( obj ); res = parser.call( this, obj, stack ); stack.pop(); return res; } return ( type === "string" ) ? parser : this.parsers.error; }, typeOf: function( obj ) { var type; if ( obj === null ) { type = "null"; } else if ( typeof obj === "undefined" ) { type = "undefined"; } else if ( QUnit.is( "regexp", obj ) ) { type = "regexp"; } else if ( QUnit.is( "date", obj ) ) { type = "date"; } else if ( QUnit.is( "function", obj ) ) { type = "function"; } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { type = "window"; } else if ( obj.nodeType === 9 ) { type = "document"; } else if ( obj.nodeType ) { type = "node"; } else if ( // native arrays toString.call( obj ) === "[object Array]" || // NodeList objects ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && typeof obj[ 0 ] === "undefined" ) ) ) ) { type = "array"; } else if ( obj.constructor === Error.prototype.constructor ) { type = "error"; } else { type = typeof obj; } return type; }, separator: function() { return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; }, // extra can be a number, shortcut for increasing-calling-decreasing indent: function( extra ) { if ( !this.multiline ) { return ""; } var chr = this.indentChar; if ( this.HTML ) { chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); } return new Array( this.depth + ( extra || 0 ) ).join( chr ); }, up: function( a ) { this.depth += a || 1; }, down: function( a ) { this.depth -= a || 1; }, setParser: function( name, parser ) { this.parsers[ name ] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, // depth: 1, // This is the list of parsers, to modify them, use dump.setParser parsers: { window: "[Window]", document: "[Document]", error: function( error ) { return "Error(\"" + error.message + "\")"; }, unknown: "[Unknown]", "null": "null", "undefined": "undefined", "function": function( fn ) { var ret = "function", // functions never have name in IE name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; if ( name ) { ret += " " + name; } ret += "( "; ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); return join( ret, dump.parse( fn, "functionCode" ), "}" ); }, array: array, nodelist: array, "arguments": array, object: function( map, stack ) { /*jshint forin:false */ var ret = [], keys, key, val, i, nonEnumerableProperties; dump.up(); keys = []; for ( key in map ) { keys.push( key ); } // Some properties are not always enumerable on Error objects. nonEnumerableProperties = [ "message", "name" ]; for ( i in nonEnumerableProperties ) { key = nonEnumerableProperties[ i ]; if ( key in map && !( key in keys ) ) { keys.push( key ); } } keys.sort(); for ( i = 0; i < keys.length; i++ ) { key = keys[ i ]; val = map[ key ]; ret.push( dump.parse( key, "key" ) + ": " + dump.parse( val, undefined, stack ) ); } dump.down(); return join( "{", ret, "}" ); }, node: function( node ) { var len, i, val, open = dump.HTML ? "<" : "<", close = dump.HTML ? ">" : ">", tag = node.nodeName.toLowerCase(), ret = open + tag, attrs = node.attributes; if ( attrs ) { for ( i = 0, len = attrs.length; i < len; i++ ) { val = attrs[ i ].nodeValue; // IE6 includes all attributes in .attributes, even ones not explicitly set. // Those have values like undefined, null, 0, false, "" or "inherit". if ( val && val !== "inherit" ) { ret += " " + attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" ); } } } ret += close; // Show content of TextNode or CDATASection if ( node.nodeType === 3 || node.nodeType === 4 ) { ret += node.nodeValue; } return ret + open + "/" + tag + close; }, // function calls it internally, it's the arguments part of the function functionArgs: function( fn ) { var args, l = fn.length; if ( !l ) { return ""; } args = new Array( l ); while ( l-- ) { // 97 is 'a' args[ l ] = String.fromCharCode( 97 + l ); } return " " + args.join( ", " ) + " "; }, // object calls it internally, the key part of an item in a map key: quote, // function calls it internally, it's the content of the function functionCode: "[code]", // node calls it internally, it's an html attribute value attribute: quote, string: quote, date: quote, regexp: literal, number: literal, "boolean": literal }, // if true, entities are escaped ( <, >, \t, space and \n ) HTML: false, // indentation unit indentChar: " ", // if true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; }()); // back compat QUnit.jsDump = QUnit.dump; // For browser, export only select globals if ( typeof window !== "undefined" ) { // Deprecated // Extend assert methods to QUnit and Global scope through Backwards compatibility (function() { var i, assertions = Assert.prototype; function applyCurrent( current ) { return function() { var assert = new Assert( QUnit.config.current ); current.apply( assert, arguments ); }; } for ( i in assertions ) { QUnit[ i ] = applyCurrent( assertions[ i ] ); } })(); (function() { var i, l, keys = [ "test", "module", "expect", "asyncTest", "start", "stop", "ok", "equal", "notEqual", "propEqual", "notPropEqual", "deepEqual", "notDeepEqual", "strictEqual", "notStrictEqual", "throws" ]; for ( i = 0, l = keys.length; i < l; i++ ) { window[ keys[ i ] ] = QUnit[ keys[ i ] ]; } })(); window.QUnit = QUnit; } // For CommonJS environments, export everything if ( typeof module !== "undefined" && module.exports ) { module.exports = QUnit; } // Get a reference to the global object, like window in browsers }( (function() { return this; })() )); /*istanbul ignore next */ /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) * Modified by Chu Alan "sprite" * * Released under the MIT license. * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ * * Usage: QUnit.diff(expected, actual) * * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" */ QUnit.diff = (function() { var hasOwn = Object.prototype.hasOwnProperty; /*jshint eqeqeq:false, eqnull:true */ function diff( o, n ) { var i, ns = {}, os = {}; for ( i = 0; i < n.length; i++ ) { if ( !hasOwn.call( ns, n[ i ] ) ) { ns[ n[ i ] ] = { rows: [], o: null }; } ns[ n[ i ] ].rows.push( i ); } for ( i = 0; i < o.length; i++ ) { if ( !hasOwn.call( os, o[ i ] ) ) { os[ o[ i ] ] = { rows: [], n: null }; } os[ o[ i ] ].rows.push( i ); } for ( i in ns ) { if ( hasOwn.call( ns, i ) ) { if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) { n[ ns[ i ].rows[ 0 ] ] = { text: n[ ns[ i ].rows[ 0 ] ], row: os[ i ].rows[ 0 ] }; o[ os[ i ].rows[ 0 ] ] = { text: o[ os[ i ].rows[ 0 ] ], row: ns[ i ].rows[ 0 ] }; } } } for ( i = 0; i < n.length - 1; i++ ) { if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null && n[ i + 1 ] == o[ n[ i ].row + 1 ] ) { n[ i + 1 ] = { text: n[ i + 1 ], row: n[ i ].row + 1 }; o[ n[ i ].row + 1 ] = { text: o[ n[ i ].row + 1 ], row: i + 1 }; } } for ( i = n.length - 1; i > 0; i-- ) { if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null && n[ i - 1 ] == o[ n[ i ].row - 1 ] ) { n[ i - 1 ] = { text: n[ i - 1 ], row: n[ i ].row - 1 }; o[ n[ i ].row - 1 ] = { text: o[ n[ i ].row - 1 ], row: i - 1 }; } } return { o: o, n: n }; } return function( o, n ) { o = o.replace( /\s+$/, "" ); n = n.replace( /\s+$/, "" ); var i, pre, str = "", out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ), oSpace = o.match( /\s+/g ), nSpace = n.match( /\s+/g ); if ( oSpace == null ) { oSpace = [ " " ]; } else { oSpace.push( " " ); } if ( nSpace == null ) { nSpace = [ " " ]; } else { nSpace.push( " " ); } if ( out.n.length === 0 ) { for ( i = 0; i < out.o.length; i++ ) { str += "" + out.o[ i ] + oSpace[ i ] + ""; } } else { if ( out.n[ 0 ].text == null ) { for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) { str += "" + out.o[ n ] + oSpace[ n ] + ""; } } for ( i = 0; i < out.n.length; i++ ) { if ( out.n[ i ].text == null ) { str += "" + out.n[ i ] + nSpace[ i ] + ""; } else { // `pre` initialized at top of scope pre = ""; for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) { pre += "" + out.o[ n ] + oSpace[ n ] + ""; } str += " " + out.n[ i ].text + nSpace[ i ] + pre; } } } return str; }; }()); (function() { // Deprecated QUnit.init - Ref #530 // Re-initialize the configuration options QUnit.init = function() { var tests, banner, result, qunit, config = QUnit.config; config.stats = { all: 0, bad: 0 }; config.moduleStats = { all: 0, bad: 0 }; config.started = 0; config.updateRate = 1000; config.blocking = false; config.autostart = true; config.autorun = false; config.filter = ""; config.queue = []; config.semaphore = 1; // Return on non-browser environments // This is necessary to not break on node tests if ( typeof window === "undefined" ) { return; } qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = "

    " + escapeText( document.title ) + "

    " + "

    " + "
    " + "

    " + "
      "; } tests = id( "qunit-tests" ); banner = id( "qunit-banner" ); result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; } if ( banner ) { banner.className = ""; } if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = "Running...
       "; } }; // Resets the test setup. Useful for tests that modify the DOM. /* DEPRECATED: Use multiple tests instead of resetting inside a test. Use testStart or testDone for custom cleanup. This method will throw an error in 2.0, and will be removed in 2.1 */ QUnit.reset = function() { // Return on non-browser environments // This is necessary to not break on node tests if ( typeof window === "undefined" ) { return; } var fixture = id( "qunit-fixture" ); if ( fixture ) { fixture.innerHTML = config.fixture; } }; // Don't load the HTML Reporter on non-Browser environments if ( typeof window === "undefined" ) { return; } var config = QUnit.config, hasOwn = Object.prototype.hasOwnProperty, defined = { document: typeof window.document !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch ( e ) { return false; } }()) }; /** * Escape text for attribute or text content. */ function escapeText( s ) { if ( !s ) { return ""; } s = s + ""; // Both single quotes and double quotes (for attributes) return s.replace( /['"<>&]/g, function( s ) { switch ( s ) { case "'": return "'"; case "\"": return """; case "<": return "<"; case ">": return ">"; case "&": return "&"; } }); } /** * @param {HTMLElement} elem * @param {string} type * @param {Function} fn */ function addEvent( elem, type, fn ) { if ( elem.addEventListener ) { // Standards-based browsers elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { // support: IE <9 elem.attachEvent( "on" + type, fn ); } } /** * @param {Array|NodeList} elems * @param {string} type * @param {Function} fn */ function addEvents( elems, type, fn ) { var i = elems.length; while ( i-- ) { addEvent( elems[ i ], type, fn ); } } function hasClass( elem, name ) { return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; } function addClass( elem, name ) { if ( !hasClass( elem, name ) ) { elem.className += ( elem.className ? " " : "" ) + name; } } function toggleClass( elem, name ) { if ( hasClass( elem, name ) ) { removeClass( elem, name ); } else { addClass( elem, name ); } } function removeClass( elem, name ) { var set = " " + elem.className + " "; // Class name may appear multiple times while ( set.indexOf( " " + name + " " ) >= 0 ) { set = set.replace( " " + name + " ", " " ); } // trim for prettiness elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); } function id( name ) { return defined.document && document.getElementById && document.getElementById( name ); } function getUrlConfigHtml() { var i, j, val, escaped, escapedTooltip, selection = false, len = config.urlConfig.length, urlConfigHtml = ""; for ( i = 0; i < len; i++ ) { val = config.urlConfig[ i ]; if ( typeof val === "string" ) { val = { id: val, label: val }; } escaped = escapeText( val.id ); escapedTooltip = escapeText( val.tooltip ); config[ val.id ] = QUnit.urlParams[ val.id ]; if ( !val.value || typeof val.value === "string" ) { urlConfigHtml += ""; } else { urlConfigHtml += ""; } } return urlConfigHtml; } function toolbarUrlConfigContainer() { var urlConfigContainer = document.createElement( "span" ); urlConfigContainer.innerHTML = getUrlConfigHtml(); // For oldIE support: // * Add handlers to the individual elements instead of the container // * Use "click" instead of "change" for checkboxes // * Fallback from event.target to event.srcElement addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", function( event ) { var params = {}, target = event.target || event.srcElement; params[ target.name ] = target.checked ? target.defaultValue || true : undefined; window.location = QUnit.url( params ); }); addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", function( event ) { var params = {}, target = event.target || event.srcElement; params[ target.name ] = target.options[ target.selectedIndex ].value || undefined; window.location = QUnit.url( params ); }); return urlConfigContainer; } function getModuleNames() { var i, moduleNames = []; for ( i in config.modules ) { if ( config.modules.hasOwnProperty( i ) ) { moduleNames.push( i ); } } moduleNames.sort(function( a, b ) { return a.localeCompare( b ); }); return moduleNames; } function toolbarModuleFilterHtml() { var i, moduleFilterHtml = "", moduleNames = getModuleNames(); if ( moduleNames.length <= 1 ) { return false; } moduleFilterHtml += "" + ""; return moduleFilterHtml; } function toolbarModuleFilter() { var moduleFilter = document.createElement( "span" ), moduleFilterHtml = toolbarModuleFilterHtml(); if ( !moduleFilterHtml ) { return false; } moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); moduleFilter.innerHTML = moduleFilterHtml; addEvent( moduleFilter.lastChild, "change", function() { var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ], selectedModule = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ); window.location = QUnit.url({ module: ( selectedModule === "" ) ? undefined : selectedModule, // Remove any existing filters filter: undefined, testNumber: undefined }); }); return moduleFilter; } function toolbarFilter() { var testList = id( "qunit-tests" ), filter = document.createElement( "input" ); filter.type = "checkbox"; filter.id = "qunit-filter-pass"; addEvent( filter, "click", function() { if ( filter.checked ) { addClass( testList, "hidepass" ); if ( defined.sessionStorage ) { sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); } } else { removeClass( testList, "hidepass" ); if ( defined.sessionStorage ) { sessionStorage.removeItem( "qunit-filter-passed-tests" ); } } }); if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { filter.checked = true; addClass( testList, "hidepass" ); } return filter; } function toolbarLabel() { var label = document.createElement( "label" ); label.setAttribute( "for", "qunit-filter-pass" ); label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); label.innerHTML = "Hide passed tests"; return label; } function appendToolbar() { var moduleFilter, toolbar = id( "qunit-testrunner-toolbar" ); if ( toolbar ) { toolbar.appendChild( toolbarFilter() ); toolbar.appendChild( toolbarLabel() ); toolbar.appendChild( toolbarUrlConfigContainer() ); moduleFilter = toolbarModuleFilter(); if ( moduleFilter ) { toolbar.appendChild( moduleFilter ); } } } function appendBanner() { var banner = id( "qunit-banner" ); if ( banner ) { banner.className = ""; banner.innerHTML = "" + banner.innerHTML + " "; } } function appendTestResults() { var tests = id( "qunit-tests" ), result = id( "qunit-testresult" ); if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { tests.innerHTML = ""; result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = "Running...
       "; } } function storeFixture() { var fixture = id( "qunit-fixture" ); if ( fixture ) { config.fixture = fixture.innerHTML; } } function appendUserAgent() { var userAgent = id( "qunit-userAgent" ); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } } // HTML Reporter initialization and load QUnit.begin(function() { var qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = "

      " + escapeText( document.title ) + "

      " + "

      " + "
      " + "

      " + "
        "; } appendBanner(); appendTestResults(); appendUserAgent(); appendToolbar(); storeFixture(); }); QUnit.done(function( details ) { var i, key, banner = id( "qunit-banner" ), tests = id( "qunit-tests" ), html = [ "Tests completed in ", details.runtime, " milliseconds.
        ", "", details.passed, " assertions of ", details.total, " passed, ", details.failed, " failed." ].join( "" ); if ( banner ) { banner.className = details.failed ? "qunit-fail" : "qunit-pass"; } if ( tests ) { id( "qunit-testresult" ).innerHTML = html; } if ( config.altertitle && defined.document && document.title ) { // show ? for good, ? for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ ( details.failed ? "\u2716" : "\u2714" ), document.title.replace( /^[\u2714\u2716] /i, "" ) ].join( " " ); } // clear own sessionStorage items if all tests passed if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { for ( i = 0; i < sessionStorage.length; i++ ) { key = sessionStorage.key( i++ ); if ( key.indexOf( "qunit-test-" ) === 0 ) { sessionStorage.removeItem( key ); } } } // scroll back to top to show results if ( config.scrolltop && window.scrollTo ) { window.scrollTo( 0, 0 ); } }); function getNameHtml( name, module ) { var nameHtml = ""; if ( module ) { nameHtml = "" + escapeText( module ) + ": "; } nameHtml += "" + escapeText( name ) + ""; return nameHtml; } QUnit.testStart(function( details ) { var a, b, li, running, assertList, name = getNameHtml( details.name, details.module ), tests = id( "qunit-tests" ); if ( tests ) { b = document.createElement( "strong" ); b.innerHTML = name; a = document.createElement( "a" ); a.innerHTML = "Rerun"; a.href = QUnit.url({ testNumber: details.testNumber }); li = document.createElement( "li" ); li.appendChild( b ); li.appendChild( a ); li.className = "running"; li.id = "qunit-test-output" + details.testNumber; assertList = document.createElement( "ol" ); assertList.className = "qunit-assert-list"; li.appendChild( assertList ); tests.appendChild( li ); } running = id( "qunit-testresult" ); if ( running ) { running.innerHTML = "Running:
        " + name; } }); QUnit.log(function( details ) { var assertList, assertLi, message, expected, actual, testItem = id( "qunit-test-output" + details.testNumber ); if ( !testItem ) { return; } message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); message = "" + message + ""; // pushFailure doesn't provide details.expected // when it calls, it's implicit to also not show expected and diff stuff // Also, we need to check details.expected existence, as it can exist and be undefined if ( !details.result && hasOwn.call( details, "expected" ) ) { expected = escapeText( QUnit.dump.parse( details.expected ) ); actual = escapeText( QUnit.dump.parse( details.actual ) ); message += ""; if ( actual !== expected ) { message += "" + ""; } if ( details.source ) { message += ""; } message += "
        Expected:
        " +
        			expected +
        			"
        Result:
        " +
        				actual + "
        Diff:
        " +
        				QUnit.diff( expected, actual ) + "
        Source:
        " +
        				escapeText( details.source ) + "
        "; // this occours when pushFailure is set and we have an extracted stack trace } else if ( !details.result && details.source ) { message += "" + "" + "
        Source:
        " +
        			escapeText( details.source ) + "
        "; } assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; assertLi = document.createElement( "li" ); assertLi.className = details.result ? "pass" : "fail"; assertLi.innerHTML = message; assertList.appendChild( assertLi ); }); QUnit.testDone(function( details ) { var testTitle, time, testItem, assertList, good, bad, testCounts, tests = id( "qunit-tests" ); // QUnit.reset() is deprecated and will be replaced for a new // fixture reset function on QUnit 2.0/2.1. // It's still called here for backwards compatibility handling QUnit.reset(); if ( !tests ) { return; } testItem = id( "qunit-test-output" + details.testNumber ); assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; good = details.passed; bad = details.failed; // store result when possible if ( config.reorder && defined.sessionStorage ) { if ( bad ) { sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); } else { sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); } } if ( bad === 0 ) { addClass( assertList, "qunit-collapsed" ); } // testItem.firstChild is the test name testTitle = testItem.firstChild; testCounts = bad ? "" + bad + ", " + "" + good + ", " : ""; testTitle.innerHTML += " (" + testCounts + details.assertions.length + ")"; addEvent( testTitle, "click", function() { toggleClass( assertList, "qunit-collapsed" ); }); time = document.createElement( "span" ); time.className = "runtime"; time.innerHTML = details.runtime + " ms"; testItem.className = bad ? "fail" : "pass"; testItem.insertBefore( time, assertList ); }); if ( !defined.document || document.readyState === "complete" ) { config.autorun = true; } if ( defined.document ) { addEvent( window, "load", QUnit.load ); } })(); ================================================ FILE: test/old/test.html ================================================ 测试代码
        ================================================ FILE: test/old/test.js ================================================ var D = Data; module('Module has'); QUnit.test( "测试has接口", function( assert ) { assert.ok(D.has('a') === false, "D.has('a') === false Passed!"); D.set('a', 123); assert.ok(D.has('a') === true, "D.has('a') === true Passed!"); }); module('Module Set'); QUnit.test( "测试set接口", function( assert ) { D.set('a', 1); assert.ok( D.get('a') === 1, "Passed!" ); D.set('a', 2); assert.ok( D.get('a') === 2, "Passed!" ); D.set('a.b', 1); assert.ok( D.get('a.b') === 1, "Passed!" ); assert.ok( typeof D.get('a') === 'object', "Passed!" ); D.set('a.b.c.d.e.f', 1); assert.ok( D.get('a.b.c.d.e.f') === 1, "Passed!" ); D.set('a', {b:1}); assert.ok( D.get('a.b') === 1, "Passed!" ); D.set('a', {b:{c: [1]}}); assert.ok( D.get('a.b.c.0') === 1, "Passed!" ); D.set('a'); assert.ok( D.get('a') === undefined, "Passed!" ); D.set('1.+-*/!@#$%^&()', 1); assert.ok( D.get('1.+-*/!@#$%^&()') === 1, "Passed!" ); }); module('Module get'); QUnit.test( "测试get接口", function( assert ) { D.set('a'); assert.ok( D.get('a') === undefined, "Passed!" ); assert.ok( D.get('a.b.c.d.e.f') === undefined, "Passed!" ); assert.ok( D.get('') === undefined, "Passed!" ); assert.ok( D.get('a-b-c-d') === undefined, "Passed!" ); }); module('Module sub'); QUnit.test( "测试sub接口", function( assert ) { D.set('a'); D.sub('set', 'a', function (e) { assert.ok( e.type === 'set', "e.type === 'set' Passed!" ); assert.ok( e.key === 'a', "e.key === 'a' Passed!" ); assert.ok( e.data === 1, "e.data === 1 Passed!" ); }); D.sub('add', 'a', function (e) { assert.ok( e.type === 'add', "e.type === 'add' Passed!" ); assert.ok( e.key === 'a', "e.key === 'a' Passed!" ); assert.ok( e.data === 1, "e.data === 1 Passed!" ); }); D.sub('update', 'a', function (e) { assert.ok( e.type === 'update', "e.type === 'update' Passed!" ); assert.ok( e.key === 'a', "e.key === 'a' Passed!" ); assert.ok( e.data === 1, "e.data === 1 Passed!" ); }); D.set('a', 1); D.set('a', 1); D.sub('set', 'b.c.d', function (e) { assert.ok( e.data === 123, "e.data === 123 Passed!" ); }); D.set('b.c.d', 123); D.set('b.c', {d: 123}); D.set('test', {a: 1}); D.sub('set', 'test', function (e) { assert.ok( e.data.a === 1, "e.data.a === 1 Passed!" ); assert.ok( e.data.b === 1, "e.data.b === 1 Passed!" ); }); D.set('test', {b: 1}); }); module('Module unsub'); QUnit.test( "测试unsub接口", function( assert ) { var eid = D.sub('set', 'm', function (e) { assert.ok( e.type === 'set', "e.type === 'set' Passed!" ); }); D.set('m', 1); D.unsub('set', 'm', eid); D.set('m', 2); assert.ok( typeof eid === 'number', "typeof eid === 'number' Passed!" ); }); module('Module new Data'); QUnit.test( "测试new Data", function( assert ) { var A = new Data(); var B = new Data(); A.set('a', 123); B.set('a', 456); assert.ok(A.get('a') === 123, "A.get('a') === 123 Passed!"); assert.ok(B.get('a') === 456, "B.get('a') === 456 Passed!"); }); ================================================ FILE: test/test.js ================================================ /** * @file 单元测试文件 * @author: Jerry Zou * @date 2016年1月22日 12:45:42 */ var expect = require('expect.js'); var Data = require('../data.js'); var D = Data; function forEach(arr, callback) { for (var i = 0; i < arr.length; i++) { callback(arr[i], i, arr); } } describe('Data.js', function() { // set timeout for asynchronous code this.timeout(1000); describe('get & set', function() { it('simple get & set', function() { expect(D.get('a')).to.equal(undefined); D.set('a', 1); expect(D.get('a')).to.equal(1); D._clear(); }); it('some edge cases', function() { D.set('1.+-*/!@#$%^&()', 1); expect(D.get('1.+-*/!@#$%^&()')).to.equal(1); D.set('a'); expect(D.get('a')).to.equal(undefined); expect(D.get('a.b.c.d.e.f')).to.equal(undefined); expect(D.get('')).to.equal(undefined); expect(D.get('a-b-c-d')).to.equal(undefined); D._clear(); }); it('对原型链上可枚举属性的测试', function() { function A() { this.a = 1; } A.prototype = { b: 2 }; var a = new A(); D.set('a', a); expect(D.get('a')).to.eql({ a: 1 }); D.set('a.b', a); expect(D.get('a')).to.eql({ a: 1, b: { a: 1 } }); expect(D.get('a.b')).to.eql({ a: 1 }); D._clear(); }); var tests = [{ 'set': { 'a.b.c': 1 }, 'get': { 'a.b': { c: 1 } } }, { 'set': { 'a.b.c': [1, 2, 3] }, 'get': { 'a.b.c.1': 2, 'a': { b: { c: [1, 2, 3] } } } }, { 'set': { 'a': { b: { c: [1, 2, 3] } } }, 'get': { 'a.b.c.2': 3 } }, { 'set': { 'a.b.c.d.e.f': 1 }, 'get': { 'a.b.c.d.e': { f: 1 } } }, { 'set': { 'a': [{ b: 1 }] }, 'get': { 'a.0.b': 1, 'a': [{ b: 1 }] } }]; forEach(tests, function(test, index) { it('complex get & set - ' + index, function() { for (var key in test.set) { if (test.set.hasOwnProperty(key)) { D.set(key, test.set[key]); } } for (key in test.get) { if (test.get.hasOwnProperty(key)) { expect(D.get(key)).to.eql(test.get[key]); } } D._clear(); }); }); }); describe('has', function() { it('simple has', function() { D._clear(); expect(D.has('a')).to.equal(false); D.set('a', 1); expect(D.has('a')).to.equal(true); D._clear(); }); }); describe('sub', function() { it('several steps', function() { var target; var events = ['add', 'delete', 'set', 'set', 'set', 'update']; var eventStack = []; var tryDone = function() { if (eventStack.length >= events.length) { eventStack.sort(); expect(eventStack).to.eql(events); D._clear(); } }; forEach(['set', 'add', 'delete', 'update'], function(eventName) { D.sub(eventName, 'a', function(e) { expect(e).to.eql({ type: eventName, key: 'a', data: target }); eventStack.push(eventName); tryDone(); }); }); target = 1; D.set('a', 1); target = 2; D.set('a', 2); target = undefined; D.set('a', undefined); }); /*** * 测试用例 tests * 注意:`events`指的是这一个测试用例中,会被触发的事件名序列 */ var tests = [{ 'set': { 'a.b.c': [1, 2, 3] }, 'sub': { 'a.b.c.1': 2, 'a.b.c.2': 3 }, 'events': ['add', 'add', 'set', 'set'] }, { 'set': { 'a': { b: { c: [1, 2, 3] } } }, 'sub': { 'a': { b: { c: [1, 2, 3] } }, 'a.b': { c: [1, 2, 3] }, 'a.b.c': [1, 2, 3], 'a.b.c.2': 3 }, 'events': ['add', 'add', 'add', 'add', 'set', 'set', 'set', 'set'] }]; forEach(tests, function(test, index) { it('complex sub - ' + index, function() { D._clear(); var events = test.events; var eventStack = []; var tryDone = function(force) { if (force || eventStack.length >= events.length) { eventStack.sort(); events.sort(); expect(eventStack).to.eql(events); } }; for (key in test.sub) { if (test.sub.hasOwnProperty(key)) { (function(key) { forEach(['set', 'update', 'delete', 'add'], function(eventName) { D.sub(eventName, key, function(e) { expect(e).to.eql({ type: eventName, key: key, data: test.sub[key] }); eventStack.push(eventName); tryDone(); }); }); }(key)); } } for (var key in test.set) { if (test.set.hasOwnProperty(key)) { D.set(key, test.set[key]); } } // done by force if number of triggered events is less than expectation setTimeout(function() { tryDone(true); }, 80); }); }); }); describe('unsub', function() { it('simple test', function() { var triggerTimes = 0; var eid = D.sub('set', 'm', function(e) { triggerTimes++; }); D.set('m', 1); D.set('m', 2); D.unsub('set', 'm', eid); D.set('m', 3); D.set('m', 4); D._clear(); expect(triggerTimes).to.equal(2); }); }); describe('multiple Data', function() { it('simple test', function() { var A = new Data(); var B = new Data(); A.set('a', 123); B.set('a', 456); expect(A.get('a')).to.equal(123); expect(B.get('a')).to.equal(456); }); }); });