From c3c1a0a0db5b77b4b8ddf1c430f1c58d825ac9dd Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 14 Jan 2021 00:32:24 -0800 Subject: [PATCH 1/3] add es module support --- .gitignore | 1 + index.d.ts | 255 ++++++ index.js | 1941 +++++++++++++++++++++++++--------------------- package.json | 43 +- rollup.config.js | 10 + test/common.js | 7 - test/expect.js | 672 ++++++++-------- 7 files changed, 1673 insertions(+), 1256 deletions(-) create mode 100644 index.d.ts create mode 100644 rollup.config.js delete mode 100644 test/common.js diff --git a/.gitignore b/.gitignore index fd4f2b0..da592f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .DS_Store +dist diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..fa22599 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,255 @@ +import { Assertion } from "." + +interface Assertion { + /** + * Check if the value is truthy + */ + ok(): void + + /** + * Creates an anonymous function which calls fn with arguments. + */ + withArgs(...args: any[]): Expect + + /** + * Assert that the function throws. + * + * @param {(error: any) => any} fn - callback to match error string against + */ + throw(fn: (error: any) => void): void + /** + * Assert that the function throws. + * + * @param {RexExp} regexp - regexp to match error string against + */ + throw(regexp: RegExp): void + /** + * Assert that the function throws. + */ + throw(): void + + /** + * Assert that the function throws. + * + * @param {(error: any) => any} fn - callback to match error string against + */ + throwError(fn: (error: any) => void): void + /** + * Assert that the function throws. + * + * @param {RexExp} regexp - regexp to match error string against + */ + throwError(regexp: RegExp): void + /** + * Assert that the function throws. + */ + throwError(): void + + /** + * Assert that the function throws. + * + * @param {(error: any) => any} fn - callback to match error string against + */ + throwException(fn: (error: any) => void): void + /** + * Assert that the function throws. + * + * @param {RexExp} regexp - regexp to match error string against + */ + throwException(regexp: RegExp): void + /** + * Assert that the function throws. + */ + throwException(): void + + /** + * Checks if the array is empty. + */ + empty(): Assertion + + /** + * Checks if the obj exactly equals another. + */ + equal(obj: any): Assertion + /** + * Checks if the obj exactly equals another. + */ + be(obj: any): Assertion + + /** + * Checks if the obj sortof equals another. + */ + eql(obj: any): Assertion + + /** + * Assert within start to finish (inclusive). + * + * @param start + * @param finish + */ + within(start: number, finish: number): Assertion + + /** + * Assert typeof. + */ + a(type: string): Assertion + + /** + * Assert instanceof. + */ + a(type: Function): Assertion + + /** + * Assert typeof. + */ + an(type: string): Assertion + + /** + * Assert instanceof. + */ + an(type: Function): Assertion + + /** + * Assert typeof / instanceof. + */ + an: An + + /** + * Assert numeric value above n. + */ + greaterThan(n: number): Assertion + + /** + * Assert numeric value above n. + */ + above(n: number): Assertion + + /** + * Assert numeric value below n. + */ + lessThan(n: number): Assertion + + /** + * Assert numeric value below n. + */ + below(n: number): Assertion + + /** + * Assert string value matches regexp. + * + * @param regexp + */ + match(regexp: RegExp): Assertion + + /** + * Assert property "length" exists and has value of n. + * + * @param n + */ + length(n: number): Assertion + + /** + * Assert property name exists, with optional val. + * + * @param name + * @param val + */ + property(name: string, val?: any): Assertion + + /** + * Assert that string contains str. + */ + contain(str: string): Assertion + string(str: string): Assertion + + /** + * Assert that the array contains obj. + */ + contain(obj: any): Assertion + string(obj: any): Assertion + + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + key(keys: string[]): Assertion + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + key(...keys: string[]): Assertion + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + keys(keys: string[]): Assertion + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + keys(...keys: string[]): Assertion + + /** + * Assert a failure. + */ + fail(message?: string): Assertion +} + +interface Expect extends Assertion { + not: Not + to: To + only: Only + have: Have + be: Be +} + +interface Not extends Assertion { + to: To + be: Be + have: Have + include: Include + only: Only +} + +interface To extends Assertion { + be: Be + have: Have + include: Include + only: Only + not: Not +} + +interface Only extends Assertion { + have: Have +} + +interface Have extends Assertion { + own: Own +} + +interface Be extends Assertion { + /** + * Checks if the obj exactly equals another. + */ + (obj: any): Assertion + + an: An +} + +interface An extends Assertion { + /** + * Assert typeof. + */ + an(type: string): Assertion + + /** + * Assert instanceof. + */ + an(type: Function): Assertion +} + +interface Include extends Assertion {} + +declare var expect: { + (target?: any): Expect + version: string + stringify(value: any, showHidden?: boolean, depth?: number): string + eql(actual: any, expected: any): boolean +} +export default expect diff --git a/index.js b/index.js index 04d8371..540f0d9 100644 --- a/index.js +++ b/index.js @@ -1,81 +1,76 @@ -(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 = {}; +/** + * Exports. + */ + +export default expect + +/** + * Exports version. + */ + +expect.version = "0.3.1" + +/** + * Possible assertion flags. + */ + +const flags = { + not: ["to", "be", "have", "include", "only"], + to: ["be", "have", "include", "only", "not"], + only: ["have"], + have: ["own"], + be: ["an"], +} + +export function expect(obj) { + return new Assertion(obj) +} + +/** + * Constructor + * + * @api private + */ +export class Assertion { + constructor(obj, flag, parent) { + this.obj = obj + this.flags = {} if (undefined != parent) { - this.flags[flag] = true; + this.flags[flag] = true for (var i in parent.flags) { if (parent.flags.hasOwnProperty(i)) { - this.flags[i] = true; + this.flags[i] = true } } } - var $flags = flag ? flags[flag] : keys(flags) - , self = this; + 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; + if (this.flags[$flags[i]]) continue - var name = $flags[i] - , assertion = new Assertion(this.obj, name, this) + var name = $flags[i], + assertion = new Assertion(this.obj, name, this) - if ('function' == typeof Assertion.prototype[name]) { + if ("function" == typeof Assertion.prototype[name]) { // clone the function, make sure we dont touch the prot reference - var old = this[name]; + var old = this[name] this[name] = function () { - return old.apply(self, arguments); - }; + 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); + for (var fn of Object.getOwnPropertyNames(Assertion.prototype)) { + if (fn != name && fn !== "length") { + this[name][fn] = bind(assertion[fn], assertion) } } } else { - this[name] = assertion; + this[name] = assertion } } } @@ -84,223 +79,276 @@ /** * Performs an assertion * - * @api private + * @private */ - Assertion.prototype.assert = function (truth, msg, error, expected) { - var msg = this.flags.not ? error : msg - , ok = this.flags.not ? !truth : truth - , err; + assert(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)); + err = new Error(msg.call(this)) if (arguments.length > 3) { - err.actual = this.obj; - err.expected = expected; - err.showDiff = true; + err.actual = this.obj + err.expected = expected + err.showDiff = true } - throw err; + throw err } - this.and = new Assertion(this.obj); - }; + this.and = new Assertion(this.obj) + } /** * Check if the value is truthy * - * @api public + * @returns {void} */ - Assertion.prototype.ok = function () { + ok() { this.assert( - !!this.obj - , function(){ return 'expected ' + i(this.obj) + ' to be truthy' } - , function(){ return 'expected ' + i(this.obj) + ' to be falsy' }); - }; + !!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 + * @param {any[]} args */ - 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); }); - }; + withArgs(...args) { + expect(this.obj).to.be.a("function") + var fn = this.obj + return expect(() => fn(...args)) + } /** * Assert that the function throws. * - * @param {Function|RegExp} callback, or regexp to match error string against - * @api public + * @template {RegExp|(error:any) => any} Match + * @param {Match} [fn] - callback, or regexp to match error string against + * @returns {void} */ + throw(fn) { + expect(this.obj).to.be.a("function") - Assertion.prototype['throw'] = - Assertion.prototype.throwError = - Assertion.prototype.throwException = function (fn) { - expect(this.obj).to.be.a('function'); - - var thrown = false - , not = this.flags.not; + var thrown = false, + not = this.flags.not try { - this.obj(); + this.obj() } catch (e) { if (isRegExp(fn)) { - var subject = 'string' == typeof e ? e : e.message; + var subject = "string" == typeof e ? e : e.message if (not) { - expect(subject).to.not.match(fn); + expect(subject).to.not.match(fn) } else { - expect(subject).to.match(fn); + expect(subject).to.match(fn) } - } else if ('function' == typeof fn) { - fn(e); + } else if ("function" == typeof fn) { + fn(e) } - thrown = true; + thrown = true } if (isRegExp(fn) && not) { // in the presence of a matcher, ensure the `not` only applies to // the matching. - this.flags.not = false; + this.flags.not = false } - var name = this.obj.name || 'fn'; + 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' }); - }; + thrown, + function () { + return "expected " + name + " to throw an exception" + }, + function () { + return "expected " + name + " not to throw an exception" + } + ) + } + get throwError() { + return this.throw + } + get throwException() { + return this.throw + } /** * 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; + empty() { + 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; + expectation = !keys(this.obj).length } } else { - if ('string' != typeof this.obj) { - expect(this.obj).to.be.an('object'); + if ("string" != typeof this.obj) { + expect(this.obj).to.be.an("object") } - expect(this.obj).to.have.property('length'); - expectation = !this.obj.length; + 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; - }; + 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 + * @param {any} obj */ - Assertion.prototype.be = - Assertion.prototype.equal = function (obj) { + equal(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; - }; + 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 + } + be(obj) { + return this.equal(obj) + } /** * Checks if the obj sortof equals another. * - * @api public + * @param {any} obj */ - Assertion.prototype.eql = function (obj) { + eql(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; - }; + 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; + within(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; - }; + 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 + * @param {string|Function} type */ - - Assertion.prototype.a = - Assertion.prototype.an = function (type) { - if ('string' == typeof type) { + an(type) { + if ("string" == typeof type) { // proper english in error msg - var n = /^[aeiou]/.test(type) ? 'n' : ''; + 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 }); + "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'; + 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 }); + 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; - }; + return this + } + a(type) { + return this.an(type) + } /** * Assert numeric value above _n_. * - * @param {Number} n - * @api public + * @param {number} n */ - - Assertion.prototype.greaterThan = - Assertion.prototype.above = function (n) { + greaterThan(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; - }; + 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 + } + above(n) { + return this.greaterThan(n) + } /** * Assert numeric value below _n_. @@ -308,71 +356,95 @@ * @param {Number} n * @api public */ - - Assertion.prototype.lessThan = - Assertion.prototype.below = function (n) { + lessThan(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; - }; + 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 + } + below(n) { + return this.lessThan(n) + } /** * Assert string value matches _regexp_. * * @param {RegExp} regexp - * @api public */ - - Assertion.prototype.match = function (regexp) { + match(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; - }; + 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 + * @param {number} n */ - - Assertion.prototype.length = function (n) { - expect(this.obj).to.have.property('length'); - var len = this.obj.length; + length(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; - }; + 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 + * @param {any} val */ - - Assertion.prototype.property = function (name, val) { + property(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; + 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)); + throw new Error(i(this.obj) + " has no property " + i(name)) } } else { - var hasProp; + var hasProp try { hasProp = name in this.obj } catch (e) { @@ -380,104 +452,143 @@ } 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) }); + 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) }); + 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; - }; + this.obj = this.obj[name] + return this + } /** * Assert that the array contains _obj_ or string contains _obj_. * - * @param {Mixed} obj|string - * @api public + * @param {any} obj|string */ - - Assertion.prototype.string = - Assertion.prototype.contain = function (obj) { - if ('string' == typeof this.obj) { + contain(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) }); + ~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) }); + ~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; - }; + return this + } + get string() { + return this.contain + } /** * Assert exact keys or inclusion of keys by using * the `.own` modifier. * - * @param {Array|String ...} keys - * @api public + * @param {Array| ...} keys */ + keys($keys) { + var str, + ok = true - Assertion.prototype.key = - Assertion.prototype.keys = function ($keys) { - var str - , ok = true; + $keys = isArray($keys) ? $keys : Array.prototype.slice.call(arguments) - $keys = isArray($keys) - ? $keys - : Array.prototype.slice.call(arguments); + if (!$keys.length) throw new Error("keys required") - if (!$keys.length) throw new Error('keys required'); - - var actual = keys(this.obj) - , len = $keys.length; + var actual = keys(this.obj), + len = $keys.length // Inclusion ok = every($keys, function (key) { - return ~indexOf(actual, key); - }); + return ~indexOf(actual, key) + }) // Strict if (!this.flags.not && this.flags.only) { - ok = ok && $keys.length == actual.length; + 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; + return i(key) + }) + var last = $keys.pop() + str = $keys.join(", ") + ", and " + last } else { - str = i($keys[0]); + str = i($keys[0]) } // Form - str = (len > 1 ? 'keys ' : 'key ') + str; + str = (len > 1 ? "keys " : "key ") + str // Have / include - str = (!this.flags.only ? 'include ' : 'only have ') + str; + 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 }); + ok, + function () { + return "expected " + i(this.obj) + " to " + str + }, + function () { + return "expected " + i(this.obj) + " to not " + str + } + ) - return this; - }; + return this + } + get key() { + return this.keys + } /** * Assert a failure. @@ -485,755 +596,791 @@ * @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); + fail(msg) { + var error = function () { + return msg || "explicit failure" } + this.assert(false, error, error) + return this } +} - /** - * Array every compatibility - * - * @see bit.ly/5Fq1N2 - * @api public - */ +/** + * Function bind implementation. + */ - 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; - } +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; + } + 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) } - /** - * Array indexOf compatibility. - * - * @see bit.ly/a5Dxa2 - * @api public - */ + if (arr.length === undefined) { + return -1 + } - function indexOf (arr, o, i) { - if (Array.prototype.indexOf) { - return Array.prototype.indexOf.call(arr, o, i); - } + 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" + ) + } +} - if (arr.length === undefined) { - return -1; - } +/** + * Inspects an object. + * + * @see taken from node.js `util` module (copyright Joyent, MIT license) + * @api private + */ - for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0 - ; i < j && arr[i] !== o; i++); +function i(obj, showHidden, depth) { + var seen = [] - return j <= i ? -1 : i; + function stylize(str) { + return str } - // 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; + 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) } - }; - // 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'; + // 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") } - }; - - /** - * 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; + // For some reason typeof null is "object", so special case here. + if (value === null) { + return stylize("null", "null") } - 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'); + if (isDOMElement(value)) { + return getOuterHTML(value) + } - case 'number': - return stylize('' + value, 'number'); + // Look up the keys of the object. + var visible_keys = keys(value) + var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys - case 'boolean': - return stylize('' + value, 'boolean'); - } - // For some reason typeof null is "object", so special case here. - if (value === null) { - return stylize('null', 'null'); + // 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") } + } - if (isDOMElement(value)) { - return getOuterHTML(value); - } + // Dates without properties can be shortcutted + if (isDate(value) && $keys.length === 0) { + return stylize(value.toUTCString(), "date") + } - // Look up the keys of the object. - var visible_keys = keys(value); - var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys; + // Error objects can be shortcutted + if (value instanceof Error) { + return stylize("[" + value.toString() + "]", "Error") + } - // 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'); - } - } + var base, type, braces + // Determine the object type + if (isArray(value)) { + type = "Array" + braces = ["[", "]"] + } else { + type = "Object" + braces = ["{", "}"] + } - // Dates without properties can be shortcutted - if (isDate(value) && $keys.length === 0) { - return stylize(value.toUTCString(), 'date'); - } + // 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 = "" + } - // Error objects can be shortcutted - if (value instanceof Error) { - return stylize("["+value.toString()+"]", 'Error'); - } + // Make dates with properties first say the date + if (isDate(value)) { + base = " " + value.toUTCString() + } - var base, type, braces; - // Determine the object type - if (isArray(value)) { - type = 'Array'; - braces = ['[', ']']; - } else { - type = 'Object'; - braces = ['{', '}']; - } + if ($keys.length === 0) { + return braces[0] + base + braces[1] + } - // Make functions say that they are functions - if (typeof value === 'function') { - var n = value.name ? ': ' + value.name : ''; - base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; + if (recurseTimes < 0) { + if (isRegExp(value)) { + return stylize("" + value, "regexp") } else { - base = ''; - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + value.toUTCString(); + return stylize("[Object]", "special") } + } - if ($keys.length === 0) { - return braces[0] + base + braces[1]; - } + seen.push(value) - if (recurseTimes < 0) { - if (isRegExp(value)) { - return stylize('' + value, 'regexp'); + 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 { - return stylize('[Object]', 'special'); + if (value.__lookupSetter__(key)) { + str = stylize("[Setter]", "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'); - } + if (indexOf(visible_keys, key) < 0) { + name = "[" + key + "]" + } + if (!str) { + if (indexOf(seen, value[key]) < 0) { + if (recurseTimes === null) { + str = format(value[key]) } else { - if (value.__lookupSetter__(key)) { - str = stylize('[Setter]', 'special'); - } + str = format(value[key], recurseTimes - 1) } - } - if (indexOf(visible_keys, key) < 0) { - name = '[' + key + ']'; - } - if (!str) { - if (indexOf(seen, value[key]) < 0) { - if (recurseTimes === null) { - str = format(value[key]); + if (str.indexOf("\n") > -1) { + if (isArray(value)) { + str = map(str.split("\n"), function (line) { + return " " + line + }) + .join("\n") + .substr(2) } else { - str = format(value[key], recurseTimes - 1); + str = + "\n" + + map(str.split("\n"), function (line) { + return " " + line + }).join("\n") } - 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'); } + } 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'); - } + } + 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 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 format(obj, (typeof depth === 'undefined' ? 2 : depth)); - } - - expect.stringify = i; - function isArray (ar) { - return Object.prototype.toString.call(ar) === '[object Array]'; + return output } + return format(obj, typeof depth === "undefined" ? 2 : depth) +} - function isRegExp(re) { - var s; - try { - s = '' + re; - } catch (e) { - return false; - } +expect.stringify = i - 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 isArray(ar) { + return Object.prototype.toString.call(ar) === "[object Array]" +} - function isDate(d) { - return d instanceof Date; +function isRegExp(re) { + var s + try { + s = "" + re + } catch (e) { + return false } - function keys (obj) { - if (Object.keys) { - return Object.keys(obj); - } + 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 = []; + var keys = [] - for (var i in obj) { - if (Object.prototype.hasOwnProperty.call(obj, i)) { - keys.push(i); - } + 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; - } + var len = +this.length - // if array contains no values, no initial value to return - if (++i >= len) - throw new TypeError(); - } while (true); - } + if (typeof fun !== "function") throw new TypeError() - for (; i < len; i++) { - if (i in this) - rv = fun.call(null, rv, this[i], i, this); - } + // no value to return if no initial value and an empty array + if (len === 0 && arguments.length === 1) throw new TypeError() - return rv; - } + var i = 0 + if (arguments.length >= 2) { + var rv = arguments[1] + } else { + do { + if (i in this) { + rv = this[i++] + break + } - /** - * Asserts deep equality - * - * @see taken from node.js `assert` module (copyright Joyent, MIT license) - * @api private - */ + // if array contains no values, no initial value to return + if (++i >= len) throw new TypeError() + } while (true) + } - 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 (; i < len; i++) { + if (i in this) rv = fun.call(null, rv, this[i], i, this) + } - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } + 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; + 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.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; + // 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); + } 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); + } 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 } - }; - - function isUndefinedOrNull (value) { - return value === null || value === undefined; + a = pSlice.call(a) + b = pSlice.call(b) + return expect.eql(a, b) } - - function isArguments (object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; + 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 } - - function regExpEquiv (a, b) { - return a.source === b.source && a.global === b.global && - a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; + // 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 } - - 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; + //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"; +var json = (function () { + "use strict" - if ('object' == typeof JSON && JSON.parse && JSON.stringify) { - return { - parse: nativeJSON.parse - , stringify: nativeJSON.stringify - } + if ("object" == typeof JSON && JSON.parse && JSON.stringify) { + return { + parse: nativeJSON.parse, + stringify: nativeJSON.stringify, } + } - var JSON = {}; + var JSON = {} - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } + 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; - } + 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; + 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]. - function quote(string) { + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key] - // 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. + // If the value has a toJSON method, call it to obtain a replacement value. - 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 + '"'; + if (value instanceof Date) { + value = date(key) } + // If we were called with a replacer function, then call the replacer to + // obtain a replacement value. - 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': + if (typeof rep === "function") { + value = rep.call(holder, key, value) + } - // JSON numbers must be finite. Encode non-finite numbers as null. + // What happens next depends on the value's type. - return isFinite(value) ? String(value) : 'null'; + switch (typeof value) { + case "string": + return quote(value) - case 'boolean': - case 'null': + case "number": + // JSON numbers must be finite. Encode non-finite numbers as 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 isFinite(value) ? String(value) : "null" - return String(value); + 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. - // If the type is 'object', we might be dealing with an object or an array or - // null. + return String(value) - case 'object': + // If the type is 'object', we might be dealing with an object or an array or + // null. - // Due to a specification blunder in ECMAScript, typeof null is 'object', - // so watch out for that case. + case "object": + // Due to a specification blunder in ECMAScript, typeof null is 'object', + // so watch out for that case. - if (!value) { - return 'null'; - } + if (!value) { + return "null" + } - // Make an array to hold the partial results of stringifying this object value. + // Make an array to hold the partial results of stringifying this object value. - gap += indent; - partial = []; + gap += indent + partial = [] - // Is the value an array? + // Is the value an array? - if (Object.prototype.toString.apply(value) === '[object 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. - // 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" + } - 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 + } - // Join all of the elements together, separated with commas, and wrap them in - // brackets. + // If the replacer is an array, use it to select the members to be stringified. - v = partial.length === 0 ? '[]' : gap ? - '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; + 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. - // 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); - } - } - } + 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; + } } + + // 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. + 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 = ''; + 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 number, make an indent string containing that + // many spaces. - // If the space parameter is a string, it will be used as the indent string. + if (typeof space === "number") { + for (i = 0; i < space; i += 1) { + indent += " " + } - } else if (typeof space === 'string') { - indent = space; - } + // 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. + // 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'); - } + 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. + // Make a fake root object containing our value under the key of ''. + // Return the result of stringifying the value. - return str('', {'': value}); - }; + return str("", { "": value }) + } // If the JSON object does not yet have a parse method, give it one. - JSON.parse = function (text, reviver) { + 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]; - } - } - } + 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); + } } - + } + 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); - }); - } + 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' @@ -1248,38 +1395,34 @@ // 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 ( + /^[\],:{}\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; + throw new SyntaxError("JSON.parse") } -})( - this - , 'undefined' != typeof module ? module : {exports: {}} -); + return JSON +})() diff --git a/package.json b/package.json index ee95c88..0cd7b78 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,33 @@ { - "name": "expect.js" - , "version": "0.3.1" - , "description": "BDD style assertions for node and the browser." - , "scripts": { - "test": "mocha --require ./test/common --growl test/expect.js" - } - , "repository": { - "type": "git", - "url": "git://github.com/LearnBoost/expect.js.git" - } - , "devDependencies": { - "mocha": "*" - , "serve": "*" + "name": "expect.js", + "version": "0.3.1", + "description": "BDD style assertions for node and the browser.", + "type": "module", + "main": "./dist/index.cjs", + "module": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.js", + "require": "./dist/index.cjs" } + }, + "scripts": { + "prepare": "npm run build", + "build": "rollup --config rollup.config.js", + "test:es": "mocha --growl test/expect.js", + "test:cjs": "npm run build && mocha --growl dist/expect.cjs" + }, + "repository": { + "type": "git", + "url": "git://github.com/LearnBoost/expect.js.git" + }, + "devDependencies": { + "mocha": "*", + "serve": "*", + "typescript": "4.1.3" + }, + "dependencies": { + "@types/expect.js": "0.3.29" + } } diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..f24e94f --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,10 @@ +export default ["./index.js", "test/expect.js"].map((name) => ({ + input: [name], + output: { + dir: `dist`, + preserveModules: true, + sourcemap: true, + format: "cjs", + entryFileNames: "[name].cjs", + }, +})) diff --git a/test/common.js b/test/common.js deleted file mode 100644 index 9c11227..0000000 --- a/test/common.js +++ /dev/null @@ -1,7 +0,0 @@ - -/*! - * Common test dependencies. - */ - -// expose the globals that are obtained through `