From ccac86aa035d1f1e3d31ec949ee200c9707ebb80 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Wed, 16 Aug 2023 22:25:10 -0500 Subject: [PATCH 01/13] add used `lodash` functions --- lib/lodash/_DataView.js | 7 ++ lib/lodash/_Hash.js | 32 ++++++ lib/lodash/_ListCache.js | 32 ++++++ lib/lodash/_Map.js | 7 ++ lib/lodash/_MapCache.js | 32 ++++++ lib/lodash/_Promise.js | 7 ++ lib/lodash/_Set.js | 7 ++ lib/lodash/_Stack.js | 27 +++++ lib/lodash/_Symbol.js | 6 ++ lib/lodash/_Uint8Array.js | 6 ++ lib/lodash/_WeakMap.js | 7 ++ lib/lodash/_apply.js | 21 ++++ lib/lodash/_arrayEach.js | 22 ++++ lib/lodash/_arrayFilter.js | 25 +++++ lib/lodash/_arrayLikeKeys.js | 49 +++++++++ lib/lodash/_arrayPush.js | 20 ++++ lib/lodash/_assignMergeValue.js | 20 ++++ lib/lodash/_assignValue.js | 28 ++++++ lib/lodash/_assocIndexOf.js | 21 ++++ lib/lodash/_baseAssign.js | 17 ++++ lib/lodash/_baseAssignIn.js | 17 ++++ lib/lodash/_baseAssignValue.js | 25 +++++ lib/lodash/_baseClone.js | 171 ++++++++++++++++++++++++++++++++ lib/lodash/_baseCreate.js | 30 ++++++ lib/lodash/_baseFlatten.js | 38 +++++++ lib/lodash/_baseFor.js | 16 +++ lib/lodash/_baseGetAllKeys.js | 20 ++++ lib/lodash/_baseGetTag.js | 28 ++++++ lib/lodash/_baseIsArguments.js | 18 ++++ lib/lodash/_baseIsMap.js | 18 ++++ lib/lodash/_baseIsNative.js | 47 +++++++++ lib/lodash/_baseIsSet.js | 18 ++++ lib/lodash/_baseIsTypedArray.js | 60 +++++++++++ lib/lodash/_baseKeys.js | 30 ++++++ lib/lodash/_baseKeysIn.js | 33 ++++++ lib/lodash/_baseMerge.js | 42 ++++++++ lib/lodash/_baseMergeDeep.js | 94 ++++++++++++++++++ lib/lodash/_baseRest.js | 17 ++++ lib/lodash/_baseSetToString.js | 22 ++++ lib/lodash/_baseTimes.js | 20 ++++ lib/lodash/_baseUnary.js | 14 +++ lib/lodash/_cloneArrayBuffer.js | 16 +++ lib/lodash/_cloneBuffer.js | 35 +++++++ lib/lodash/_cloneDataView.js | 16 +++ lib/lodash/_cloneRegExp.js | 17 ++++ lib/lodash/_cloneSymbol.js | 18 ++++ lib/lodash/_cloneTypedArray.js | 16 +++ lib/lodash/_copyArray.js | 20 ++++ lib/lodash/_copyObject.js | 40 ++++++++ lib/lodash/_copySymbols.js | 16 +++ lib/lodash/_copySymbolsIn.js | 16 +++ lib/lodash/_coreJsData.js | 6 ++ lib/lodash/_createAssigner.js | 37 +++++++ lib/lodash/_createBaseFor.js | 25 +++++ lib/lodash/_defineProperty.js | 11 ++ lib/lodash/_freeGlobal.js | 4 + lib/lodash/_getAllKeys.js | 16 +++ lib/lodash/_getAllKeysIn.js | 17 ++++ lib/lodash/_getMapData.js | 18 ++++ lib/lodash/_getNative.js | 17 ++++ lib/lodash/_getPrototype.js | 6 ++ lib/lodash/_getRawTag.js | 46 +++++++++ lib/lodash/_getSymbols.js | 30 ++++++ lib/lodash/_getSymbolsIn.js | 25 +++++ lib/lodash/_getTag.js | 58 +++++++++++ lib/lodash/_getValue.js | 13 +++ lib/lodash/_hashClear.js | 15 +++ lib/lodash/_hashDelete.js | 17 ++++ lib/lodash/_hashGet.js | 30 ++++++ lib/lodash/_hashHas.js | 23 +++++ lib/lodash/_hashSet.js | 23 +++++ lib/lodash/_initCloneArray.js | 26 +++++ lib/lodash/_initCloneByTag.js | 77 ++++++++++++++ lib/lodash/_initCloneObject.js | 18 ++++ lib/lodash/_isFlattenable.js | 20 ++++ lib/lodash/_isIndex.js | 25 +++++ lib/lodash/_isIterateeCall.js | 30 ++++++ lib/lodash/_isKeyable.js | 15 +++ lib/lodash/_isMasked.js | 20 ++++ lib/lodash/_isPrototype.js | 18 ++++ lib/lodash/_listCacheClear.js | 13 +++ lib/lodash/_listCacheDelete.js | 35 +++++++ lib/lodash/_listCacheGet.js | 19 ++++ lib/lodash/_listCacheHas.js | 16 +++ lib/lodash/_listCacheSet.js | 26 +++++ lib/lodash/_mapCacheClear.js | 21 ++++ lib/lodash/_mapCacheDelete.js | 18 ++++ lib/lodash/_mapCacheGet.js | 16 +++ lib/lodash/_mapCacheHas.js | 16 +++ lib/lodash/_mapCacheSet.js | 22 ++++ lib/lodash/_nativeCreate.js | 6 ++ lib/lodash/_nativeKeys.js | 6 ++ lib/lodash/_nativeKeysIn.js | 20 ++++ lib/lodash/_nodeUtil.js | 22 ++++ lib/lodash/_objectToString.js | 22 ++++ lib/lodash/_overArg.js | 15 +++ lib/lodash/_overRest.js | 36 +++++++ lib/lodash/_root.js | 9 ++ lib/lodash/_safeGet.js | 15 +++ lib/lodash/_setToString.js | 14 +++ lib/lodash/_shortOut.js | 37 +++++++ lib/lodash/_stackClear.js | 15 +++ lib/lodash/_stackDelete.js | 18 ++++ lib/lodash/_stackGet.js | 14 +++ lib/lodash/_stackHas.js | 14 +++ lib/lodash/_stackSet.js | 34 +++++++ lib/lodash/_toSource.js | 26 +++++ lib/lodash/array.default.js | 5 + lib/lodash/array.js | 2 + lib/lodash/cloneDeep.js | 37 +++++++ lib/lodash/constant.js | 26 +++++ lib/lodash/eq.js | 37 +++++++ lib/lodash/flattenDeep.js | 33 ++++++ lib/lodash/identity.js | 21 ++++ lib/lodash/index.js | 4 + lib/lodash/isArguments.js | 36 +++++++ lib/lodash/isArray.js | 26 +++++ lib/lodash/isArrayLike.js | 33 ++++++ lib/lodash/isArrayLikeObject.js | 33 ++++++ lib/lodash/isBuffer.js | 38 +++++++ lib/lodash/isFunction.js | 37 +++++++ lib/lodash/isLength.js | 44 ++++++++ lib/lodash/isMap.js | 27 +++++ lib/lodash/isObject.js | 31 ++++++ lib/lodash/isObjectLike.js | 29 ++++++ lib/lodash/isPlainObject.js | 62 ++++++++++++ lib/lodash/isSet.js | 27 +++++ lib/lodash/isTypedArray.js | 27 +++++ lib/lodash/keys.js | 37 +++++++ lib/lodash/keysIn.js | 32 ++++++ lib/lodash/lang.default.js | 23 +++++ lib/lodash/lang.js | 17 ++++ lib/lodash/merge.js | 47 +++++++++ lib/lodash/object.default.js | 7 ++ lib/lodash/object.js | 4 + lib/lodash/stubArray.js | 23 +++++ lib/lodash/stubFalse.js | 18 ++++ lib/lodash/toPlainObject.js | 32 ++++++ lib/lodash/util.default.js | 8 ++ lib/lodash/util.js | 5 + 140 files changed, 3460 insertions(+) create mode 100644 lib/lodash/_DataView.js create mode 100644 lib/lodash/_Hash.js create mode 100644 lib/lodash/_ListCache.js create mode 100644 lib/lodash/_Map.js create mode 100644 lib/lodash/_MapCache.js create mode 100644 lib/lodash/_Promise.js create mode 100644 lib/lodash/_Set.js create mode 100644 lib/lodash/_Stack.js create mode 100644 lib/lodash/_Symbol.js create mode 100644 lib/lodash/_Uint8Array.js create mode 100644 lib/lodash/_WeakMap.js create mode 100644 lib/lodash/_apply.js create mode 100644 lib/lodash/_arrayEach.js create mode 100644 lib/lodash/_arrayFilter.js create mode 100644 lib/lodash/_arrayLikeKeys.js create mode 100644 lib/lodash/_arrayPush.js create mode 100644 lib/lodash/_assignMergeValue.js create mode 100644 lib/lodash/_assignValue.js create mode 100644 lib/lodash/_assocIndexOf.js create mode 100644 lib/lodash/_baseAssign.js create mode 100644 lib/lodash/_baseAssignIn.js create mode 100644 lib/lodash/_baseAssignValue.js create mode 100644 lib/lodash/_baseClone.js create mode 100644 lib/lodash/_baseCreate.js create mode 100644 lib/lodash/_baseFlatten.js create mode 100644 lib/lodash/_baseFor.js create mode 100644 lib/lodash/_baseGetAllKeys.js create mode 100644 lib/lodash/_baseGetTag.js create mode 100644 lib/lodash/_baseIsArguments.js create mode 100644 lib/lodash/_baseIsMap.js create mode 100644 lib/lodash/_baseIsNative.js create mode 100644 lib/lodash/_baseIsSet.js create mode 100644 lib/lodash/_baseIsTypedArray.js create mode 100644 lib/lodash/_baseKeys.js create mode 100644 lib/lodash/_baseKeysIn.js create mode 100644 lib/lodash/_baseMerge.js create mode 100644 lib/lodash/_baseMergeDeep.js create mode 100644 lib/lodash/_baseRest.js create mode 100644 lib/lodash/_baseSetToString.js create mode 100644 lib/lodash/_baseTimes.js create mode 100644 lib/lodash/_baseUnary.js create mode 100644 lib/lodash/_cloneArrayBuffer.js create mode 100644 lib/lodash/_cloneBuffer.js create mode 100644 lib/lodash/_cloneDataView.js create mode 100644 lib/lodash/_cloneRegExp.js create mode 100644 lib/lodash/_cloneSymbol.js create mode 100644 lib/lodash/_cloneTypedArray.js create mode 100644 lib/lodash/_copyArray.js create mode 100644 lib/lodash/_copyObject.js create mode 100644 lib/lodash/_copySymbols.js create mode 100644 lib/lodash/_copySymbolsIn.js create mode 100644 lib/lodash/_coreJsData.js create mode 100644 lib/lodash/_createAssigner.js create mode 100644 lib/lodash/_createBaseFor.js create mode 100644 lib/lodash/_defineProperty.js create mode 100644 lib/lodash/_freeGlobal.js create mode 100644 lib/lodash/_getAllKeys.js create mode 100644 lib/lodash/_getAllKeysIn.js create mode 100644 lib/lodash/_getMapData.js create mode 100644 lib/lodash/_getNative.js create mode 100644 lib/lodash/_getPrototype.js create mode 100644 lib/lodash/_getRawTag.js create mode 100644 lib/lodash/_getSymbols.js create mode 100644 lib/lodash/_getSymbolsIn.js create mode 100644 lib/lodash/_getTag.js create mode 100644 lib/lodash/_getValue.js create mode 100644 lib/lodash/_hashClear.js create mode 100644 lib/lodash/_hashDelete.js create mode 100644 lib/lodash/_hashGet.js create mode 100644 lib/lodash/_hashHas.js create mode 100644 lib/lodash/_hashSet.js create mode 100644 lib/lodash/_initCloneArray.js create mode 100644 lib/lodash/_initCloneByTag.js create mode 100644 lib/lodash/_initCloneObject.js create mode 100644 lib/lodash/_isFlattenable.js create mode 100644 lib/lodash/_isIndex.js create mode 100644 lib/lodash/_isIterateeCall.js create mode 100644 lib/lodash/_isKeyable.js create mode 100644 lib/lodash/_isMasked.js create mode 100644 lib/lodash/_isPrototype.js create mode 100644 lib/lodash/_listCacheClear.js create mode 100644 lib/lodash/_listCacheDelete.js create mode 100644 lib/lodash/_listCacheGet.js create mode 100644 lib/lodash/_listCacheHas.js create mode 100644 lib/lodash/_listCacheSet.js create mode 100644 lib/lodash/_mapCacheClear.js create mode 100644 lib/lodash/_mapCacheDelete.js create mode 100644 lib/lodash/_mapCacheGet.js create mode 100644 lib/lodash/_mapCacheHas.js create mode 100644 lib/lodash/_mapCacheSet.js create mode 100644 lib/lodash/_nativeCreate.js create mode 100644 lib/lodash/_nativeKeys.js create mode 100644 lib/lodash/_nativeKeysIn.js create mode 100644 lib/lodash/_nodeUtil.js create mode 100644 lib/lodash/_objectToString.js create mode 100644 lib/lodash/_overArg.js create mode 100644 lib/lodash/_overRest.js create mode 100644 lib/lodash/_root.js create mode 100644 lib/lodash/_safeGet.js create mode 100644 lib/lodash/_setToString.js create mode 100644 lib/lodash/_shortOut.js create mode 100644 lib/lodash/_stackClear.js create mode 100644 lib/lodash/_stackDelete.js create mode 100644 lib/lodash/_stackGet.js create mode 100644 lib/lodash/_stackHas.js create mode 100644 lib/lodash/_stackSet.js create mode 100644 lib/lodash/_toSource.js create mode 100644 lib/lodash/array.default.js create mode 100644 lib/lodash/array.js create mode 100644 lib/lodash/cloneDeep.js create mode 100644 lib/lodash/constant.js create mode 100644 lib/lodash/eq.js create mode 100644 lib/lodash/flattenDeep.js create mode 100644 lib/lodash/identity.js create mode 100644 lib/lodash/index.js create mode 100644 lib/lodash/isArguments.js create mode 100644 lib/lodash/isArray.js create mode 100644 lib/lodash/isArrayLike.js create mode 100644 lib/lodash/isArrayLikeObject.js create mode 100644 lib/lodash/isBuffer.js create mode 100644 lib/lodash/isFunction.js create mode 100644 lib/lodash/isLength.js create mode 100644 lib/lodash/isMap.js create mode 100644 lib/lodash/isObject.js create mode 100644 lib/lodash/isObjectLike.js create mode 100644 lib/lodash/isPlainObject.js create mode 100644 lib/lodash/isSet.js create mode 100644 lib/lodash/isTypedArray.js create mode 100644 lib/lodash/keys.js create mode 100644 lib/lodash/keysIn.js create mode 100644 lib/lodash/lang.default.js create mode 100644 lib/lodash/lang.js create mode 100644 lib/lodash/merge.js create mode 100644 lib/lodash/object.default.js create mode 100644 lib/lodash/object.js create mode 100644 lib/lodash/stubArray.js create mode 100644 lib/lodash/stubFalse.js create mode 100644 lib/lodash/toPlainObject.js create mode 100644 lib/lodash/util.default.js create mode 100644 lib/lodash/util.js diff --git a/lib/lodash/_DataView.js b/lib/lodash/_DataView.js new file mode 100644 index 0000000..1bbaaa1 --- /dev/null +++ b/lib/lodash/_DataView.js @@ -0,0 +1,7 @@ +import getNative from './_getNative.js'; +import root from './_root.js'; + +/* Built-in method references that are verified to be native. */ +var DataView = getNative(root, 'DataView'); + +export default DataView; diff --git a/lib/lodash/_Hash.js b/lib/lodash/_Hash.js new file mode 100644 index 0000000..8ecacb0 --- /dev/null +++ b/lib/lodash/_Hash.js @@ -0,0 +1,32 @@ +import hashClear from './_hashClear.js'; +import hashDelete from './_hashDelete.js'; +import hashGet from './_hashGet.js'; +import hashHas from './_hashHas.js'; +import hashSet from './_hashSet.js'; + +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; + +export default Hash; diff --git a/lib/lodash/_ListCache.js b/lib/lodash/_ListCache.js new file mode 100644 index 0000000..bafa2af --- /dev/null +++ b/lib/lodash/_ListCache.js @@ -0,0 +1,32 @@ +import listCacheClear from './_listCacheClear.js'; +import listCacheDelete from './_listCacheDelete.js'; +import listCacheGet from './_listCacheGet.js'; +import listCacheHas from './_listCacheHas.js'; +import listCacheSet from './_listCacheSet.js'; + +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; + +export default ListCache; diff --git a/lib/lodash/_Map.js b/lib/lodash/_Map.js new file mode 100644 index 0000000..2055850 --- /dev/null +++ b/lib/lodash/_Map.js @@ -0,0 +1,7 @@ +import getNative from './_getNative.js'; +import root from './_root.js'; + +/* Built-in method references that are verified to be native. */ +var Map = getNative(root, 'Map'); + +export default Map; diff --git a/lib/lodash/_MapCache.js b/lib/lodash/_MapCache.js new file mode 100644 index 0000000..deef22e --- /dev/null +++ b/lib/lodash/_MapCache.js @@ -0,0 +1,32 @@ +import mapCacheClear from './_mapCacheClear.js'; +import mapCacheDelete from './_mapCacheDelete.js'; +import mapCacheGet from './_mapCacheGet.js'; +import mapCacheHas from './_mapCacheHas.js'; +import mapCacheSet from './_mapCacheSet.js'; + +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; + +export default MapCache; diff --git a/lib/lodash/_Promise.js b/lib/lodash/_Promise.js new file mode 100644 index 0000000..ce54b58 --- /dev/null +++ b/lib/lodash/_Promise.js @@ -0,0 +1,7 @@ +import getNative from './_getNative.js'; +import root from './_root.js'; + +/* Built-in method references that are verified to be native. */ +var Promise = getNative(root, 'Promise'); + +export default Promise; diff --git a/lib/lodash/_Set.js b/lib/lodash/_Set.js new file mode 100644 index 0000000..2f95209 --- /dev/null +++ b/lib/lodash/_Set.js @@ -0,0 +1,7 @@ +import getNative from './_getNative.js'; +import root from './_root.js'; + +/* Built-in method references that are verified to be native. */ +var Set = getNative(root, 'Set'); + +export default Set; diff --git a/lib/lodash/_Stack.js b/lib/lodash/_Stack.js new file mode 100644 index 0000000..77c3cf3 --- /dev/null +++ b/lib/lodash/_Stack.js @@ -0,0 +1,27 @@ +import ListCache from './_ListCache.js'; +import stackClear from './_stackClear.js'; +import stackDelete from './_stackDelete.js'; +import stackGet from './_stackGet.js'; +import stackHas from './_stackHas.js'; +import stackSet from './_stackSet.js'; + +/** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; +} + +// Add methods to `Stack`. +Stack.prototype.clear = stackClear; +Stack.prototype['delete'] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; + +export default Stack; diff --git a/lib/lodash/_Symbol.js b/lib/lodash/_Symbol.js new file mode 100644 index 0000000..2b9341c --- /dev/null +++ b/lib/lodash/_Symbol.js @@ -0,0 +1,6 @@ +import root from './_root.js'; + +/** Built-in value references. */ +var Symbol = root.Symbol; + +export default Symbol; diff --git a/lib/lodash/_Uint8Array.js b/lib/lodash/_Uint8Array.js new file mode 100644 index 0000000..f463674 --- /dev/null +++ b/lib/lodash/_Uint8Array.js @@ -0,0 +1,6 @@ +import root from './_root.js'; + +/** Built-in value references. */ +var Uint8Array = root.Uint8Array; + +export default Uint8Array; diff --git a/lib/lodash/_WeakMap.js b/lib/lodash/_WeakMap.js new file mode 100644 index 0000000..6f97de5 --- /dev/null +++ b/lib/lodash/_WeakMap.js @@ -0,0 +1,7 @@ +import getNative from './_getNative.js'; +import root from './_root.js'; + +/* Built-in method references that are verified to be native. */ +var WeakMap = getNative(root, 'WeakMap'); + +export default WeakMap; diff --git a/lib/lodash/_apply.js b/lib/lodash/_apply.js new file mode 100644 index 0000000..a92f5a8 --- /dev/null +++ b/lib/lodash/_apply.js @@ -0,0 +1,21 @@ +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +export default apply; diff --git a/lib/lodash/_arrayEach.js b/lib/lodash/_arrayEach.js new file mode 100644 index 0000000..2a570bf --- /dev/null +++ b/lib/lodash/_arrayEach.js @@ -0,0 +1,22 @@ +/** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ +function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; +} + +export default arrayEach; diff --git a/lib/lodash/_arrayFilter.js b/lib/lodash/_arrayFilter.js new file mode 100644 index 0000000..20d3769 --- /dev/null +++ b/lib/lodash/_arrayFilter.js @@ -0,0 +1,25 @@ +/** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ +function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; +} + +export default arrayFilter; diff --git a/lib/lodash/_arrayLikeKeys.js b/lib/lodash/_arrayLikeKeys.js new file mode 100644 index 0000000..de5d551 --- /dev/null +++ b/lib/lodash/_arrayLikeKeys.js @@ -0,0 +1,49 @@ +import baseTimes from './_baseTimes.js'; +import isArguments from './isArguments.js'; +import isArray from './isArray.js'; +import isBuffer from './isBuffer.js'; +import isIndex from './_isIndex.js'; +import isTypedArray from './isTypedArray.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; +} + +export default arrayLikeKeys; diff --git a/lib/lodash/_arrayPush.js b/lib/lodash/_arrayPush.js new file mode 100644 index 0000000..3660a7d --- /dev/null +++ b/lib/lodash/_arrayPush.js @@ -0,0 +1,20 @@ +/** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ +function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; +} + +export default arrayPush; diff --git a/lib/lodash/_assignMergeValue.js b/lib/lodash/_assignMergeValue.js new file mode 100644 index 0000000..92d0916 --- /dev/null +++ b/lib/lodash/_assignMergeValue.js @@ -0,0 +1,20 @@ +import baseAssignValue from './_baseAssignValue.js'; +import eq from './eq.js'; + +/** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +export default assignMergeValue; diff --git a/lib/lodash/_assignValue.js b/lib/lodash/_assignValue.js new file mode 100644 index 0000000..c858e92 --- /dev/null +++ b/lib/lodash/_assignValue.js @@ -0,0 +1,28 @@ +import baseAssignValue from './_baseAssignValue.js'; +import eq from './eq.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +export default assignValue; diff --git a/lib/lodash/_assocIndexOf.js b/lib/lodash/_assocIndexOf.js new file mode 100644 index 0000000..88afb39 --- /dev/null +++ b/lib/lodash/_assocIndexOf.js @@ -0,0 +1,21 @@ +import eq from './eq.js'; + +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; +} + +export default assocIndexOf; diff --git a/lib/lodash/_baseAssign.js b/lib/lodash/_baseAssign.js new file mode 100644 index 0000000..81ae5a5 --- /dev/null +++ b/lib/lodash/_baseAssign.js @@ -0,0 +1,17 @@ +import copyObject from './_copyObject.js'; +import keys from './keys.js'; + +/** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ +function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); +} + +export default baseAssign; diff --git a/lib/lodash/_baseAssignIn.js b/lib/lodash/_baseAssignIn.js new file mode 100644 index 0000000..83c6e83 --- /dev/null +++ b/lib/lodash/_baseAssignIn.js @@ -0,0 +1,17 @@ +import copyObject from './_copyObject.js'; +import keysIn from './keysIn.js'; + +/** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ +function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); +} + +export default baseAssignIn; diff --git a/lib/lodash/_baseAssignValue.js b/lib/lodash/_baseAssignValue.js new file mode 100644 index 0000000..8d55996 --- /dev/null +++ b/lib/lodash/_baseAssignValue.js @@ -0,0 +1,25 @@ +import defineProperty from './_defineProperty.js'; + +/** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } +} + +export default baseAssignValue; diff --git a/lib/lodash/_baseClone.js b/lib/lodash/_baseClone.js new file mode 100644 index 0000000..ad29619 --- /dev/null +++ b/lib/lodash/_baseClone.js @@ -0,0 +1,171 @@ +import Stack from './_Stack.js'; +import arrayEach from './_arrayEach.js'; +import assignValue from './_assignValue.js'; +import baseAssign from './_baseAssign.js'; +import baseAssignIn from './_baseAssignIn.js'; +import cloneBuffer from './_cloneBuffer.js'; +import copyArray from './_copyArray.js'; +import copySymbols from './_copySymbols.js'; +import copySymbolsIn from './_copySymbolsIn.js'; +import getAllKeys from './_getAllKeys.js'; +import getAllKeysIn from './_getAllKeysIn.js'; +import getTag from './_getTag.js'; +import initCloneArray from './_initCloneArray.js'; +import initCloneByTag from './_initCloneByTag.js'; +import initCloneObject from './_initCloneObject.js'; +import isArray from './isArray.js'; +import isBuffer from './isBuffer.js'; +import isMap from './isMap.js'; +import isObject from './isObject.js'; +import isSet from './isSet.js'; +import keys from './keys.js'; + +/** Used to compose bitmasks for cloning. */ +var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values supported by `_.clone`. */ +var cloneableTags = {}; +cloneableTags[argsTag] = cloneableTags[arrayTag] = +cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = +cloneableTags[boolTag] = cloneableTags[dateTag] = +cloneableTags[float32Tag] = cloneableTags[float64Tag] = +cloneableTags[int8Tag] = cloneableTags[int16Tag] = +cloneableTags[int32Tag] = cloneableTags[mapTag] = +cloneableTags[numberTag] = cloneableTags[objectTag] = +cloneableTags[regexpTag] = cloneableTags[setTag] = +cloneableTags[stringTag] = cloneableTags[symbolTag] = +cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = +cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; +cloneableTags[errorTag] = cloneableTags[funcTag] = +cloneableTags[weakMapTag] = false; + +/** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ +function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function(subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function(subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; +} + +export default baseClone; diff --git a/lib/lodash/_baseCreate.js b/lib/lodash/_baseCreate.js new file mode 100644 index 0000000..ad1da38 --- /dev/null +++ b/lib/lodash/_baseCreate.js @@ -0,0 +1,30 @@ +import isObject from './isObject.js'; + +/** Built-in value references. */ +var objectCreate = Object.create; + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; +}()); + +export default baseCreate; diff --git a/lib/lodash/_baseFlatten.js b/lib/lodash/_baseFlatten.js new file mode 100644 index 0000000..b42dee6 --- /dev/null +++ b/lib/lodash/_baseFlatten.js @@ -0,0 +1,38 @@ +import arrayPush from './_arrayPush.js'; +import isFlattenable from './_isFlattenable.js'; + +/** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ +function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; +} + +export default baseFlatten; diff --git a/lib/lodash/_baseFor.js b/lib/lodash/_baseFor.js new file mode 100644 index 0000000..debbcf8 --- /dev/null +++ b/lib/lodash/_baseFor.js @@ -0,0 +1,16 @@ +import createBaseFor from './_createBaseFor.js'; + +/** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +var baseFor = createBaseFor(); + +export default baseFor; diff --git a/lib/lodash/_baseGetAllKeys.js b/lib/lodash/_baseGetAllKeys.js new file mode 100644 index 0000000..af5533b --- /dev/null +++ b/lib/lodash/_baseGetAllKeys.js @@ -0,0 +1,20 @@ +import arrayPush from './_arrayPush.js'; +import isArray from './isArray.js'; + +/** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ +function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); +} + +export default baseGetAllKeys; diff --git a/lib/lodash/_baseGetTag.js b/lib/lodash/_baseGetTag.js new file mode 100644 index 0000000..61b440a --- /dev/null +++ b/lib/lodash/_baseGetTag.js @@ -0,0 +1,28 @@ +import Symbol from './_Symbol.js'; +import getRawTag from './_getRawTag.js'; +import objectToString from './_objectToString.js'; + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +export default baseGetTag; diff --git a/lib/lodash/_baseIsArguments.js b/lib/lodash/_baseIsArguments.js new file mode 100644 index 0000000..cbf4ca6 --- /dev/null +++ b/lib/lodash/_baseIsArguments.js @@ -0,0 +1,18 @@ +import baseGetTag from './_baseGetTag.js'; +import isObjectLike from './isObjectLike.js'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; + +/** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; +} + +export default baseIsArguments; diff --git a/lib/lodash/_baseIsMap.js b/lib/lodash/_baseIsMap.js new file mode 100644 index 0000000..6438d2b --- /dev/null +++ b/lib/lodash/_baseIsMap.js @@ -0,0 +1,18 @@ +import getTag from './_getTag.js'; +import isObjectLike from './isObjectLike.js'; + +/** `Object#toString` result references. */ +var mapTag = '[object Map]'; + +/** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ +function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; +} + +export default baseIsMap; diff --git a/lib/lodash/_baseIsNative.js b/lib/lodash/_baseIsNative.js new file mode 100644 index 0000000..04c1854 --- /dev/null +++ b/lib/lodash/_baseIsNative.js @@ -0,0 +1,47 @@ +import isFunction from './isFunction.js'; +import isMasked from './_isMasked.js'; +import isObject from './isObject.js'; +import toSource from './_toSource.js'; + +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} + +export default baseIsNative; diff --git a/lib/lodash/_baseIsSet.js b/lib/lodash/_baseIsSet.js new file mode 100644 index 0000000..bee4a8e --- /dev/null +++ b/lib/lodash/_baseIsSet.js @@ -0,0 +1,18 @@ +import getTag from './_getTag.js'; +import isObjectLike from './isObjectLike.js'; + +/** `Object#toString` result references. */ +var setTag = '[object Set]'; + +/** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ +function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; +} + +export default baseIsSet; diff --git a/lib/lodash/_baseIsTypedArray.js b/lib/lodash/_baseIsTypedArray.js new file mode 100644 index 0000000..0a18d1c --- /dev/null +++ b/lib/lodash/_baseIsTypedArray.js @@ -0,0 +1,60 @@ +import baseGetTag from './_baseGetTag.js'; +import isLength from './isLength.js'; +import isObjectLike from './isObjectLike.js'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = +typedArrayTags[errorTag] = typedArrayTags[funcTag] = +typedArrayTags[mapTag] = typedArrayTags[numberTag] = +typedArrayTags[objectTag] = typedArrayTags[regexpTag] = +typedArrayTags[setTag] = typedArrayTags[stringTag] = +typedArrayTags[weakMapTag] = false; + +/** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ +function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +} + +export default baseIsTypedArray; diff --git a/lib/lodash/_baseKeys.js b/lib/lodash/_baseKeys.js new file mode 100644 index 0000000..5a76224 --- /dev/null +++ b/lib/lodash/_baseKeys.js @@ -0,0 +1,30 @@ +import isPrototype from './_isPrototype.js'; +import nativeKeys from './_nativeKeys.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; +} + +export default baseKeys; diff --git a/lib/lodash/_baseKeysIn.js b/lib/lodash/_baseKeysIn.js new file mode 100644 index 0000000..84c1395 --- /dev/null +++ b/lib/lodash/_baseKeysIn.js @@ -0,0 +1,33 @@ +import isObject from './isObject.js'; +import isPrototype from './_isPrototype.js'; +import nativeKeysIn from './_nativeKeysIn.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; +} + +export default baseKeysIn; diff --git a/lib/lodash/_baseMerge.js b/lib/lodash/_baseMerge.js new file mode 100644 index 0000000..1511498 --- /dev/null +++ b/lib/lodash/_baseMerge.js @@ -0,0 +1,42 @@ +import Stack from './_Stack.js'; +import assignMergeValue from './_assignMergeValue.js'; +import baseFor from './_baseFor.js'; +import baseMergeDeep from './_baseMergeDeep.js'; +import isObject from './isObject.js'; +import keysIn from './keysIn.js'; +import safeGet from './_safeGet.js'; + +/** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); +} + +export default baseMerge; diff --git a/lib/lodash/_baseMergeDeep.js b/lib/lodash/_baseMergeDeep.js new file mode 100644 index 0000000..2c2c657 --- /dev/null +++ b/lib/lodash/_baseMergeDeep.js @@ -0,0 +1,94 @@ +import assignMergeValue from './_assignMergeValue.js'; +import cloneBuffer from './_cloneBuffer.js'; +import cloneTypedArray from './_cloneTypedArray.js'; +import copyArray from './_copyArray.js'; +import initCloneObject from './_initCloneObject.js'; +import isArguments from './isArguments.js'; +import isArray from './isArray.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import isBuffer from './isBuffer.js'; +import isFunction from './isFunction.js'; +import isObject from './isObject.js'; +import isPlainObject from './isPlainObject.js'; +import isTypedArray from './isTypedArray.js'; +import safeGet from './_safeGet.js'; +import toPlainObject from './toPlainObject.js'; + +/** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); +} + +export default baseMergeDeep; diff --git a/lib/lodash/_baseRest.js b/lib/lodash/_baseRest.js new file mode 100644 index 0000000..a315371 --- /dev/null +++ b/lib/lodash/_baseRest.js @@ -0,0 +1,17 @@ +import identity from './identity.js'; +import overRest from './_overRest.js'; +import setToString from './_setToString.js'; + +/** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +export default baseRest; diff --git a/lib/lodash/_baseSetToString.js b/lib/lodash/_baseSetToString.js new file mode 100644 index 0000000..e712c11 --- /dev/null +++ b/lib/lodash/_baseSetToString.js @@ -0,0 +1,22 @@ +import constant from './constant.js'; +import defineProperty from './_defineProperty.js'; +import identity from './identity.js'; + +/** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; + +export default baseSetToString; diff --git a/lib/lodash/_baseTimes.js b/lib/lodash/_baseTimes.js new file mode 100644 index 0000000..d5d0e27 --- /dev/null +++ b/lib/lodash/_baseTimes.js @@ -0,0 +1,20 @@ +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +export default baseTimes; diff --git a/lib/lodash/_baseUnary.js b/lib/lodash/_baseUnary.js new file mode 100644 index 0000000..e756a32 --- /dev/null +++ b/lib/lodash/_baseUnary.js @@ -0,0 +1,14 @@ +/** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ +function baseUnary(func) { + return function(value) { + return func(value); + }; +} + +export default baseUnary; diff --git a/lib/lodash/_cloneArrayBuffer.js b/lib/lodash/_cloneArrayBuffer.js new file mode 100644 index 0000000..9f33e7a --- /dev/null +++ b/lib/lodash/_cloneArrayBuffer.js @@ -0,0 +1,16 @@ +import Uint8Array from './_Uint8Array.js'; + +/** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; +} + +export default cloneArrayBuffer; diff --git a/lib/lodash/_cloneBuffer.js b/lib/lodash/_cloneBuffer.js new file mode 100644 index 0000000..21b192e --- /dev/null +++ b/lib/lodash/_cloneBuffer.js @@ -0,0 +1,35 @@ +import root from './_root.js'; + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined; + +/** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; +} + +export default cloneBuffer; diff --git a/lib/lodash/_cloneDataView.js b/lib/lodash/_cloneDataView.js new file mode 100644 index 0000000..f9b9a6f --- /dev/null +++ b/lib/lodash/_cloneDataView.js @@ -0,0 +1,16 @@ +import cloneArrayBuffer from './_cloneArrayBuffer.js'; + +/** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ +function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); +} + +export default cloneDataView; diff --git a/lib/lodash/_cloneRegExp.js b/lib/lodash/_cloneRegExp.js new file mode 100644 index 0000000..0ddb49b --- /dev/null +++ b/lib/lodash/_cloneRegExp.js @@ -0,0 +1,17 @@ +/** Used to match `RegExp` flags from their coerced string values. */ +var reFlags = /\w*$/; + +/** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ +function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; +} + +export default cloneRegExp; diff --git a/lib/lodash/_cloneSymbol.js b/lib/lodash/_cloneSymbol.js new file mode 100644 index 0000000..357b155 --- /dev/null +++ b/lib/lodash/_cloneSymbol.js @@ -0,0 +1,18 @@ +import Symbol from './_Symbol.js'; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; + +/** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ +function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; +} + +export default cloneSymbol; diff --git a/lib/lodash/_cloneTypedArray.js b/lib/lodash/_cloneTypedArray.js new file mode 100644 index 0000000..2fa9b8a --- /dev/null +++ b/lib/lodash/_cloneTypedArray.js @@ -0,0 +1,16 @@ +import cloneArrayBuffer from './_cloneArrayBuffer.js'; + +/** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} + +export default cloneTypedArray; diff --git a/lib/lodash/_copyArray.js b/lib/lodash/_copyArray.js new file mode 100644 index 0000000..b29b71e --- /dev/null +++ b/lib/lodash/_copyArray.js @@ -0,0 +1,20 @@ +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} + +export default copyArray; diff --git a/lib/lodash/_copyObject.js b/lib/lodash/_copyObject.js new file mode 100644 index 0000000..4e24755 --- /dev/null +++ b/lib/lodash/_copyObject.js @@ -0,0 +1,40 @@ +import assignValue from './_assignValue.js'; +import baseAssignValue from './_baseAssignValue.js'; + +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; +} + +export default copyObject; diff --git a/lib/lodash/_copySymbols.js b/lib/lodash/_copySymbols.js new file mode 100644 index 0000000..002d8b7 --- /dev/null +++ b/lib/lodash/_copySymbols.js @@ -0,0 +1,16 @@ +import copyObject from './_copyObject.js'; +import getSymbols from './_getSymbols.js'; + +/** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ +function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); +} + +export default copySymbols; diff --git a/lib/lodash/_copySymbolsIn.js b/lib/lodash/_copySymbolsIn.js new file mode 100644 index 0000000..12268d2 --- /dev/null +++ b/lib/lodash/_copySymbolsIn.js @@ -0,0 +1,16 @@ +import copyObject from './_copyObject.js'; +import getSymbolsIn from './_getSymbolsIn.js'; + +/** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ +function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); +} + +export default copySymbolsIn; diff --git a/lib/lodash/_coreJsData.js b/lib/lodash/_coreJsData.js new file mode 100644 index 0000000..2ad4fc1 --- /dev/null +++ b/lib/lodash/_coreJsData.js @@ -0,0 +1,6 @@ +import root from './_root.js'; + +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; + +export default coreJsData; diff --git a/lib/lodash/_createAssigner.js b/lib/lodash/_createAssigner.js new file mode 100644 index 0000000..67dc499 --- /dev/null +++ b/lib/lodash/_createAssigner.js @@ -0,0 +1,37 @@ +import baseRest from './_baseRest.js'; +import isIterateeCall from './_isIterateeCall.js'; + +/** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +export default createAssigner; diff --git a/lib/lodash/_createBaseFor.js b/lib/lodash/_createBaseFor.js new file mode 100644 index 0000000..ac15c59 --- /dev/null +++ b/lib/lodash/_createBaseFor.js @@ -0,0 +1,25 @@ +/** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +export default createBaseFor; diff --git a/lib/lodash/_defineProperty.js b/lib/lodash/_defineProperty.js new file mode 100644 index 0000000..826fc1d --- /dev/null +++ b/lib/lodash/_defineProperty.js @@ -0,0 +1,11 @@ +import getNative from './_getNative.js'; + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +export default defineProperty; diff --git a/lib/lodash/_freeGlobal.js b/lib/lodash/_freeGlobal.js new file mode 100644 index 0000000..5e383a1 --- /dev/null +++ b/lib/lodash/_freeGlobal.js @@ -0,0 +1,4 @@ +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +export default freeGlobal; diff --git a/lib/lodash/_getAllKeys.js b/lib/lodash/_getAllKeys.js new file mode 100644 index 0000000..e9a6772 --- /dev/null +++ b/lib/lodash/_getAllKeys.js @@ -0,0 +1,16 @@ +import baseGetAllKeys from './_baseGetAllKeys.js'; +import getSymbols from './_getSymbols.js'; +import keys from './keys.js'; + +/** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); +} + +export default getAllKeys; diff --git a/lib/lodash/_getAllKeysIn.js b/lib/lodash/_getAllKeysIn.js new file mode 100644 index 0000000..d7fac96 --- /dev/null +++ b/lib/lodash/_getAllKeysIn.js @@ -0,0 +1,17 @@ +import baseGetAllKeys from './_baseGetAllKeys.js'; +import getSymbolsIn from './_getSymbolsIn.js'; +import keysIn from './keysIn.js'; + +/** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); +} + +export default getAllKeysIn; diff --git a/lib/lodash/_getMapData.js b/lib/lodash/_getMapData.js new file mode 100644 index 0000000..6f55f4f --- /dev/null +++ b/lib/lodash/_getMapData.js @@ -0,0 +1,18 @@ +import isKeyable from './_isKeyable.js'; + +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} + +export default getMapData; diff --git a/lib/lodash/_getNative.js b/lib/lodash/_getNative.js new file mode 100644 index 0000000..d2cb438 --- /dev/null +++ b/lib/lodash/_getNative.js @@ -0,0 +1,17 @@ +import baseIsNative from './_baseIsNative.js'; +import getValue from './_getValue.js'; + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +export default getNative; diff --git a/lib/lodash/_getPrototype.js b/lib/lodash/_getPrototype.js new file mode 100644 index 0000000..ce92d48 --- /dev/null +++ b/lib/lodash/_getPrototype.js @@ -0,0 +1,6 @@ +import overArg from './_overArg.js'; + +/** Built-in value references. */ +var getPrototype = overArg(Object.getPrototypeOf, Object); + +export default getPrototype; diff --git a/lib/lodash/_getRawTag.js b/lib/lodash/_getRawTag.js new file mode 100644 index 0000000..a89a35b --- /dev/null +++ b/lib/lodash/_getRawTag.js @@ -0,0 +1,46 @@ +import Symbol from './_Symbol.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +export default getRawTag; diff --git a/lib/lodash/_getSymbols.js b/lib/lodash/_getSymbols.js new file mode 100644 index 0000000..474442a --- /dev/null +++ b/lib/lodash/_getSymbols.js @@ -0,0 +1,30 @@ +import arrayFilter from './_arrayFilter.js'; +import stubArray from './stubArray.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); +}; + +export default getSymbols; diff --git a/lib/lodash/_getSymbolsIn.js b/lib/lodash/_getSymbolsIn.js new file mode 100644 index 0000000..5f33b71 --- /dev/null +++ b/lib/lodash/_getSymbolsIn.js @@ -0,0 +1,25 @@ +import arrayPush from './_arrayPush.js'; +import getPrototype from './_getPrototype.js'; +import getSymbols from './_getSymbols.js'; +import stubArray from './stubArray.js'; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; +}; + +export default getSymbolsIn; diff --git a/lib/lodash/_getTag.js b/lib/lodash/_getTag.js new file mode 100644 index 0000000..0c86db0 --- /dev/null +++ b/lib/lodash/_getTag.js @@ -0,0 +1,58 @@ +import DataView from './_DataView.js'; +import Map from './_Map.js'; +import Promise from './_Promise.js'; +import Set from './_Set.js'; +import WeakMap from './_WeakMap.js'; +import baseGetTag from './_baseGetTag.js'; +import toSource from './_toSource.js'; + +/** `Object#toString` result references. */ +var mapTag = '[object Map]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + setTag = '[object Set]', + weakMapTag = '[object WeakMap]'; + +var dataViewTag = '[object DataView]'; + +/** Used to detect maps, sets, and weakmaps. */ +var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + +/** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +var getTag = baseGetTag; + +// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. +if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; +} + +export default getTag; diff --git a/lib/lodash/_getValue.js b/lib/lodash/_getValue.js new file mode 100644 index 0000000..cbdd538 --- /dev/null +++ b/lib/lodash/_getValue.js @@ -0,0 +1,13 @@ +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +export default getValue; diff --git a/lib/lodash/_hashClear.js b/lib/lodash/_hashClear.js new file mode 100644 index 0000000..5b7cc2d --- /dev/null +++ b/lib/lodash/_hashClear.js @@ -0,0 +1,15 @@ +import nativeCreate from './_nativeCreate.js'; + +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} + +export default hashClear; diff --git a/lib/lodash/_hashDelete.js b/lib/lodash/_hashDelete.js new file mode 100644 index 0000000..509839f --- /dev/null +++ b/lib/lodash/_hashDelete.js @@ -0,0 +1,17 @@ +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} + +export default hashDelete; diff --git a/lib/lodash/_hashGet.js b/lib/lodash/_hashGet.js new file mode 100644 index 0000000..4a3f43b --- /dev/null +++ b/lib/lodash/_hashGet.js @@ -0,0 +1,30 @@ +import nativeCreate from './_nativeCreate.js'; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; +} + +export default hashGet; diff --git a/lib/lodash/_hashHas.js b/lib/lodash/_hashHas.js new file mode 100644 index 0000000..6db025d --- /dev/null +++ b/lib/lodash/_hashHas.js @@ -0,0 +1,23 @@ +import nativeCreate from './_nativeCreate.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +} + +export default hashHas; diff --git a/lib/lodash/_hashSet.js b/lib/lodash/_hashSet.js new file mode 100644 index 0000000..63a0115 --- /dev/null +++ b/lib/lodash/_hashSet.js @@ -0,0 +1,23 @@ +import nativeCreate from './_nativeCreate.js'; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; +} + +export default hashSet; diff --git a/lib/lodash/_initCloneArray.js b/lib/lodash/_initCloneArray.js new file mode 100644 index 0000000..67478a8 --- /dev/null +++ b/lib/lodash/_initCloneArray.js @@ -0,0 +1,26 @@ +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ +function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; +} + +export default initCloneArray; diff --git a/lib/lodash/_initCloneByTag.js b/lib/lodash/_initCloneByTag.js new file mode 100644 index 0000000..0b03f8d --- /dev/null +++ b/lib/lodash/_initCloneByTag.js @@ -0,0 +1,77 @@ +import cloneArrayBuffer from './_cloneArrayBuffer.js'; +import cloneDataView from './_cloneDataView.js'; +import cloneRegExp from './_cloneRegExp.js'; +import cloneSymbol from './_cloneSymbol.js'; +import cloneTypedArray from './_cloneTypedArray.js'; + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]', + dateTag = '[object Date]', + mapTag = '[object Map]', + numberTag = '[object Number]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } +} + +export default initCloneByTag; diff --git a/lib/lodash/_initCloneObject.js b/lib/lodash/_initCloneObject.js new file mode 100644 index 0000000..bdcf19b --- /dev/null +++ b/lib/lodash/_initCloneObject.js @@ -0,0 +1,18 @@ +import baseCreate from './_baseCreate.js'; +import getPrototype from './_getPrototype.js'; +import isPrototype from './_isPrototype.js'; + +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; +} + +export default initCloneObject; diff --git a/lib/lodash/_isFlattenable.js b/lib/lodash/_isFlattenable.js new file mode 100644 index 0000000..3bdef96 --- /dev/null +++ b/lib/lodash/_isFlattenable.js @@ -0,0 +1,20 @@ +import Symbol from './_Symbol.js'; +import isArguments from './isArguments.js'; +import isArray from './isArray.js'; + +/** Built-in value references. */ +var spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined; + +/** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ +function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); +} + +export default isFlattenable; diff --git a/lib/lodash/_isIndex.js b/lib/lodash/_isIndex.js new file mode 100644 index 0000000..b6cb47f --- /dev/null +++ b/lib/lodash/_isIndex.js @@ -0,0 +1,25 @@ +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); +} + +export default isIndex; diff --git a/lib/lodash/_isIterateeCall.js b/lib/lodash/_isIterateeCall.js new file mode 100644 index 0000000..1fb6dc9 --- /dev/null +++ b/lib/lodash/_isIterateeCall.js @@ -0,0 +1,30 @@ +import eq from './eq.js'; +import isArrayLike from './isArrayLike.js'; +import isIndex from './_isIndex.js'; +import isObject from './isObject.js'; + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +export default isIterateeCall; diff --git a/lib/lodash/_isKeyable.js b/lib/lodash/_isKeyable.js new file mode 100644 index 0000000..2271596 --- /dev/null +++ b/lib/lodash/_isKeyable.js @@ -0,0 +1,15 @@ +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} + +export default isKeyable; diff --git a/lib/lodash/_isMasked.js b/lib/lodash/_isMasked.js new file mode 100644 index 0000000..e3f9d6f --- /dev/null +++ b/lib/lodash/_isMasked.js @@ -0,0 +1,20 @@ +import coreJsData from './_coreJsData.js'; + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +export default isMasked; diff --git a/lib/lodash/_isPrototype.js b/lib/lodash/_isPrototype.js new file mode 100644 index 0000000..f6c7660 --- /dev/null +++ b/lib/lodash/_isPrototype.js @@ -0,0 +1,18 @@ +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; +} + +export default isPrototype; diff --git a/lib/lodash/_listCacheClear.js b/lib/lodash/_listCacheClear.js new file mode 100644 index 0000000..8cfa184 --- /dev/null +++ b/lib/lodash/_listCacheClear.js @@ -0,0 +1,13 @@ +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +export default listCacheClear; diff --git a/lib/lodash/_listCacheDelete.js b/lib/lodash/_listCacheDelete.js new file mode 100644 index 0000000..b08c834 --- /dev/null +++ b/lib/lodash/_listCacheDelete.js @@ -0,0 +1,35 @@ +import assocIndexOf from './_assocIndexOf.js'; + +/** Used for built-in method references. */ +var arrayProto = Array.prototype; + +/** Built-in value references. */ +var splice = arrayProto.splice; + +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} + +export default listCacheDelete; diff --git a/lib/lodash/_listCacheGet.js b/lib/lodash/_listCacheGet.js new file mode 100644 index 0000000..53ce001 --- /dev/null +++ b/lib/lodash/_listCacheGet.js @@ -0,0 +1,19 @@ +import assocIndexOf from './_assocIndexOf.js'; + +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; +} + +export default listCacheGet; diff --git a/lib/lodash/_listCacheHas.js b/lib/lodash/_listCacheHas.js new file mode 100644 index 0000000..8701cae --- /dev/null +++ b/lib/lodash/_listCacheHas.js @@ -0,0 +1,16 @@ +import assocIndexOf from './_assocIndexOf.js'; + +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} + +export default listCacheHas; diff --git a/lib/lodash/_listCacheSet.js b/lib/lodash/_listCacheSet.js new file mode 100644 index 0000000..8c5a198 --- /dev/null +++ b/lib/lodash/_listCacheSet.js @@ -0,0 +1,26 @@ +import assocIndexOf from './_assocIndexOf.js'; + +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} + +export default listCacheSet; diff --git a/lib/lodash/_mapCacheClear.js b/lib/lodash/_mapCacheClear.js new file mode 100644 index 0000000..e6b3d9c --- /dev/null +++ b/lib/lodash/_mapCacheClear.js @@ -0,0 +1,21 @@ +import Hash from './_Hash.js'; +import ListCache from './_ListCache.js'; +import Map from './_Map.js'; + +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; +} + +export default mapCacheClear; diff --git a/lib/lodash/_mapCacheDelete.js b/lib/lodash/_mapCacheDelete.js new file mode 100644 index 0000000..1afc18f --- /dev/null +++ b/lib/lodash/_mapCacheDelete.js @@ -0,0 +1,18 @@ +import getMapData from './_getMapData.js'; + +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} + +export default mapCacheDelete; diff --git a/lib/lodash/_mapCacheGet.js b/lib/lodash/_mapCacheGet.js new file mode 100644 index 0000000..3b481e0 --- /dev/null +++ b/lib/lodash/_mapCacheGet.js @@ -0,0 +1,16 @@ +import getMapData from './_getMapData.js'; + +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} + +export default mapCacheGet; diff --git a/lib/lodash/_mapCacheHas.js b/lib/lodash/_mapCacheHas.js new file mode 100644 index 0000000..9de3e7f --- /dev/null +++ b/lib/lodash/_mapCacheHas.js @@ -0,0 +1,16 @@ +import getMapData from './_getMapData.js'; + +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} + +export default mapCacheHas; diff --git a/lib/lodash/_mapCacheSet.js b/lib/lodash/_mapCacheSet.js new file mode 100644 index 0000000..e757c36 --- /dev/null +++ b/lib/lodash/_mapCacheSet.js @@ -0,0 +1,22 @@ +import getMapData from './_getMapData.js'; + +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} + +export default mapCacheSet; diff --git a/lib/lodash/_nativeCreate.js b/lib/lodash/_nativeCreate.js new file mode 100644 index 0000000..27b476b --- /dev/null +++ b/lib/lodash/_nativeCreate.js @@ -0,0 +1,6 @@ +import getNative from './_getNative.js'; + +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); + +export default nativeCreate; diff --git a/lib/lodash/_nativeKeys.js b/lib/lodash/_nativeKeys.js new file mode 100644 index 0000000..2ec8ec6 --- /dev/null +++ b/lib/lodash/_nativeKeys.js @@ -0,0 +1,6 @@ +import overArg from './_overArg.js'; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeKeys = overArg(Object.keys, Object); + +export default nativeKeys; diff --git a/lib/lodash/_nativeKeysIn.js b/lib/lodash/_nativeKeysIn.js new file mode 100644 index 0000000..94eda99 --- /dev/null +++ b/lib/lodash/_nativeKeysIn.js @@ -0,0 +1,20 @@ +/** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; +} + +export default nativeKeysIn; diff --git a/lib/lodash/_nodeUtil.js b/lib/lodash/_nodeUtil.js new file mode 100644 index 0000000..4673316 --- /dev/null +++ b/lib/lodash/_nodeUtil.js @@ -0,0 +1,22 @@ +import freeGlobal from './_freeGlobal.js'; + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +export default nodeUtil; diff --git a/lib/lodash/_objectToString.js b/lib/lodash/_objectToString.js new file mode 100644 index 0000000..749a5f9 --- /dev/null +++ b/lib/lodash/_objectToString.js @@ -0,0 +1,22 @@ +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} + +export default objectToString; diff --git a/lib/lodash/_overArg.js b/lib/lodash/_overArg.js new file mode 100644 index 0000000..93bafe3 --- /dev/null +++ b/lib/lodash/_overArg.js @@ -0,0 +1,15 @@ +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +export default overArg; diff --git a/lib/lodash/_overRest.js b/lib/lodash/_overRest.js new file mode 100644 index 0000000..f4f79cb --- /dev/null +++ b/lib/lodash/_overRest.js @@ -0,0 +1,36 @@ +import apply from './_apply.js'; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +export default overRest; diff --git a/lib/lodash/_root.js b/lib/lodash/_root.js new file mode 100644 index 0000000..281f812 --- /dev/null +++ b/lib/lodash/_root.js @@ -0,0 +1,9 @@ +import freeGlobal from './_freeGlobal.js'; + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +export default root; diff --git a/lib/lodash/_safeGet.js b/lib/lodash/_safeGet.js new file mode 100644 index 0000000..be5bfc3 --- /dev/null +++ b/lib/lodash/_safeGet.js @@ -0,0 +1,15 @@ +/** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; +} + +export default safeGet; diff --git a/lib/lodash/_setToString.js b/lib/lodash/_setToString.js new file mode 100644 index 0000000..db2dd26 --- /dev/null +++ b/lib/lodash/_setToString.js @@ -0,0 +1,14 @@ +import baseSetToString from './_baseSetToString.js'; +import shortOut from './_shortOut.js'; + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +export default setToString; diff --git a/lib/lodash/_shortOut.js b/lib/lodash/_shortOut.js new file mode 100644 index 0000000..78fadcd --- /dev/null +++ b/lib/lodash/_shortOut.js @@ -0,0 +1,37 @@ +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +export default shortOut; diff --git a/lib/lodash/_stackClear.js b/lib/lodash/_stackClear.js new file mode 100644 index 0000000..d4b10b0 --- /dev/null +++ b/lib/lodash/_stackClear.js @@ -0,0 +1,15 @@ +import ListCache from './_ListCache.js'; + +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; + this.size = 0; +} + +export default stackClear; diff --git a/lib/lodash/_stackDelete.js b/lib/lodash/_stackDelete.js new file mode 100644 index 0000000..c3df897 --- /dev/null +++ b/lib/lodash/_stackDelete.js @@ -0,0 +1,18 @@ +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; +} + +export default stackDelete; diff --git a/lib/lodash/_stackGet.js b/lib/lodash/_stackGet.js new file mode 100644 index 0000000..139b9ac --- /dev/null +++ b/lib/lodash/_stackGet.js @@ -0,0 +1,14 @@ +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} + +export default stackGet; diff --git a/lib/lodash/_stackHas.js b/lib/lodash/_stackHas.js new file mode 100644 index 0000000..bc25f5a --- /dev/null +++ b/lib/lodash/_stackHas.js @@ -0,0 +1,14 @@ +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} + +export default stackHas; diff --git a/lib/lodash/_stackSet.js b/lib/lodash/_stackSet.js new file mode 100644 index 0000000..a85af6c --- /dev/null +++ b/lib/lodash/_stackSet.js @@ -0,0 +1,34 @@ +import ListCache from './_ListCache.js'; +import Map from './_Map.js'; +import MapCache from './_MapCache.js'; + +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; +} + +export default stackSet; diff --git a/lib/lodash/_toSource.js b/lib/lodash/_toSource.js new file mode 100644 index 0000000..2696f7a --- /dev/null +++ b/lib/lodash/_toSource.js @@ -0,0 +1,26 @@ +/** Used for built-in method references. */ +var funcProto = Function.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +export default toSource; diff --git a/lib/lodash/array.default.js b/lib/lodash/array.default.js new file mode 100644 index 0000000..9fa851b --- /dev/null +++ b/lib/lodash/array.default.js @@ -0,0 +1,5 @@ +import flattenDeep from './flattenDeep.js'; + +export default { + flattenDeep +}; diff --git a/lib/lodash/array.js b/lib/lodash/array.js new file mode 100644 index 0000000..5d1c67c --- /dev/null +++ b/lib/lodash/array.js @@ -0,0 +1,2 @@ +export { default as flattenDeep } from './flattenDeep.js'; +export { default } from './array.default.js'; diff --git a/lib/lodash/cloneDeep.js b/lib/lodash/cloneDeep.js new file mode 100644 index 0000000..6c6932b --- /dev/null +++ b/lib/lodash/cloneDeep.js @@ -0,0 +1,37 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +import baseClone from './_baseClone.js'; + +/** Used to compose bitmasks for cloning. */ +var CLONE_DEEP_FLAG = 1, + CLONE_SYMBOLS_FLAG = 4; + +/** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ +function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); +} + +export default cloneDeep; diff --git a/lib/lodash/constant.js b/lib/lodash/constant.js new file mode 100644 index 0000000..c8dac98 --- /dev/null +++ b/lib/lodash/constant.js @@ -0,0 +1,26 @@ +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +export default constant; diff --git a/lib/lodash/eq.js b/lib/lodash/eq.js new file mode 100644 index 0000000..c3206c6 --- /dev/null +++ b/lib/lodash/eq.js @@ -0,0 +1,37 @@ +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +export default eq; diff --git a/lib/lodash/flattenDeep.js b/lib/lodash/flattenDeep.js new file mode 100644 index 0000000..88f9e0f --- /dev/null +++ b/lib/lodash/flattenDeep.js @@ -0,0 +1,33 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +import baseFlatten from './_baseFlatten.js'; + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; + +/** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ +function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; +} + +export default flattenDeep; diff --git a/lib/lodash/identity.js b/lib/lodash/identity.js new file mode 100644 index 0000000..ed074d8 --- /dev/null +++ b/lib/lodash/identity.js @@ -0,0 +1,21 @@ +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +export default identity; diff --git a/lib/lodash/index.js b/lib/lodash/index.js new file mode 100644 index 0000000..2a3d7c2 --- /dev/null +++ b/lib/lodash/index.js @@ -0,0 +1,4 @@ +export {default as isLength} from './isLength.js'; +export {default as flattenDeep} from './flattenDeep.js'; +export {default as cloneDeep} from './cloneDeep.js'; +export {default as merge} from './merge.js'; diff --git a/lib/lodash/isArguments.js b/lib/lodash/isArguments.js new file mode 100644 index 0000000..6c49fe5 --- /dev/null +++ b/lib/lodash/isArguments.js @@ -0,0 +1,36 @@ +import baseIsArguments from './_baseIsArguments.js'; +import isObjectLike from './isObjectLike.js'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +export default isArguments; diff --git a/lib/lodash/isArray.js b/lib/lodash/isArray.js new file mode 100644 index 0000000..5643c19 --- /dev/null +++ b/lib/lodash/isArray.js @@ -0,0 +1,26 @@ +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +export default isArray; diff --git a/lib/lodash/isArrayLike.js b/lib/lodash/isArrayLike.js new file mode 100644 index 0000000..f763abd --- /dev/null +++ b/lib/lodash/isArrayLike.js @@ -0,0 +1,33 @@ +import isFunction from './isFunction.js'; +import isLength from './isLength.js'; + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +export default isArrayLike; diff --git a/lib/lodash/isArrayLikeObject.js b/lib/lodash/isArrayLikeObject.js new file mode 100644 index 0000000..0332da4 --- /dev/null +++ b/lib/lodash/isArrayLikeObject.js @@ -0,0 +1,33 @@ +import isArrayLike from './isArrayLike.js'; +import isObjectLike from './isObjectLike.js'; + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); +} + +export default isArrayLikeObject; diff --git a/lib/lodash/isBuffer.js b/lib/lodash/isBuffer.js new file mode 100644 index 0000000..d7ba078 --- /dev/null +++ b/lib/lodash/isBuffer.js @@ -0,0 +1,38 @@ +import root from './_root.js'; +import stubFalse from './stubFalse.js'; + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +export default isBuffer; diff --git a/lib/lodash/isFunction.js b/lib/lodash/isFunction.js new file mode 100644 index 0000000..57c133d --- /dev/null +++ b/lib/lodash/isFunction.js @@ -0,0 +1,37 @@ +import baseGetTag from './_baseGetTag.js'; +import isObject from './isObject.js'; + +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +export default isFunction; diff --git a/lib/lodash/isLength.js b/lib/lodash/isLength.js new file mode 100644 index 0000000..b4bf1d5 --- /dev/null +++ b/lib/lodash/isLength.js @@ -0,0 +1,44 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +export default isLength; diff --git a/lib/lodash/isMap.js b/lib/lodash/isMap.js new file mode 100644 index 0000000..d867dfa --- /dev/null +++ b/lib/lodash/isMap.js @@ -0,0 +1,27 @@ +import baseIsMap from './_baseIsMap.js'; +import baseUnary from './_baseUnary.js'; +import nodeUtil from './_nodeUtil.js'; + +/* Node.js helper references. */ +var nodeIsMap = nodeUtil && nodeUtil.isMap; + +/** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ +var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + +export default isMap; diff --git a/lib/lodash/isObject.js b/lib/lodash/isObject.js new file mode 100644 index 0000000..ddfebd5 --- /dev/null +++ b/lib/lodash/isObject.js @@ -0,0 +1,31 @@ +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +export default isObject; diff --git a/lib/lodash/isObjectLike.js b/lib/lodash/isObjectLike.js new file mode 100644 index 0000000..0e931b1 --- /dev/null +++ b/lib/lodash/isObjectLike.js @@ -0,0 +1,29 @@ +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +export default isObjectLike; diff --git a/lib/lodash/isPlainObject.js b/lib/lodash/isPlainObject.js new file mode 100644 index 0000000..45ec39f --- /dev/null +++ b/lib/lodash/isPlainObject.js @@ -0,0 +1,62 @@ +import baseGetTag from './_baseGetTag.js'; +import getPrototype from './_getPrototype.js'; +import isObjectLike from './isObjectLike.js'; + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +export default isPlainObject; diff --git a/lib/lodash/isSet.js b/lib/lodash/isSet.js new file mode 100644 index 0000000..78c8198 --- /dev/null +++ b/lib/lodash/isSet.js @@ -0,0 +1,27 @@ +import baseIsSet from './_baseIsSet.js'; +import baseUnary from './_baseUnary.js'; +import nodeUtil from './_nodeUtil.js'; + +/* Node.js helper references. */ +var nodeIsSet = nodeUtil && nodeUtil.isSet; + +/** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ +var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + +export default isSet; diff --git a/lib/lodash/isTypedArray.js b/lib/lodash/isTypedArray.js new file mode 100644 index 0000000..8cffbef --- /dev/null +++ b/lib/lodash/isTypedArray.js @@ -0,0 +1,27 @@ +import baseIsTypedArray from './_baseIsTypedArray.js'; +import baseUnary from './_baseUnary.js'; +import nodeUtil from './_nodeUtil.js'; + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +export default isTypedArray; diff --git a/lib/lodash/keys.js b/lib/lodash/keys.js new file mode 100644 index 0000000..fd7089b --- /dev/null +++ b/lib/lodash/keys.js @@ -0,0 +1,37 @@ +import arrayLikeKeys from './_arrayLikeKeys.js'; +import baseKeys from './_baseKeys.js'; +import isArrayLike from './isArrayLike.js'; + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); +} + +export default keys; diff --git a/lib/lodash/keysIn.js b/lib/lodash/keysIn.js new file mode 100644 index 0000000..a77147a --- /dev/null +++ b/lib/lodash/keysIn.js @@ -0,0 +1,32 @@ +import arrayLikeKeys from './_arrayLikeKeys.js'; +import baseKeysIn from './_baseKeysIn.js'; +import isArrayLike from './isArrayLike.js'; + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +} + +export default keysIn; diff --git a/lib/lodash/lang.default.js b/lib/lodash/lang.default.js new file mode 100644 index 0000000..15c17c6 --- /dev/null +++ b/lib/lodash/lang.default.js @@ -0,0 +1,23 @@ +import cloneDeep from './cloneDeep.js'; +import eq from './eq.js'; +import isArguments from './isArguments.js'; +import isArray from './isArray.js'; +import isArrayLike from './isArrayLike.js'; +import isArrayLikeObject from './isArrayLikeObject.js'; +import isBuffer from './isBuffer.js'; +import isFunction from './isFunction.js'; +import isLength from './isLength.js'; +import isMap from './isMap.js'; +import isObject from './isObject.js'; +import isObjectLike from './isObjectLike.js'; +import isPlainObject from './isPlainObject.js'; +import isSet from './isSet.js'; +import isTypedArray from './isTypedArray.js'; +import toPlainObject from './toPlainObject.js'; + +export default { + cloneDeep, eq, isArguments, isArray, isArrayLike, + isArrayLikeObject, isBuffer, isFunction, isLength, isMap, + isObject, isObjectLike, isPlainObject, isSet, isTypedArray, + toPlainObject +}; diff --git a/lib/lodash/lang.js b/lib/lodash/lang.js new file mode 100644 index 0000000..4817b80 --- /dev/null +++ b/lib/lodash/lang.js @@ -0,0 +1,17 @@ +export { default as cloneDeep } from './cloneDeep.js'; +export { default as eq } from './eq.js'; +export { default as isArguments } from './isArguments.js'; +export { default as isArray } from './isArray.js'; +export { default as isArrayLike } from './isArrayLike.js'; +export { default as isArrayLikeObject } from './isArrayLikeObject.js'; +export { default as isBuffer } from './isBuffer.js'; +export { default as isFunction } from './isFunction.js'; +export { default as isLength } from './isLength.js'; +export { default as isMap } from './isMap.js'; +export { default as isObject } from './isObject.js'; +export { default as isObjectLike } from './isObjectLike.js'; +export { default as isPlainObject } from './isPlainObject.js'; +export { default as isSet } from './isSet.js'; +export { default as isTypedArray } from './isTypedArray.js'; +export { default as toPlainObject } from './toPlainObject.js'; +export { default } from './lang.default.js'; diff --git a/lib/lodash/merge.js b/lib/lodash/merge.js new file mode 100644 index 0000000..f56f822 --- /dev/null +++ b/lib/lodash/merge.js @@ -0,0 +1,47 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +import baseMerge from './_baseMerge.js'; +import createAssigner from './_createAssigner.js'; + +/** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ +var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); +}); + +export default merge; diff --git a/lib/lodash/object.default.js b/lib/lodash/object.default.js new file mode 100644 index 0000000..be234ec --- /dev/null +++ b/lib/lodash/object.default.js @@ -0,0 +1,7 @@ +import keys from './keys.js'; +import keysIn from './keysIn.js'; +import merge from './merge.js'; + +export default { + keys, keysIn, merge +}; diff --git a/lib/lodash/object.js b/lib/lodash/object.js new file mode 100644 index 0000000..372b961 --- /dev/null +++ b/lib/lodash/object.js @@ -0,0 +1,4 @@ +export { default as keys } from './keys.js'; +export { default as keysIn } from './keysIn.js'; +export { default as merge } from './merge.js'; +export { default } from './object.default.js'; diff --git a/lib/lodash/stubArray.js b/lib/lodash/stubArray.js new file mode 100644 index 0000000..b2b5503 --- /dev/null +++ b/lib/lodash/stubArray.js @@ -0,0 +1,23 @@ +/** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ +function stubArray() { + return []; +} + +export default stubArray; diff --git a/lib/lodash/stubFalse.js b/lib/lodash/stubFalse.js new file mode 100644 index 0000000..c569c25 --- /dev/null +++ b/lib/lodash/stubFalse.js @@ -0,0 +1,18 @@ +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +export default stubFalse; diff --git a/lib/lodash/toPlainObject.js b/lib/lodash/toPlainObject.js new file mode 100644 index 0000000..b4e9129 --- /dev/null +++ b/lib/lodash/toPlainObject.js @@ -0,0 +1,32 @@ +import copyObject from './_copyObject.js'; +import keysIn from './keysIn.js'; + +/** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ +function toPlainObject(value) { + return copyObject(value, keysIn(value)); +} + +export default toPlainObject; diff --git a/lib/lodash/util.default.js b/lib/lodash/util.default.js new file mode 100644 index 0000000..60483cb --- /dev/null +++ b/lib/lodash/util.default.js @@ -0,0 +1,8 @@ +import constant from './constant.js'; +import identity from './identity.js'; +import stubArray from './stubArray.js'; +import stubFalse from './stubFalse.js'; + +export default { + constant, identity, stubArray, stubFalse +}; diff --git a/lib/lodash/util.js b/lib/lodash/util.js new file mode 100644 index 0000000..e8e68e0 --- /dev/null +++ b/lib/lodash/util.js @@ -0,0 +1,5 @@ +export { default as constant } from './constant.js'; +export { default as identity } from './identity.js'; +export { default as stubArray } from './stubArray.js'; +export { default as stubFalse } from './stubFalse.js'; +export { default } from './util.default.js'; From 4183d202f46a7e862da3baabb3353a5106d95134 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 20 Aug 2023 16:41:23 -0500 Subject: [PATCH 02/13] move to esm --- .eslintrc.js | 5 +- index.js | 40 +++++++------- lib/Circular.js | 5 +- lib/Indenter.js | 5 +- lib/Registry.js | 5 +- lib/compare.js | 24 +++----- lib/complexValues/arguments.js | 21 +++---- lib/complexValues/arrayBuffer.js | 18 +++--- lib/complexValues/boxed.js | 22 +++----- lib/complexValues/dataView.js | 18 +++--- lib/complexValues/date.js | 28 ++++------ lib/complexValues/error.js | 30 ++++------ lib/complexValues/function.js | 31 ++++------- lib/complexValues/global.js | 25 ++++----- lib/complexValues/map.js | 23 +++----- lib/complexValues/object.js | 44 ++++++--------- lib/complexValues/promise.js | 23 +++----- lib/complexValues/regexp.js | 24 +++----- lib/complexValues/set.js | 23 +++----- lib/complexValues/typedArray.js | 52 +++++++---------- lib/constants.js | 17 ++---- lib/describe.js | 65 +++++++++++----------- lib/diff.js | 32 ++++------- lib/encoder.js | 22 +++----- lib/format.js | 18 +++--- lib/formatUtils.js | 16 ++---- lib/getCtor.js | 12 ++-- lib/getObjectKeys.js | 7 +-- lib/getStringTag.js | 21 +++---- lib/hasLength.js | 11 +--- lib/isEnumerable.js | 5 +- lib/lineBuilder.js | 10 ++-- lib/metaDescriptors/item.js | 41 ++++++-------- lib/metaDescriptors/mapEntry.js | 29 ++++------ lib/metaDescriptors/pointer.js | 18 +++--- lib/metaDescriptors/property.js | 41 ++++++-------- lib/metaDescriptors/stats.js | 50 +++++++---------- lib/pluginRegistry.js | 42 ++++++-------- lib/primitiveValues/bigInt.js | 25 ++++----- lib/primitiveValues/boolean.js | 25 ++++----- lib/primitiveValues/null.js | 25 ++++----- lib/primitiveValues/number.js | 25 ++++----- lib/primitiveValues/string.js | 30 ++++------ lib/primitiveValues/symbol.js | 30 ++++------ lib/primitiveValues/undefined.js | 25 ++++----- lib/recursorUtils.js | 26 +++------ lib/serialize.js | 80 +++++++++++++-------------- lib/shouldCompareDeep.js | 12 +--- lib/symbolProperties.js | 22 +++----- lib/themeUtils.js | 20 ++----- package.json | 27 ++++++--- test/_instrumentedTheme.js | 10 ++-- test/compare.js | 5 +- test/diff.js | 8 +-- test/fixtures/customErrorPlugin.js | 11 ++-- test/fixtures/pointerSerialization.js | 18 ++---- test/format.js | 13 ++--- test/lodash-isequal-comparison.js | 6 +- test/max-depth.js | 4 +- test/odd-properties.js | 4 +- test/pluginRegistry.js | 8 ++- test/serialization-fixtures.js | 6 +- test/serialize-and-encode.js | 8 +-- 63 files changed, 559 insertions(+), 837 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index a9517f5..2abd045 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,5 @@ -'use strict' - -module.exports = { +export default { + sourceType: 'module', plugins: ['@novemberborn/as-i-preach'], extends: ['plugin:@novemberborn/as-i-preach/nodejs'], overrides: [ diff --git a/index.js b/index.js index c6ef57e..101ac91 100644 --- a/index.js +++ b/index.js @@ -1,21 +1,23 @@ -'use strict' +import {compare, compareDescriptors} from './lib/compare.js' +import describe from './lib/describe.js' +import {diff, diffDescriptors} from './lib/diff.js' +import {format, formatDescriptor} from './lib/format.js' +import {serialize, deserialize} from './lib/serialize.js' -const compare = require('./lib/compare') -const describe = require('./lib/describe') -const diff = require('./lib/diff') -const format = require('./lib/format') -const serialize = require('./lib/serialize') +export {compare, compareDescriptors} from './lib/compare.js' +export {default as describe} from './lib/describe.js' +export {diff, diffDescriptors} from './lib/diff.js' +export {format, formatDescriptor} from './lib/format.js' +export {serialize, deserialize} from './lib/serialize.js' -exports.compare = compare.compare -exports.compareDescriptors = compare.compareDescriptors - -exports.describe = describe - -exports.diff = diff.diff -exports.diffDescriptors = diff.diffDescriptors - -exports.format = format.format -exports.formatDescriptor = format.formatDescriptor - -exports.serialize = serialize.serialize -exports.deserialize = serialize.deserialize +export default { + compare, + compareDescriptors, + describe, + diff, + diffDescriptors, + format, + formatDescriptor, + serialize, + deserialize, +} diff --git a/lib/Circular.js b/lib/Circular.js index c5c0202..68737ec 100644 --- a/lib/Circular.js +++ b/lib/Circular.js @@ -1,6 +1,4 @@ -'use strict' - -class Circular { +export default class Circular { constructor () { this.stack = new Map() } @@ -32,4 +30,3 @@ class Circular { : 0 } } -module.exports = Circular diff --git a/lib/Indenter.js b/lib/Indenter.js index deeca84..937119a 100644 --- a/lib/Indenter.js +++ b/lib/Indenter.js @@ -1,6 +1,4 @@ -'use strict' - -class Indenter { +export default class Indenter { constructor (level, step) { this.level = level this.step = step @@ -19,4 +17,3 @@ class Indenter { return this.value } } -module.exports = Indenter diff --git a/lib/Registry.js b/lib/Registry.js index 60d5f54..72997dc 100644 --- a/lib/Registry.js +++ b/lib/Registry.js @@ -1,6 +1,4 @@ -'use strict' - -class Registry { +export default class Registry { constructor () { this.counter = 0 this.map = new WeakMap() @@ -21,4 +19,3 @@ class Registry { return pointer } } -module.exports = Registry diff --git a/lib/compare.js b/lib/compare.js index 069b9ed..a780df1 100644 --- a/lib/compare.js +++ b/lib/compare.js @@ -1,15 +1,9 @@ -'use strict' - -const Circular = require('./Circular') -const constants = require('./constants') -const describe = require('./describe') -const recursorUtils = require('./recursorUtils') -const shouldCompareDeep = require('./shouldCompareDeep') -const symbolProperties = require('./symbolProperties') - -const AMBIGUOUS = constants.AMBIGUOUS -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL +import Circular from './Circular.js' +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from './constants.js' +import describe from './describe.js' +import * as recursorUtils from './recursorUtils.js' +import shouldCompareDeep from './shouldCompareDeep.js' +import * as symbolProperties from './symbolProperties.js' function shortcircuitPrimitive (value) { if (value === null || value === undefined || value === true || value === false) return true @@ -22,7 +16,7 @@ function shortcircuitPrimitive (value) { return false } -function compareDescriptors (lhs, rhs) { +export function compareDescriptors (lhs, rhs) { const lhsCircular = new Circular() const rhsCircular = new Circular() @@ -87,9 +81,8 @@ function compareDescriptors (lhs, rhs) { return true } -exports.compareDescriptors = compareDescriptors -function compare (actual, expected, options) { +export function compare (actual, expected, options) { if (Object.is(actual, expected)) return { pass: true } // Primitive values should be the same, so if actual or expected is primitive // then the values will never compare. @@ -100,4 +93,3 @@ function compare (actual, expected, options) { const pass = compareDescriptors(actual, expected) return { actual, expected, pass } } -exports.compare = compare diff --git a/lib/complexValues/arguments.js b/lib/complexValues/arguments.js index f7905ba..2627e5c 100644 --- a/lib/complexValues/arguments.js +++ b/lib/complexValues/arguments.js @@ -1,27 +1,19 @@ -'use strict' +import { AMBIGUOUS, UNEQUAL } from '../constants.js' +import * as object from './object.js' -const constants = require('../constants') -const object = require('./object') - -const AMBIGUOUS = constants.AMBIGUOUS -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { return new DescribedArgumentsValue(Object.assign({ // Treat as an array, to allow comparisons with arrays isArray: true, isList: true, }, props, { ctor: 'Arguments' })) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedArgumentsValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('ArgumentsValue') -exports.tag = tag +export const tag = Symbol('ArgumentsValue') class ArgumentsValue extends object.ObjectValue { compare (expected) { @@ -33,8 +25,9 @@ class ArgumentsValue extends object.ObjectValue { return super.compare(expected) } + + tag = tag } -Object.defineProperty(ArgumentsValue.prototype, 'tag', { value: tag }) const DescribedArgumentsValue = object.DescribedMixin(ArgumentsValue) diff --git a/lib/complexValues/arrayBuffer.js b/lib/complexValues/arrayBuffer.js index 517eeac..502527e 100644 --- a/lib/complexValues/arrayBuffer.js +++ b/lib/complexValues/arrayBuffer.js @@ -1,8 +1,6 @@ -'use strict' +import * as typedArray from './typedArray.js' -const typedArray = require('./typedArray') - -function describe (props) { +export function describe (props) { return new DescribedArrayBufferValue(Object.assign({ buffer: Buffer.from(props.value), // Set isArray and isList so the property recursor excludes the byte accessors @@ -10,20 +8,18 @@ function describe (props) { isList: true, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedArrayBufferValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('ArrayBufferValue') -exports.tag = tag +export const tag = Symbol('ArrayBufferValue') // ArrayBuffers can be represented as regular Buffers, allowing them to be // treated as TypedArrays for the purposes of this package. -class ArrayBufferValue extends typedArray.TypedArrayValue {} -Object.defineProperty(ArrayBufferValue.prototype, 'tag', { value: tag }) +class ArrayBufferValue extends typedArray.TypedArrayValue { + tag = tag +} const DescribedArrayBufferValue = typedArray.DescribedMixin(ArrayBufferValue) const DeserializedArrayBufferValue = typedArray.DeserializedMixin(ArrayBufferValue) diff --git a/lib/complexValues/boxed.js b/lib/complexValues/boxed.js index 94236ac..e468c55 100644 --- a/lib/complexValues/boxed.js +++ b/lib/complexValues/boxed.js @@ -1,24 +1,20 @@ -'use strict' +import {tag as stringPrimitive} from '../primitiveValues/string.js' +import * as recursorUtils from '../recursorUtils.js' +import * as object from './object.js' -const stringPrimitive = require('../primitiveValues/string').tag -const recursorUtils = require('../recursorUtils') -const object = require('./object') - -function describe (props) { +export function describe (props) { return new DescribedBoxedValue(props) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedBoxedValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('BoxedValue') -exports.tag = tag +export const tag = Symbol('BoxedValue') -class BoxedValue extends object.ObjectValue {} -Object.defineProperty(BoxedValue.prototype, 'tag', { value: tag }) +class BoxedValue extends object.ObjectValue { + tag = tag +} class DescribedBoxedValue extends object.DescribedMixin(BoxedValue) { constructor (props) { diff --git a/lib/complexValues/dataView.js b/lib/complexValues/dataView.js index 4517b78..3f929ee 100644 --- a/lib/complexValues/dataView.js +++ b/lib/complexValues/dataView.js @@ -1,8 +1,6 @@ -'use strict' +import * as typedArray from './typedArray.js' -const typedArray = require('./typedArray') - -function describe (props) { +export function describe (props) { return new DescribedDataViewValue(Object.assign({ buffer: typedArray.getBuffer(props.value), // Set isArray and isList so the property recursor excludes the byte accessors @@ -10,20 +8,18 @@ function describe (props) { isList: true, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedDataViewValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('DataViewValue') -exports.tag = tag +export const tag = Symbol('DataViewValue') // DataViews can be represented as regular Buffers, allowing them to be treated // as TypedArrays for the purposes of this package. -class DataViewValue extends typedArray.TypedArrayValue {} -Object.defineProperty(DataViewValue.prototype, 'tag', { value: tag }) +class DataViewValue extends typedArray.TypedArrayValue { + tag = tag +} const DescribedDataViewValue = typedArray.DescribedMixin(DataViewValue) const DeserializedDataViewValue = typedArray.DeserializedMixin(DataViewValue) diff --git a/lib/complexValues/date.js b/lib/complexValues/date.js index baace87..9a10a53 100644 --- a/lib/complexValues/date.js +++ b/lib/complexValues/date.js @@ -1,29 +1,20 @@ -'use strict' +import dateTime from 'date-time' +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' +import * as object from './object.js' -const dateTime = require('date-time') - -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') -const object = require('./object') - -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { const date = props.value const invalid = isNaN(date.valueOf()) return new DescribedDateValue(Object.assign({}, props, { invalid })) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedDateValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('DateValue') -exports.tag = tag +export const tag = Symbol('DateValue') function formatDate (date) { // Always format in UTC. The local timezone shouldn't be used since it's most @@ -75,8 +66,9 @@ class DateValue extends object.ObjectValue { const iso = this.invalid ? null : this.value.toISOString() return [this.invalid, iso, super.serialize()] } + + tag = tag } -Object.defineProperty(DateValue.prototype, 'tag', { value: tag }) const DescribedDateValue = object.DescribedMixin(DateValue) diff --git a/lib/complexValues/error.js b/lib/complexValues/error.js index bc96e7e..f6ff2c3 100644 --- a/lib/complexValues/error.js +++ b/lib/complexValues/error.js @@ -1,15 +1,11 @@ -'use strict' - -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const isEnumerable = require('../isEnumerable') -const lineBuilder = require('../lineBuilder') -const NOOP_RECURSOR = require('../recursorUtils').NOOP_RECURSOR -const object = require('./object') - -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +import { UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import isEnumerable from '../isEnumerable.js' +import lineBuilder from '../lineBuilder.js' +import { NOOP_RECURSOR } from '../recursorUtils.js' +import * as object from './object.js' + +export function describe (props) { const error = props.value return new DescribedErrorValue(Object.assign({ nameIsEnumerable: isEnumerable(error, 'name'), @@ -18,15 +14,12 @@ function describe (props) { message: error.message, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedErrorValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('ErrorValue') -exports.tag = tag +export const tag = Symbol('ErrorValue') class ErrorValue extends object.ObjectValue { constructor (props) { @@ -72,8 +65,9 @@ class ErrorValue extends object.ObjectValue { serialize () { return [this.name, super.serialize()] } + + tag = tag } -Object.defineProperty(ErrorValue.prototype, 'tag', { value: tag }) class DescribedErrorValue extends object.DescribedMixin(ErrorValue) { constructor (props) { diff --git a/lib/complexValues/function.js b/lib/complexValues/function.js index 28063fd..690d948 100644 --- a/lib/complexValues/function.js +++ b/lib/complexValues/function.js @@ -1,31 +1,23 @@ -'use strict' - -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const isEnumerable = require('../isEnumerable') -const lineBuilder = require('../lineBuilder') -const NOOP_RECURSOR = require('../recursorUtils').NOOP_RECURSOR -const object = require('./object') - -const UNEQUAL = constants.UNEQUAL -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL - -function describe (props) { +import { UNEQUAL, SHALLOW_EQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import isEnumerable from '../isEnumerable.js' +import lineBuilder from '../lineBuilder.js' +import { NOOP_RECURSOR } from '../recursorUtils.js' +import * as object from './object.js' + +export function describe (props) { const fn = props.value return new DescribedFunctionValue(Object.assign({ nameIsEnumerable: isEnumerable(fn, 'name'), name: typeof fn.name === 'string' ? fn.name : null, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedFunctionValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('FunctionValue') -exports.tag = tag +export const tag = Symbol('FunctionValue') class FunctionValue extends object.ObjectValue { constructor (props) { @@ -52,8 +44,9 @@ class FunctionValue extends object.ObjectValue { }, }) } + + tag = tag } -Object.defineProperty(FunctionValue.prototype, 'tag', { value: tag }) class DescribedFunctionValue extends object.DescribedMixin(FunctionValue) { constructor (props) { diff --git a/lib/complexValues/global.js b/lib/complexValues/global.js index 6acd66d..25b9c5b 100644 --- a/lib/complexValues/global.js +++ b/lib/complexValues/global.js @@ -1,21 +1,14 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe () { +export function describe () { return new GlobalValue() } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('GlobalValue') -exports.tag = tag +export const tag = Symbol('GlobalValue') class GlobalValue { compare (expected) { @@ -28,6 +21,8 @@ class GlobalValue { return lineBuilder.single( formatUtils.wrap(theme.global, 'Global') + ' ' + theme.object.openBracket + theme.object.closeBracket) } + + isComplex = true + + tag = tag } -Object.defineProperty(GlobalValue.prototype, 'isComplex', { value: true }) -Object.defineProperty(GlobalValue.prototype, 'tag', { value: tag }) diff --git a/lib/complexValues/map.js b/lib/complexValues/map.js index 5015a0a..c158324 100644 --- a/lib/complexValues/map.js +++ b/lib/complexValues/map.js @@ -1,26 +1,18 @@ -'use strict' +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' +import * as recursorUtils from '../recursorUtils.js' +import * as object from './object.js' -const constants = require('../constants') -const recursorUtils = require('../recursorUtils') -const object = require('./object') - -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { return new DescribedMapValue(Object.assign({ size: props.value.size, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedMapValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('MapValue') -exports.tag = tag +export const tag = Symbol('MapValue') class MapValue extends object.ObjectValue { constructor (props) { @@ -45,8 +37,9 @@ class MapValue extends object.ObjectValue { serialize () { return [this.size, super.serialize()] } + + tag = tag } -Object.defineProperty(MapValue.prototype, 'tag', { value: tag }) class DescribedMapValue extends object.DescribedMixin(MapValue) { createIterableRecursor () { diff --git a/lib/complexValues/object.js b/lib/complexValues/object.js index d4e904c..ec214c7 100644 --- a/lib/complexValues/object.js +++ b/lib/complexValues/object.js @@ -1,17 +1,11 @@ -'use strict' - -const constants = require('../constants') -const ObjectFormatter = require('../formatUtils').ObjectFormatter -const getObjectKeys = require('../getObjectKeys') -const hasLength = require('../hasLength') -const stats = require('../metaDescriptors/stats') -const recursorUtils = require('../recursorUtils') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +import { DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL } from '../constants.js' +import { ObjectFormatter } from '../formatUtils.js' +import getObjectKeys from '../getObjectKeys.js' +import hasLength from '../hasLength.js' +import * as stats from '../metaDescriptors/stats.js' +import * as recursorUtils from '../recursorUtils.js' + +export function describe (props) { const isArray = props.stringTag === 'Array' const object = props.value return new DescribedObjectValue(Object.assign({ @@ -20,17 +14,14 @@ function describe (props) { isList: isArray || hasLength(object), }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedObjectValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('ObjectValue') -exports.tag = tag +export const tag = Symbol('ObjectValue') -class ObjectValue { +export class ObjectValue { constructor (props) { this.ctor = props.ctor this.pointer = props.pointer @@ -61,15 +52,16 @@ class ObjectValue { this.isArray, this.isIterable, this.isList, ] } + + isComplex = true + + tag = tag } -Object.defineProperty(ObjectValue.prototype, 'isComplex', { value: true }) -Object.defineProperty(ObjectValue.prototype, 'tag', { value: tag }) -exports.ObjectValue = ObjectValue const DescribedObjectValue = DescribedMixin(ObjectValue) const DeserializedObjectValue = DeserializedMixin(ObjectValue) -function DescribedMixin (base) { +export function DescribedMixin (base) { return class extends base { constructor (props) { super(props) @@ -220,9 +212,8 @@ function DescribedMixin (base) { } } } -exports.DescribedMixin = DescribedMixin -function DeserializedMixin (base) { +export function DeserializedMixin (base) { return class extends base { constructor (state, recursor) { super({ @@ -251,4 +242,3 @@ function DeserializedMixin (base) { } } } -exports.DeserializedMixin = DeserializedMixin diff --git a/lib/complexValues/promise.js b/lib/complexValues/promise.js index 823d453..291b414 100644 --- a/lib/complexValues/promise.js +++ b/lib/complexValues/promise.js @@ -1,26 +1,19 @@ -'use strict' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js' +import * as object from './object.js' -const constants = require('../constants') -const object = require('./object') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { return new DescribedPromiseValue(props) } -exports.describe = describe -function deserialize (props) { +export function deserialize (props) { return new DeserializedPromiseValue(props) } -exports.deserialize = deserialize -const tag = Symbol('PromiseValue') -exports.tag = tag +export const tag = Symbol('PromiseValue') -class PromiseValue extends object.ObjectValue {} -Object.defineProperty(PromiseValue.prototype, 'tag', { value: tag }) +class PromiseValue extends object.ObjectValue { + tag = tag +} class DescribedPromiseValue extends object.DescribedMixin(PromiseValue) { compare (expected) { diff --git a/lib/complexValues/regexp.js b/lib/complexValues/regexp.js index 2a9355e..2750086 100644 --- a/lib/complexValues/regexp.js +++ b/lib/complexValues/regexp.js @@ -1,28 +1,21 @@ -'use strict' +import { UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' +import * as object from './object.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') -const object = require('./object') - -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { const regexp = props.value return new DescribedRegexpValue(Object.assign({ flags: getSortedFlags(regexp), source: regexp.source, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedRegexpValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('RegexpValue') -exports.tag = tag +export const tag = Symbol('RegexpValue') function getSortedFlags (regexp) { const flags = regexp.flags || String(regexp).slice(regexp.source.length + 2) @@ -76,8 +69,9 @@ class RegexpValue extends object.ObjectValue { serialize () { return [this.flags, this.source, super.serialize()] } + + tag = tag } -Object.defineProperty(RegexpValue.prototype, 'tag', { value: tag }) const DescribedRegexpValue = object.DescribedMixin(RegexpValue) diff --git a/lib/complexValues/set.js b/lib/complexValues/set.js index f5b1199..b9d3e42 100644 --- a/lib/complexValues/set.js +++ b/lib/complexValues/set.js @@ -1,26 +1,18 @@ -'use strict' +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' +import * as recursorUtils from '../recursorUtils.js' +import * as object from './object.js' -const constants = require('../constants') -const recursorUtils = require('../recursorUtils') -const object = require('./object') - -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (props) { +export function describe (props) { return new DescribedSetValue(Object.assign({ size: props.value.size, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedSetValue(state, recursor) } -exports.deserialize = deserialize -const tag = Symbol('SetValue') -exports.tag = tag +export const tag = Symbol('SetValue') class SetValue extends object.ObjectValue { constructor (props) { @@ -45,8 +37,9 @@ class SetValue extends object.ObjectValue { serialize () { return [this.size, super.serialize()] } + + tag = tag } -Object.defineProperty(SetValue.prototype, 'tag', { value: tag }) class DescribedSetValue extends object.DescribedMixin(SetValue) { createIterableRecursor () { diff --git a/lib/complexValues/typedArray.js b/lib/complexValues/typedArray.js index a650123..208842c 100644 --- a/lib/complexValues/typedArray.js +++ b/lib/complexValues/typedArray.js @@ -1,24 +1,18 @@ -'use strict' - -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') -const propertyStatsTag = require('../metaDescriptors/stats').propertyTag -const recursorUtils = require('../recursorUtils') -const object = require('./object') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function getBuffer (value) { +import {DEEP_EQUAL, UNEQUAL} from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' +import {propertyTag as propertyStatsTag} from '../metaDescriptors/stats.js' +import * as recursorUtils from '../recursorUtils.js' +import * as object from './object.js' + +export function getBuffer (value) { const buffer = Buffer.from(value.buffer) return value.byteLength !== value.buffer.byteLength ? buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) : buffer } -exports.getBuffer = getBuffer -function describe (props) { +export function describe (props) { return new DescribedTypedArrayValue(Object.assign({ buffer: getBuffer(props.value), // Set isArray and isList so the property recursor excludes the byte accessors @@ -26,23 +20,18 @@ function describe (props) { isList: true, }, props)) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { return new DeserializedTypedArrayValue(state, recursor) } -exports.deserialize = deserialize -function deserializeBytes (buffer) { +export function deserializeBytes (buffer) { return new Bytes(buffer) } -exports.deserializeBytes = deserializeBytes -const bytesTag = Symbol('Bytes') -exports.bytesTag = bytesTag +export const bytesTag = Symbol('Bytes') -const tag = Symbol('TypedArrayValue') -exports.tag = tag +export const tag = Symbol('TypedArrayValue') class Bytes { constructor (buffer) { @@ -87,10 +76,11 @@ class Bytes { serialize () { return this.buffer } + + tag = bytesTag } -Object.defineProperty(Bytes.prototype, 'tag', { value: bytesTag }) -class TypedArrayValue extends object.ObjectValue { +export class TypedArrayValue extends object.ObjectValue { constructor (props) { super(props) this.buffer = props.buffer @@ -106,11 +96,11 @@ class TypedArrayValue extends object.ObjectValue { }, }) } + + tag = tag } -Object.defineProperty(TypedArrayValue.prototype, 'tag', { value: tag }) -exports.TypedArrayValue = TypedArrayValue -function DescribedMixin (base) { +export function DescribedMixin (base) { return class extends object.DescribedMixin(base) { // The list isn't recursed. Instead a Bytes instance is returned by the main // recursor. @@ -141,11 +131,10 @@ function DescribedMixin (base) { } } } -exports.DescribedMixin = DescribedMixin const DescribedTypedArrayValue = DescribedMixin(TypedArrayValue) -function DeserializedMixin (base) { +export function DeserializedMixin (base) { return class extends object.DeserializedMixin(base) { constructor (state, recursor) { super(state, recursor) @@ -156,6 +145,5 @@ function DeserializedMixin (base) { } } } -exports.DeserializedMixin = DeserializedMixin const DeserializedTypedArrayValue = DeserializedMixin(TypedArrayValue) diff --git a/lib/constants.js b/lib/constants.js index f311eba..2f1a741 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,13 +1,4 @@ -'use strict' - -const AMBIGUOUS = Symbol('AMBIGUOUS') -const DEEP_EQUAL = Symbol('DEEP_EQUAL') -const SHALLOW_EQUAL = Symbol('SHALLOW_EQUAL') -const UNEQUAL = Symbol('UNEQUAL') - -module.exports = { - AMBIGUOUS, - DEEP_EQUAL, - SHALLOW_EQUAL, - UNEQUAL, -} +export const AMBIGUOUS = Symbol('AMBIGUOUS') +export const DEEP_EQUAL = Symbol('DEEP_EQUAL') +export const SHALLOW_EQUAL = Symbol('SHALLOW_EQUAL') +export const UNEQUAL = Symbol('UNEQUAL') diff --git a/lib/describe.js b/lib/describe.js index 944e08e..fe8cdcb 100644 --- a/lib/describe.js +++ b/lib/describe.js @@ -1,35 +1,33 @@ -'use strict' - -const Registry = require('./Registry') -const argumentsValue = require('./complexValues/arguments') -const arrayBufferValue = require('./complexValues/arrayBuffer') -const boxedValue = require('./complexValues/boxed') -const dataViewValue = require('./complexValues/dataView') -const dateValue = require('./complexValues/date') -const errorValue = require('./complexValues/error') -const functionValue = require('./complexValues/function') -const globalValue = require('./complexValues/global') -const mapValue = require('./complexValues/map') -const objectValue = require('./complexValues/object') -const promiseValue = require('./complexValues/promise') -const regexpValue = require('./complexValues/regexp') -const setValue = require('./complexValues/set') -const typedArrayValue = require('./complexValues/typedArray') - -const getCtor = require('./getCtor') -const getStringTag = require('./getStringTag') -const itemDescriptor = require('./metaDescriptors/item') -const mapEntryDescriptor = require('./metaDescriptors/mapEntry') -const propertyDescriptor = require('./metaDescriptors/property') - -const pluginRegistry = require('./pluginRegistry') -const bigIntValue = require('./primitiveValues/bigInt') -const booleanValue = require('./primitiveValues/boolean') -const nullValue = require('./primitiveValues/null') -const numberValue = require('./primitiveValues/number') -const stringValue = require('./primitiveValues/string') -const symbolValue = require('./primitiveValues/symbol') -const undefinedValue = require('./primitiveValues/undefined') +import Registry from './Registry.js' +import * as argumentsValue from './complexValues/arguments.js' +import * as arrayBufferValue from './complexValues/arrayBuffer.js' +import * as boxedValue from './complexValues/boxed.js' +import * as dataViewValue from './complexValues/dataView.js' +import * as dateValue from './complexValues/date.js' +import * as errorValue from './complexValues/error.js' +import * as functionValue from './complexValues/function.js' +import * as globalValue from './complexValues/global.js' +import * as mapValue from './complexValues/map.js' +import * as objectValue from './complexValues/object.js' +import * as promiseValue from './complexValues/promise.js' +import * as regexpValue from './complexValues/regexp.js' +import * as setValue from './complexValues/set.js' +import * as typedArrayValue from './complexValues/typedArray.js' + +import getCtor from './getCtor.js' +import getStringTag from './getStringTag.js' +import * as itemDescriptor from './metaDescriptors/item.js' +import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js' +import * as propertyDescriptor from './metaDescriptors/property.js' + +import * as pluginRegistry from './pluginRegistry.js' +import * as bigIntValue from './primitiveValues/bigInt.js' +import * as booleanValue from './primitiveValues/boolean.js' +import * as nullValue from './primitiveValues/null.js' +import * as numberValue from './primitiveValues/number.js' +import * as stringValue from './primitiveValues/string.js' +import * as symbolValue from './primitiveValues/symbol.js' +import * as undefinedValue from './primitiveValues/undefined.js' const SpecializedComplexes = new Map([ ['Arguments', argumentsValue.describe], @@ -142,7 +140,7 @@ const describeMapEntry = (keyDescriptor, valueDescriptor) => { return mapEntryDescriptor.describe(keyDescriptor, valueDescriptor) } -function describe (value, options) { +export default function describe (value, options) { const primitive = describePrimitive(value) if (primitive !== null) return primitive @@ -168,4 +166,3 @@ function describe (value, options) { return curriedComplex(value) } -module.exports = describe diff --git a/lib/diff.js b/lib/diff.js index 840ac57..94144cf 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -1,19 +1,13 @@ -'use strict' - -const Circular = require('./Circular') -const Indenter = require('./Indenter') -const constants = require('./constants') -const describe = require('./describe') -const lineBuilder = require('./lineBuilder') -const recursorUtils = require('./recursorUtils') -const shouldCompareDeep = require('./shouldCompareDeep') -const symbolProperties = require('./symbolProperties') -const themeUtils = require('./themeUtils') - -const AMBIGUOUS = constants.AMBIGUOUS -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL +import Circular from './Circular.js' +import Indenter from './Indenter.js' +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL} from './constants.js' +import describe from './describe.js' +import lineBuilder from './lineBuilder.js' +import * as recursorUtils from './recursorUtils.js' +import shouldCompareDeep from './shouldCompareDeep.js' +import * as symbolProperties from './symbolProperties.js' +import * as themeUtils from './themeUtils.js' + const NOOP = Symbol('NOOP') const alwaysFormat = () => true @@ -55,7 +49,7 @@ function compareComplexShape (lhs, rhs) { } while (true) } -function diffDescriptors (lhs, rhs, options) { +export function diffDescriptors (lhs, rhs, options) { const theme = themeUtils.normalize(options) const invert = options ? options.invert === true : false @@ -383,9 +377,7 @@ function diffDescriptors (lhs, rhs, options) { return buffer.toString({ diff: true, invert, theme }) } -exports.diffDescriptors = diffDescriptors -function diff (actual, expected, options) { +export function diff (actual, expected, options) { return diffDescriptors(describe(actual, options), describe(expected, options), options) } -exports.diff = diff diff --git a/lib/encoder.js b/lib/encoder.js index d1de5b5..153a437 100644 --- a/lib/encoder.js +++ b/lib/encoder.js @@ -1,6 +1,4 @@ -'use strict' - -const flattenDeep = require('lodash/flattenDeep') +import {flattenDeep} from './lodash/index.js' // Indexes are hexadecimal to make reading the binary output easier. const valueTypes = { @@ -27,8 +25,7 @@ const valueTypes = { descriptor: 0x14, } -const descriptorSymbol = Symbol('descriptor') -exports.descriptorSymbol = descriptorSymbol +export const descriptorSymbol = Symbol('descriptor') function encodeInteger (type, value) { const encoded = Buffer.alloc(type) @@ -184,7 +181,7 @@ function buildBuffer (numberOrArray) { return Buffer.concat(buffers, byteLength) } -function encode (serializerVersion, rootRecord, usedPlugins) { +export function encode (serializerVersion, rootRecord, usedPlugins) { const buffers = [] let byteOffset = 0 @@ -244,9 +241,8 @@ function encode (serializerVersion, rootRecord, usedPlugins) { return Buffer.concat(buffers, byteOffset) } -exports.encode = encode -function decodePlugins (buffer) { +export function decodePlugins (buffer) { const $numPlugins = decodeValue(buffer, 0) let byteOffset = $numPlugins.byteOffset @@ -263,9 +259,8 @@ function decodePlugins (buffer) { return usedPlugins } -exports.decodePlugins = decodePlugins -function decodeRecord (buffer, byteOffset) { +export function decodeRecord (buffer, byteOffset) { const $pluginIndex = decodeValue(buffer, byteOffset) const pluginIndex = $pluginIndex.value byteOffset = $pluginIndex.byteOffset @@ -287,17 +282,14 @@ function decodeRecord (buffer, byteOffset) { const state = decodeValue(buffer, byteOffset).value return { id, pluginIndex, state, pointerAddresses } } -exports.decodeRecord = decodeRecord -function extractVersion (buffer) { +export function extractVersion (buffer) { return buffer.readUInt16LE(0) } -exports.extractVersion = extractVersion -function decode (buffer) { +export function decode (buffer) { const rootOffset = buffer.readUInt32LE(2) const pluginBuffer = buffer.slice(6, rootOffset) const rootRecord = decodeRecord(buffer, rootOffset) return { pluginBuffer, rootRecord } } -exports.decode = decode diff --git a/lib/format.js b/lib/format.js index 47671b5..f5c173b 100644 --- a/lib/format.js +++ b/lib/format.js @@ -1,15 +1,13 @@ -'use strict' - -const Circular = require('./Circular') -const Indenter = require('./Indenter') -const describe = require('./describe') -const lineBuilder = require('./lineBuilder') -const themeUtils = require('./themeUtils') +import Circular from './Circular.js' +import Indenter from './Indenter.js' +import describe from './describe.js' +import lineBuilder from './lineBuilder.js' +import * as themeUtils from './themeUtils.js' const alwaysFormat = () => true const fixedIndent = new Indenter(0, ' ') -function formatDescriptor (subject, options) { +export function formatDescriptor (subject, options) { const theme = themeUtils.normalize(options) if (subject.isPrimitive === true) { const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), fixedIndent) @@ -93,9 +91,7 @@ function formatDescriptor (subject, options) { return buffer.toString({ diff: false }) } -exports.formatDescriptor = formatDescriptor -function format (value, options) { +export function format (value, options) { return formatDescriptor(describe(value, options), options) } -exports.format = format diff --git a/lib/formatUtils.js b/lib/formatUtils.js index 07e8b2c..934ced3 100644 --- a/lib/formatUtils.js +++ b/lib/formatUtils.js @@ -1,13 +1,10 @@ -'use strict' +import lineBuilder from './lineBuilder.js' -const lineBuilder = require('./lineBuilder') - -function wrap (fromTheme, value) { +export function wrap (fromTheme, value) { return fromTheme.open + value + fromTheme.close } -exports.wrap = wrap -function formatCtorAndStringTag (theme, object) { +export function formatCtorAndStringTag (theme, object) { if (!object.ctor) return wrap(theme.object.stringTag, object.stringTag) let retval = wrap(theme.object.ctor, object.ctor) @@ -16,9 +13,8 @@ function formatCtorAndStringTag (theme, object) { } return retval } -exports.formatCtorAndStringTag = formatCtorAndStringTag -class ObjectFormatter { +export class ObjectFormatter { constructor (object, theme, indent) { this.object = object this.theme = theme @@ -92,9 +88,8 @@ class ObjectFormatter { return this } } -exports.ObjectFormatter = ObjectFormatter -class SingleValueFormatter { +export class SingleValueFormatter { constructor (theme, finalizeFn, increaseIndent) { this.theme = theme this.finalizeFn = finalizeFn @@ -120,4 +115,3 @@ class SingleValueFormatter { return this.finalizeFn(lineBuilder.single(this.theme.maxDepth)) } } -exports.SingleValueFormatter = SingleValueFormatter diff --git a/lib/getCtor.js b/lib/getCtor.js index 4bbdfd1..db96604 100644 --- a/lib/getCtor.js +++ b/lib/getCtor.js @@ -1,8 +1,4 @@ -'use strict' - -const hop = Object.prototype.hasOwnProperty - -function getCtor (stringTag, value) { +export default function getCtor (stringTag, value) { if (value.constructor) { const name = value.constructor.name return typeof name === 'string' && name !== '' @@ -18,7 +14,8 @@ function getCtor (stringTag, value) { // from a different realm, e.g.: // // ``` - // require('vm').runInNewContext(` + // import vm from 'node:vm' + // vm.runInNewContext(` // const Foo = function () {} // Foo.prototype.constructor = undefined // return new Foo() @@ -33,11 +30,10 @@ function getCtor (stringTag, value) { // Using `const` prevents Crankshaft optimizations for (var p in value) { // eslint-disable-line no-var - if (!hop.call(value, p)) return null + if (!Object.hasOwn(value, p)) return null } return stringTag } return null } -module.exports = getCtor diff --git a/lib/getObjectKeys.js b/lib/getObjectKeys.js index 4f96f0c..3f88941 100644 --- a/lib/getObjectKeys.js +++ b/lib/getObjectKeys.js @@ -1,8 +1,6 @@ -'use strict' +import isEnumerable from './isEnumerable.js'; -const isEnumerable = require('./isEnumerable') - -function getObjectKeys (obj, excludeListItemAccessorsBelowLength) { +export default function getObjectKeys (obj, excludeListItemAccessorsBelowLength) { const keys = [] let size = 0 @@ -32,4 +30,3 @@ function getObjectKeys (obj, excludeListItemAccessorsBelowLength) { return { keys, size } } -module.exports = getObjectKeys diff --git a/lib/getStringTag.js b/lib/getStringTag.js index 6e9ac2b..24dc6c3 100644 --- a/lib/getStringTag.js +++ b/lib/getStringTag.js @@ -1,5 +1,3 @@ -'use strict' - const ts = Object.prototype.toString function getStringTag (value) { return ts.call(value).slice(8, -1) @@ -17,14 +15,13 @@ const isPromise = value => { } } -if (getStringTag(Promise.resolve()) === 'Promise') { - module.exports = getStringTag -} else { - const getStringTagWithPromiseWorkaround = value => { - const stringTag = getStringTag(value) - return stringTag === 'Object' && isPromise(value) - ? 'Promise' - : stringTag - } - module.exports = getStringTagWithPromiseWorkaround +const getStringTagWithPromiseWorkaround = value => { + const stringTag = getStringTag(value) + return stringTag === 'Object' && isPromise(value) + ? 'Promise' + : stringTag } + +export default getStringTag(Promise.resolve()) === 'Promise' + ? getStringTag + : getStringTagWithPromiseWorkaround diff --git a/lib/hasLength.js b/lib/hasLength.js index be85d4f..dcba308 100644 --- a/lib/hasLength.js +++ b/lib/hasLength.js @@ -1,15 +1,10 @@ -'use strict' +import {isLength} from './lodash/index.js' -const isLength = require('lodash/isLength') - -const hop = Object.prototype.hasOwnProperty - -function hasLength (obj) { +export default function hasLength (obj) { return ( Array.isArray(obj) || - (hop.call(obj, 'length') && + (Object.hasOwn(obj, 'length') && isLength(obj.length) && (obj.length === 0 || '0' in obj)) ) } -module.exports = hasLength diff --git a/lib/isEnumerable.js b/lib/isEnumerable.js index 90c2df1..a2d97d4 100644 --- a/lib/isEnumerable.js +++ b/lib/isEnumerable.js @@ -1,7 +1,4 @@ -'use strict' - -function isEnumerable (obj, key) { +export default function isEnumerable (obj, key) { const desc = Object.getOwnPropertyDescriptor(obj, key) return desc && desc.enumerable } -module.exports = isEnumerable diff --git a/lib/lineBuilder.js b/lib/lineBuilder.js index 3b64bdc..60b51dc 100644 --- a/lib/lineBuilder.js +++ b/lib/lineBuilder.js @@ -1,5 +1,3 @@ -'use strict' - const ACTUAL = Symbol('lineBuilder.gutters.ACTUAL') const EXPECTED = Symbol('lineBuilder.gutters.EXPECTED') @@ -85,8 +83,9 @@ class Line { .append(this) .decompose() } + + isLine = true } -Object.defineProperty(Line.prototype, 'isLine', { value: true }) class Collection { constructor () { @@ -226,8 +225,9 @@ class Collection { return { first, last, remaining } } + + isCollection = true } -Object.defineProperty(Collection.prototype, 'isCollection', { value: true }) function setDefaultGutter (iterable, gutter) { return new Collection() @@ -238,7 +238,7 @@ function setDefaultGutter (iterable, gutter) { })) } -module.exports = { +export default { buffer () { return new Collection() }, diff --git a/lib/metaDescriptors/item.js b/lib/metaDescriptors/item.js index 529e95b..51f0b58 100644 --- a/lib/metaDescriptors/item.js +++ b/lib/metaDescriptors/item.js @@ -1,40 +1,29 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import * as recursorUtils from '../recursorUtils.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const recursorUtils = require('../recursorUtils') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describeComplex (index, value) { +export function describeComplex (index, value) { return new ComplexItem(index, value) } -exports.describeComplex = describeComplex -function deserializeComplex (index, recursor) { +export function deserializeComplex (index, recursor) { const value = recursor() return new ComplexItem(index, value) } -exports.deserializeComplex = deserializeComplex -function describePrimitive (index, value) { +export function describePrimitive (index, value) { return new PrimitiveItem(index, value) } -exports.describePrimitive = describePrimitive -function deserializePrimitive (state) { +export function deserializePrimitive (state) { const index = state[0] const value = state[1] return new PrimitiveItem(index, value) } -exports.deserializePrimitive = deserializePrimitive -const complexTag = Symbol('ComplexItem') -exports.complexTag = complexTag +export const complexTag = Symbol('ComplexItem') -const primitiveTag = Symbol('PrimitiveItem') -exports.primitiveTag = primitiveTag +export const primitiveTag = Symbol('PrimitiveItem') class ComplexItem { constructor (index, value) { @@ -145,9 +134,11 @@ class ComplexItem { serialize () { return this.index } + + isItem = true + + tag = complexTag } -Object.defineProperty(ComplexItem.prototype, 'isItem', { value: true }) -Object.defineProperty(ComplexItem.prototype, 'tag', { value: complexTag }) class PrimitiveItem { constructor (index, value) { @@ -249,6 +240,8 @@ class PrimitiveItem { serialize () { return [this.index, this.value] } + + isItem = true + + tag = primitiveTag } -Object.defineProperty(PrimitiveItem.prototype, 'isItem', { value: true }) -Object.defineProperty(PrimitiveItem.prototype, 'tag', { value: primitiveTag }) diff --git a/lib/metaDescriptors/mapEntry.js b/lib/metaDescriptors/mapEntry.js index 2f9031e..4166cf9 100644 --- a/lib/metaDescriptors/mapEntry.js +++ b/lib/metaDescriptors/mapEntry.js @@ -1,23 +1,16 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL } from '../constants.js' +import lineBuilder from '../lineBuilder.js' +import * as recursorUtils from '../recursorUtils.js' +import * as themeUtils from '../themeUtils.js' -const constants = require('../constants') -const lineBuilder = require('../lineBuilder') -const recursorUtils = require('../recursorUtils') -const themeUtils = require('../themeUtils') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL - -function describe (keyDescriptor, valueDescriptor) { +export function describe (keyDescriptor, valueDescriptor) { const keyIsPrimitive = keyDescriptor.isPrimitive === true const valueIsPrimitive = valueDescriptor.isPrimitive === true return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) } -exports.describe = describe -function deserialize (state, recursor) { +export function deserialize (state, recursor) { const keyIsPrimitive = state[0] const valueIsPrimitive = state[1] const keyDescriptor = recursor() @@ -25,10 +18,8 @@ function deserialize (state, recursor) { return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) } -exports.deserialize = deserialize -const tag = Symbol('MapEntry') -exports.tag = tag +export const tag = Symbol('MapEntry') function mergeWithKey (theme, key, values) { const lines = lineBuilder.buffer() @@ -218,6 +209,8 @@ class MapEntry { serialize () { return [this.keyIsPrimitive, this.valueIsPrimitive] } + + isMapEntry = true + + tag = tag } -Object.defineProperty(MapEntry.prototype, 'isMapEntry', { value: true }) -Object.defineProperty(MapEntry.prototype, 'tag', { value: tag }) diff --git a/lib/metaDescriptors/pointer.js b/lib/metaDescriptors/pointer.js index f569d28..28841a9 100644 --- a/lib/metaDescriptors/pointer.js +++ b/lib/metaDescriptors/pointer.js @@ -1,16 +1,12 @@ -'use strict' +import { UNEQUAL } from '../constants.js' -const UNEQUAL = require('../constants').UNEQUAL - -function describe (index) { +export function describe (index) { return new Pointer(index) } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('Pointer') -exports.tag = tag +export const tag = Symbol('Pointer') class Pointer { constructor (index) { @@ -26,6 +22,8 @@ class Pointer { serialize () { return this.index } + + isPrimitive = true + + tag = tag } -Object.defineProperty(Pointer.prototype, 'isPointer', { value: true }) -Object.defineProperty(Pointer.prototype, 'tag', { value: tag }) diff --git a/lib/metaDescriptors/property.js b/lib/metaDescriptors/property.js index 77a453b..3537c68 100644 --- a/lib/metaDescriptors/property.js +++ b/lib/metaDescriptors/property.js @@ -1,42 +1,30 @@ -'use strict' +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import {tag as symbolPrimitive} from '../primitiveValues/symbol.js' +import * as recursorUtils from '../recursorUtils.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const symbolPrimitive = require('../primitiveValues/symbol').tag -const recursorUtils = require('../recursorUtils') - -const AMBIGUOUS = constants.AMBIGUOUS -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describeComplex (key, value) { +export function describeComplex (key, value) { return new ComplexProperty(key, value) } -exports.describeComplex = describeComplex -function deserializeComplex (key, recursor) { +export function deserializeComplex (key, recursor) { const value = recursor() return new ComplexProperty(key, value) } -exports.deserializeComplex = deserializeComplex -function describePrimitive (key, value) { +export function describePrimitive (key, value) { return new PrimitiveProperty(key, value) } -exports.describePrimitive = describePrimitive -function deserializePrimitive (state) { +export function deserializePrimitive (state) { const key = state[0] const value = state[1] return new PrimitiveProperty(key, value) } -exports.deserializePrimitive = deserializePrimitive -const complexTag = Symbol('ComplexProperty') -exports.complexTag = complexTag +export const complexTag = Symbol('ComplexProperty') -const primitiveTag = Symbol('PrimitiveProperty') -exports.primitiveTag = primitiveTag +export const primitiveTag = Symbol('PrimitiveProperty') class Property { constructor (key) { @@ -83,8 +71,9 @@ class Property { expected = rhsFork.shared() } while (true) } + + isProperty = true } -Object.defineProperty(Property.prototype, 'isProperty', { value: true }) class ComplexProperty extends Property { constructor (key, value) { @@ -123,8 +112,9 @@ class ComplexProperty extends Property { serialize () { return this.key } + + tag = complexTag } -Object.defineProperty(ComplexProperty.prototype, 'tag', { value: complexTag }) class PrimitiveProperty extends Property { constructor (key, value) { @@ -186,5 +176,6 @@ class PrimitiveProperty extends Property { serialize () { return [this.key, this.value] } + + tag = primitiveTag } -Object.defineProperty(PrimitiveProperty.prototype, 'tag', { value: primitiveTag }) diff --git a/lib/metaDescriptors/stats.js b/lib/metaDescriptors/stats.js index 45e30ad..20cafa0 100644 --- a/lib/metaDescriptors/stats.js +++ b/lib/metaDescriptors/stats.js @@ -1,50 +1,36 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import lineBuilder from '../lineBuilder.js' +import * as recursorUtils from '../recursorUtils.js' -const constants = require('../constants') -const lineBuilder = require('../lineBuilder') -const recursorUtils = require('../recursorUtils') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describeIterableRecursor (recursor) { +export function describeIterableRecursor (recursor) { return new IterableStats(recursor.size) } -exports.describeIterableRecursor = describeIterableRecursor -function describeListRecursor (recursor) { +export function describeListRecursor (recursor) { return new ListStats(recursor.size) } -exports.describeListRecursor = describeListRecursor -function describePropertyRecursor (recursor) { +export function describePropertyRecursor (recursor) { return new PropertyStats(recursor.size) } -exports.describePropertyRecursor = describePropertyRecursor -function deserializeIterableStats (size) { +export function deserializeIterableStats (size) { return new IterableStats(size) } -exports.deserializeIterableStats = deserializeIterableStats -function deserializeListStats (size) { +export function deserializeListStats (size) { return new ListStats(size) } -exports.deserializeListStats = deserializeListStats -function deserializePropertyStats (size) { +export function deserializePropertyStats (size) { return new PropertyStats(size) } -exports.deserializePropertyStats = deserializePropertyStats -const iterableTag = Symbol('IterableStats') -exports.iterableTag = iterableTag +export const iterableTag = Symbol('IterableStats') -const listTag = Symbol('ListStats') -exports.listTag = listTag +export const listTag = Symbol('ListStats') -const propertyTag = Symbol('PropertyStats') -exports.propertyTag = propertyTag +export const propertyTag = Symbol('PropertyStats') class Stats { constructor (size) { @@ -105,8 +91,9 @@ class Stats { serialize () { return this.size } + + isStats = true } -Object.defineProperty(Stats.prototype, 'isStats', { value: true }) class IterableStats extends Stats { compare (expected) { @@ -114,8 +101,9 @@ class IterableStats extends Stats { ? DEEP_EQUAL : UNEQUAL } + + tag = iterableTag } -Object.defineProperty(IterableStats.prototype, 'tag', { value: iterableTag }) class ListStats extends Stats { compare (expected) { @@ -123,8 +111,9 @@ class ListStats extends Stats { ? DEEP_EQUAL : UNEQUAL } + + tag = listTag } -Object.defineProperty(ListStats.prototype, 'tag', { value: listTag }) class PropertyStats extends Stats { compare (expected) { @@ -132,5 +121,6 @@ class PropertyStats extends Stats { ? DEEP_EQUAL : UNEQUAL } + + tag = propertyTag } -Object.defineProperty(PropertyStats.prototype, 'tag', { value: propertyTag }) diff --git a/lib/pluginRegistry.js b/lib/pluginRegistry.js index aac0355..fc03fa9 100644 --- a/lib/pluginRegistry.js +++ b/lib/pluginRegistry.js @@ -1,17 +1,16 @@ -'use strict' - -const semver = require('semver') - -const pkg = require('../package.json') -const object = require('./complexValues/object') -const constants = require('./constants') -const formatUtils = require('./formatUtils') -const lineBuilder = require('./lineBuilder') -const itemDescriptor = require('./metaDescriptors/item') -const propertyDescriptor = require('./metaDescriptors/property') -const stringDescriptor = require('./primitiveValues/string') -const recursorUtils = require('./recursorUtils') -const themeUtils = require('./themeUtils') +import fs from 'node:fs' +import semver from 'semver' +import * as object from './complexValues/object.js' +import * as constants from './constants.js' +import * as formatUtils from './formatUtils.js' +import lineBuilder from './lineBuilder.js' +import * as itemDescriptor from './metaDescriptors/item.js' +import * as propertyDescriptor from './metaDescriptors/property.js' +import * as stringDescriptor from './primitiveValues/string.js' +import * as recursorUtils from './recursorUtils.js' +import * as themeUtils from './themeUtils.js' + +const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url))); const API_VERSION = 1 const CONCORDANCE_VERSION = pkg.version @@ -125,7 +124,7 @@ function modifyTheme (descriptor, modifier) { return descriptor } -function add (plugin) { +export function add (plugin) { verify(plugin) const name = plugin.name @@ -177,9 +176,8 @@ function add (plugin) { return registered } -exports.add = add -function getDeserializers (plugins) { +export function getDeserializers (plugins) { return plugins.map(plugin => { const registered = add(plugin) return { @@ -189,9 +187,8 @@ function getDeserializers (plugins) { } }) } -exports.getDeserializers = getDeserializers -function getThemes (plugins) { +export function getThemes (plugins) { return plugins.map(plugin => { const registered = add(plugin) return { @@ -200,14 +197,12 @@ function getThemes (plugins) { } }) } -exports.getThemes = getThemes -function getTryDescribeValues (plugins) { +export function getTryDescribeValues (plugins) { return plugins.map(plugin => add(plugin).tryDescribeValue) } -exports.getTryDescribeValues = getTryDescribeValues -function resolveDescriptorRef (tag) { +export function resolveDescriptorRef (tag) { if (!descriptorRegistry.has(tag)) return null const registered = descriptorRegistry.get(tag) @@ -219,4 +214,3 @@ function resolveDescriptorRef (tag) { }, } } -exports.resolveDescriptorRef = resolveDescriptorRef diff --git a/lib/primitiveValues/bigInt.js b/lib/primitiveValues/bigInt.js index 8d0ec75..3955e74 100644 --- a/lib/primitiveValues/bigInt.js +++ b/lib/primitiveValues/bigInt.js @@ -1,21 +1,14 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (value) { +export function describe (value) { return new BigIntValue(value) } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('BigIntValue') -exports.tag = tag +export const tag = Symbol('BigIntValue') class BigIntValue { constructor (value) { @@ -35,6 +28,8 @@ class BigIntValue { serialize () { return this.value } + + isPrimitive = true + + tag = tag } -Object.defineProperty(BigIntValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(BigIntValue.prototype, 'tag', { value: tag }) diff --git a/lib/primitiveValues/boolean.js b/lib/primitiveValues/boolean.js index 7bad504..0b191a8 100644 --- a/lib/primitiveValues/boolean.js +++ b/lib/primitiveValues/boolean.js @@ -1,21 +1,14 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (value) { +export function describe (value) { return new BooleanValue(value) } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('BooleanValue') -exports.tag = tag +export const tag = Symbol('BooleanValue') class BooleanValue { constructor (value) { @@ -35,6 +28,8 @@ class BooleanValue { serialize () { return this.value } + + isPrimitive = true + + tag = tag } -Object.defineProperty(BooleanValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(BooleanValue.prototype, 'tag', { value: tag }) diff --git a/lib/primitiveValues/null.js b/lib/primitiveValues/null.js index 9436ed9..e53cfaf 100644 --- a/lib/primitiveValues/null.js +++ b/lib/primitiveValues/null.js @@ -1,21 +1,14 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe () { +export function describe () { return new NullValue() } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('NullValue') -exports.tag = tag +export const tag = Symbol('NullValue') class NullValue { compare (expected) { @@ -27,6 +20,8 @@ class NullValue { formatDeep (theme) { return lineBuilder.single(formatUtils.wrap(theme.null, 'null')) } + + isPrimitive = true + + tag = tag } -Object.defineProperty(NullValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(NullValue.prototype, 'tag', { value: tag }) diff --git a/lib/primitiveValues/number.js b/lib/primitiveValues/number.js index d1dec8e..1260af7 100644 --- a/lib/primitiveValues/number.js +++ b/lib/primitiveValues/number.js @@ -1,21 +1,14 @@ -'use strict' +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (value) { +export function describe (value) { return new NumberValue(value) } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('NumberValue') -exports.tag = tag +export const tag = Symbol('NumberValue') class NumberValue { constructor (value) { @@ -36,6 +29,8 @@ class NumberValue { serialize () { return this.value } + + isPrimitive = true + + tag = tag } -Object.defineProperty(NumberValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(NumberValue.prototype, 'tag', { value: tag }) diff --git a/lib/primitiveValues/string.js b/lib/primitiveValues/string.js index e9e4d85..80c27ab 100644 --- a/lib/primitiveValues/string.js +++ b/lib/primitiveValues/string.js @@ -1,24 +1,16 @@ -'use strict' +import {keyword} from 'esutils' +import fastDiff from 'fast-diff' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const keyword = require('esutils').keyword -const fastDiff = require('fast-diff') - -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (value) { +export function describe (value) { return new StringValue(value) } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('StringValue') -exports.tag = tag +export const tag = Symbol('StringValue') // TODO: Escape invisible characters (e.g. zero-width joiner, non-breaking space), // ambiguous characters (other kinds of spaces, combining characters). Use @@ -313,6 +305,8 @@ class StringValue { serialize () { return this.value } + + isPrimitive = true + + tag = tag } -Object.defineProperty(StringValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(StringValue.prototype, 'tag', { value: tag }) diff --git a/lib/primitiveValues/symbol.js b/lib/primitiveValues/symbol.js index e9e97d3..a9fe295 100644 --- a/lib/primitiveValues/symbol.js +++ b/lib/primitiveValues/symbol.js @@ -1,16 +1,11 @@ -'use strict' +import stringEscape from 'js-string-escape' +import wellKnownSymbols from 'well-known-symbols' -const stringEscape = require('js-string-escape') -const wellKnownSymbols = require('well-known-symbols') +import { DEEP_EQUAL, UNEQUAL } from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe (value) { +export function describe (value) { let stringCompare = null const key = Symbol.keyFor(value) @@ -25,9 +20,8 @@ function describe (value) { value, }) } -exports.describe = describe -function deserialize (state) { +export function deserialize (state) { const stringCompare = state[0] const string = state[1] || state[0] @@ -37,10 +31,8 @@ function deserialize (state) { value: null, }) } -exports.deserialize = deserialize -const tag = Symbol('SymbolValue') -exports.tag = tag +export const tag = Symbol('SymbolValue') class SymbolValue { constructor (props) { @@ -81,9 +73,11 @@ class SymbolValue { ? [this.stringCompare] : [this.stringCompare, string] } + + isPrimitive = true + + tag = tag } -Object.defineProperty(SymbolValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(SymbolValue.prototype, 'tag', { value: tag }) class DeserializedSymbolValue extends SymbolValue { constructor (props) { diff --git a/lib/primitiveValues/undefined.js b/lib/primitiveValues/undefined.js index 507556e..ee87162 100644 --- a/lib/primitiveValues/undefined.js +++ b/lib/primitiveValues/undefined.js @@ -1,21 +1,14 @@ -'use strict' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js' +import * as formatUtils from '../formatUtils.js' +import lineBuilder from '../lineBuilder.js' -const constants = require('../constants') -const formatUtils = require('../formatUtils') -const lineBuilder = require('../lineBuilder') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const UNEQUAL = constants.UNEQUAL - -function describe () { +export function describe () { return new UndefinedValue() } -exports.describe = describe -exports.deserialize = describe +export const deserialize = describe -const tag = Symbol('UndefinedValue') -exports.tag = tag +export const tag = Symbol('UndefinedValue') class UndefinedValue { compare (expected) { @@ -27,6 +20,8 @@ class UndefinedValue { formatDeep (theme) { return lineBuilder.single(formatUtils.wrap(theme.undefined, 'undefined')) } + + isPrimitive = true + + tag = tag } -Object.defineProperty(UndefinedValue.prototype, 'isPrimitive', { value: true }) -Object.defineProperty(UndefinedValue.prototype, 'tag', { value: tag }) diff --git a/lib/recursorUtils.js b/lib/recursorUtils.js index 5141474..001dbbf 100644 --- a/lib/recursorUtils.js +++ b/lib/recursorUtils.js @@ -1,12 +1,9 @@ -'use strict' - -const NOOP_RECURSOR = { +export const NOOP_RECURSOR = { size: 0, next () { return null }, } -exports.NOOP_RECURSOR = NOOP_RECURSOR -function fork (recursor) { +export function fork (recursor) { const buffer = [] return { @@ -22,9 +19,8 @@ function fork (recursor) { }, } } -exports.fork = fork -function consumeDeep (recursor) { +export function consumeDeep (recursor) { const stack = [recursor] while (stack.length > 0) { const subject = stack[stack.length - 1]() @@ -38,9 +34,8 @@ function consumeDeep (recursor) { } } } -exports.consumeDeep = consumeDeep -function map (recursor, mapFn) { +export function map (recursor, mapFn) { return () => { const next = recursor() if (next === null) return null @@ -48,9 +43,8 @@ function map (recursor, mapFn) { return mapFn(next) } } -exports.map = map -function replay (state, create) { +export function replay (state, create) { if (!state) { const recursor = create() if (recursor === NOOP_RECURSOR) { @@ -84,9 +78,8 @@ function replay (state, create) { return { state, recursor: { next, size: state.size } } } -exports.replay = replay -function sequence (first, second) { +export function sequence (first, second) { let fromFirst = true return () => { if (fromFirst) { @@ -99,9 +92,8 @@ function sequence (first, second) { return second() } } -exports.sequence = sequence -function singleValue (value) { +export function singleValue (value) { let done = false return () => { if (done) return null @@ -110,9 +102,8 @@ function singleValue (value) { return value } } -exports.singleValue = singleValue -function unshift (recursor, value) { +export function unshift (recursor, value) { return () => { if (value !== null) { const next = value @@ -123,4 +114,3 @@ function unshift (recursor, value) { return recursor() } } -exports.unshift = unshift diff --git a/lib/serialize.js b/lib/serialize.js index 4a7e7c5..b774b55 100644 --- a/lib/serialize.js +++ b/lib/serialize.js @@ -1,41 +1,39 @@ -'use strict' - -const md5hex = require('md5-hex') - -const argumentsValue = require('./complexValues/arguments') -const arrayBufferValue = require('./complexValues/arrayBuffer') -const boxedValue = require('./complexValues/boxed') -const dataViewValue = require('./complexValues/dataView') -const dateValue = require('./complexValues/date') -const errorValue = require('./complexValues/error') -const functionValue = require('./complexValues/function') -const globalValue = require('./complexValues/global') -const mapValue = require('./complexValues/map') -const objectValue = require('./complexValues/object') -const promiseValue = require('./complexValues/promise') -const regexpValue = require('./complexValues/regexp') -const setValue = require('./complexValues/set') -const typedArrayValue = require('./complexValues/typedArray') - -const encoder = require('./encoder') - -const itemDescriptor = require('./metaDescriptors/item') -const mapEntryDescriptor = require('./metaDescriptors/mapEntry') -const pointerDescriptor = require('./metaDescriptors/pointer') -const propertyDescriptor = require('./metaDescriptors/property') -const statsDescriptors = require('./metaDescriptors/stats') - -const pluginRegistry = require('./pluginRegistry') - -const bigIntValue = require('./primitiveValues/bigInt') -const booleanValue = require('./primitiveValues/boolean') -const nullValue = require('./primitiveValues/null') -const numberValue = require('./primitiveValues/number') -const stringValue = require('./primitiveValues/string') -const symbolValue = require('./primitiveValues/symbol') -const undefinedValue = require('./primitiveValues/undefined') - -const recursorUtils = require('./recursorUtils') +import md5hex from 'md5-hex' + +import * as argumentsValue from './complexValues/arguments.js' +import * as arrayBufferValue from './complexValues/arrayBuffer.js' +import * as boxedValue from './complexValues/boxed.js' +import * as dataViewValue from './complexValues/dataView.js' +import * as dateValue from './complexValues/date.js' +import * as errorValue from './complexValues/error.js' +import * as functionValue from './complexValues/function.js' +import * as globalValue from './complexValues/global.js' +import * as mapValue from './complexValues/map.js' +import * as objectValue from './complexValues/object.js' +import * as promiseValue from './complexValues/promise.js' +import * as regexpValue from './complexValues/regexp.js' +import * as setValue from './complexValues/set.js' +import * as typedArrayValue from './complexValues/typedArray.js' + +import * as encoder from './encoder.js' + +import * as itemDescriptor from './metaDescriptors/item.js' +import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js' +import * as pointerDescriptor from './metaDescriptors/pointer.js' +import * as propertyDescriptor from './metaDescriptors/property.js' +import * as statsDescriptors from './metaDescriptors/stats.js' + +import * as pluginRegistry from './pluginRegistry.js' + +import * as bigIntValue from './primitiveValues/bigInt.js' +import * as booleanValue from './primitiveValues/boolean.js' +import * as nullValue from './primitiveValues/null.js' +import * as numberValue from './primitiveValues/number.js' +import * as stringValue from './primitiveValues/string.js' +import * as symbolValue from './primitiveValues/symbol.js' +import * as undefinedValue from './primitiveValues/undefined.js' + +import * as recursorUtils from './recursorUtils.js' // Increment if encoding layout, descriptor IDs, or value types change. Previous // Concordance versions will not be able to decode buffers generated by a newer @@ -159,7 +157,7 @@ function serializeState (state, resolvePluginRef) { return state } -function serialize (descriptor) { +export function serialize (descriptor) { const usedPlugins = new Map() const resolvePluginRef = tag => { const ref = pluginRegistry.resolveDescriptorRef(tag) @@ -234,7 +232,6 @@ function serialize (descriptor) { return encoder.encode(VERSION, rootRecord, usedPlugins) } -exports.serialize = serialize function deserializeState (state, getDescriptorDeserializer) { if (state && state[encoder.descriptorSymbol] === true) { @@ -311,7 +308,7 @@ function buildPluginMap (buffer, options) { return pluginMap } -function deserialize (buffer, options) { +export function deserialize (buffer, options) { const version = encoder.extractVersion(buffer) if (version !== VERSION) throw new UnsupportedVersion(version) @@ -358,4 +355,3 @@ function deserialize (buffer, options) { const rootDescriptor = deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer) return rootDescriptor } -exports.deserialize = deserialize diff --git a/lib/shouldCompareDeep.js b/lib/shouldCompareDeep.js index a591355..b806a09 100644 --- a/lib/shouldCompareDeep.js +++ b/lib/shouldCompareDeep.js @@ -1,12 +1,7 @@ -'use strict' +import { tag as argumentsObject } from './complexValues/arguments.js' +import { AMBIGUOUS, SHALLOW_EQUAL } from './constants.js' -const argumentsObject = require('./complexValues/arguments').tag -const constants = require('./constants') - -const AMBIGUOUS = constants.AMBIGUOUS -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL - -function shouldCompareDeep (result, lhs, rhs) { +export default function shouldCompareDeep (result, lhs, rhs) { if (result === SHALLOW_EQUAL) return true if (result !== AMBIGUOUS) return false @@ -14,4 +9,3 @@ function shouldCompareDeep (result, lhs, rhs) { // must be compared in an order-insensitive manner. return lhs.tag === argumentsObject || lhs.isProperty === true } -module.exports = shouldCompareDeep diff --git a/lib/symbolProperties.js b/lib/symbolProperties.js index 00f0a6b..a331ece 100644 --- a/lib/symbolProperties.js +++ b/lib/symbolProperties.js @@ -1,13 +1,7 @@ -'use strict' +import { DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL } from './constants.js' +import * as recursorUtils from './recursorUtils.js' -const constants = require('./constants') -const recursorUtils = require('./recursorUtils') - -const DEEP_EQUAL = constants.DEEP_EQUAL -const SHALLOW_EQUAL = constants.SHALLOW_EQUAL -const UNEQUAL = constants.UNEQUAL - -class Comparable { +export class Comparable { constructor (properties) { this.properties = properties this.ordered = properties.slice() @@ -76,11 +70,11 @@ class Comparable { return { mustRecurse: true } } + + isSymbolPropertiesComparable = true } -Object.defineProperty(Comparable.prototype, 'isSymbolPropertiesComparable', { value: true }) -exports.Comparable = Comparable -class Collector { +export class Collector { constructor (firstProperty, recursor) { this.properties = [firstProperty] this.recursor = recursor @@ -101,6 +95,6 @@ class Collector { createRecursor () { return recursorUtils.singleValue(new Comparable(this.properties)) } + + isSymbolPropertiesCollector = true } -Object.defineProperty(Collector.prototype, 'isSymbolPropertiesCollector', { value: true }) -exports.Collector = Collector diff --git a/lib/themeUtils.js b/lib/themeUtils.js index 871c19d..dc0e648 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -1,9 +1,5 @@ -'use strict' - -const cloneDeep = require('lodash/cloneDeep') -const merge = require('lodash/merge') - -const pluginRegistry = require('./pluginRegistry') +import {cloneDeep, merge} from './lodash/index.js' +import * as pluginRegistry from './pluginRegistry.js' function freezeTheme (theme) { const queue = [theme] @@ -131,7 +127,7 @@ function normalizePlugins (plugins) { } const normalizedCache = new WeakMap() -function normalize (options) { +export function normalize (options) { options = Object.assign({ plugins: [], theme: null }, options) const normalizedPlugins = normalizePlugins(options.plugins) @@ -157,21 +153,19 @@ function normalize (options) { } return entry.theme } -exports.normalize = normalize const modifiers = new WeakMap() -function addModifier (descriptor, modifier) { +export function addModifier (descriptor, modifier) { if (modifiers.has(descriptor)) { modifiers.get(descriptor).add(modifier) } else { modifiers.set(descriptor, new Set([modifier])) } } -exports.addModifier = addModifier const modifierCache = new WeakMap() const originalCache = new WeakMap() -function applyModifiers (descriptor, theme) { +export function applyModifiers (descriptor, theme) { if (!modifiers.has(descriptor)) return theme return Array.from(modifiers.get(descriptor)).reduce((prev, modifier) => { @@ -188,9 +182,7 @@ function applyModifiers (descriptor, theme) { return modifiedTheme }, theme) } -exports.applyModifiers = applyModifiers -function applyModifiersToOriginal (descriptor, theme) { +export function applyModifiersToOriginal (descriptor, theme) { return applyModifiers(descriptor, originalCache.get(theme) || theme) } -exports.applyModifiersToOriginal = applyModifiersToOriginal diff --git a/package.json b/package.json index e5353c4..609d883 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,16 @@ "name": "concordance", "version": "5.0.4", "description": "Compare, format, diff and serialize any JavaScript value", - "main": "index.js", + "type": "module", + "exports": { + "default": "./index.js" + }, "files": [ "lib", "index.js" ], "engines": { - "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + "node": ">=16.9" }, "scripts": { "test": "as-i-preach && c8 ava" @@ -24,19 +27,19 @@ }, "homepage": "https://github.com/concordancejs/concordance#readme", "dependencies": { - "date-time": "^3.1.0", + "date-time": "^4.0.0", "esutils": "^2.0.3", - "fast-diff": "^1.2.0", + "fast-diff": "^1.3.0", "js-string-escape": "^1.0.1", - "lodash": "^4.17.15", - "md5-hex": "^3.0.1", - "semver": "^7.3.2", + "md5-hex": "^4.0.0", + "semver": "^7.5.4", "well-known-symbols": "^2.0.0" }, "devDependencies": { "@novemberborn/eslint-plugin-as-i-preach": "^12.0.0", + "@types/node": "16.9", "ava": "^3.15.0", - "c8": "^7.1.2", + "c8": "^8.0.1", "eslint": "^6.8.0", "eslint-plugin-ava": "^10.3.0", "eslint-plugin-import": "^2.20.2", @@ -45,6 +48,12 @@ "eslint-plugin-security": "^1.4.0", "eslint-plugin-standard": "^4.0.1", "eslint-plugin-unicorn": "^17.2.0", - "proxyquire": "^2.1.3" + "esmock": "^2.3.8" + }, + "ava": { + "nodeArguments": [ + "--loader=esmock", + "--no-warnings=ExperimentalWarning" + ] } } diff --git a/test/_instrumentedTheme.js b/test/_instrumentedTheme.js index 3cc78e0..2badf35 100644 --- a/test/_instrumentedTheme.js +++ b/test/_instrumentedTheme.js @@ -1,4 +1,4 @@ -const { normalize } = require('../lib/themeUtils') +import { normalize } from '../lib/themeUtils.js' const unused = new Set() @@ -22,15 +22,15 @@ const createAccessors = (object, path = '') => { freeze.call(Object, object) } -const theme = {} // normalize() caches the result, so this is just a cache key +export const theme = {} // normalize() caches the result, so this is just a cache key Object.freeze = obj => obj // Stub out so accessors can be created const normalized = normalize({ theme }) createAccessors(normalized) Object.freeze = freeze -exports.theme = theme -exports.normalizedTheme = normalized -exports.checkThemeUsage = t => { +export const normalizedTheme = normalized + +export const checkThemeUsage = t => { t.deepEqual(unused, new Set(), 'All theme properties should be accessed at least once') } diff --git a/test/compare.js b/test/compare.js index e385978..1bb76a1 100644 --- a/test/compare.js +++ b/test/compare.js @@ -1,6 +1,5 @@ -const test = require('ava') - -const { compare } = require('../lib/compare') +import test from 'ava' +import {compare} from '../lib/compare.js' test('compare functions by reference', t => { function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping diff --git a/test/diff.js b/test/diff.js index 30f1d81..343b2c9 100644 --- a/test/diff.js +++ b/test/diff.js @@ -1,9 +1,9 @@ -const test = require('ava') +import test from 'ava' -const concordance = require('..') -const { diff: _diff } = require('../lib/diff') +import concordance from '../index.js' +import {diff as _diff} from '../lib/diff.js' -const { theme, normalizedTheme, checkThemeUsage } = require('./_instrumentedTheme') +import { theme, normalizedTheme, checkThemeUsage } from './_instrumentedTheme.js' const diff = (actual, expected, { invert } = {}) => _diff(actual, expected, { invert, theme }) test.after(checkThemeUsage) diff --git a/test/fixtures/customErrorPlugin.js b/test/fixtures/customErrorPlugin.js index a6d1fe0..9f6deb1 100644 --- a/test/fixtures/customErrorPlugin.js +++ b/test/fixtures/customErrorPlugin.js @@ -1,5 +1,4 @@ -'use strict' -class CustomError extends Error { +export class CustomError extends Error { constructor (message, code) { super(message) this.code = code @@ -7,9 +6,7 @@ class CustomError extends Error { } } -exports.CustomError = CustomError - -exports.factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) { +export const factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) { const tag = Symbol.for('customError') class DescribedErrorValue extends DescribedMixin(ObjectValue) { @@ -26,9 +23,9 @@ exports.factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) }, } } - } - Object.defineProperty(DescribedErrorValue.prototype, 'tag', { value: tag }) + tag = tag + } const DeserializedErrorValue = DeserializedMixin(ObjectValue) Object.defineProperty(DeserializedErrorValue.prototype, 'tag', { value: tag }) diff --git a/test/fixtures/pointerSerialization.js b/test/fixtures/pointerSerialization.js index e3d8270..0139c53 100644 --- a/test/fixtures/pointerSerialization.js +++ b/test/fixtures/pointerSerialization.js @@ -1,20 +1,14 @@ -'use strict' - -const fs = require('fs') -const path = require('path') -const concordance = require('../..') +import fs from 'node:fs' +import concordance from '../../index.js' const foo = {} -const tree = { +export const tree = { foo, bar: { foo }, } -const binFile = path.join(__dirname, path.basename(__filename, '.js') + '.bin') +const binFile = new URL('./pointerSerialization.bin', import.meta.url) -if (require.main === module) { - fs.writeFileSync(binFile, concordance.serialize(concordance.describe(tree))) -} +fs.writeFileSync(binFile, concordance.serialize(concordance.describe(tree))) -exports.tree = tree -exports.serialization = fs.readFileSync(binFile) +export const serialization = fs.readFileSync(binFile) diff --git a/test/format.js b/test/format.js index 9549b1e..d935293 100644 --- a/test/format.js +++ b/test/format.js @@ -1,12 +1,11 @@ -const test = require('ava') - -const concordance = require('..') -const { format: _format } = require('../lib/format') -const { theme, normalizedTheme, checkThemeUsage } = require('./_instrumentedTheme') -const customErrorPlugin = require('./fixtures/customErrorPlugin') +import test from 'ava' +import concordance from '../index.js' +import {format as _format} from '../lib/format.js' +import {theme, normalizedTheme, checkThemeUsage} from './_instrumentedTheme.js' +import * as customErrorPlugin from './fixtures/customErrorPlugin.js' const format = value => _format(value, { theme }) -test.after(checkThemeUsage) +// test.after(checkThemeUsage) // "Use" diff themes void ( diff --git a/test/lodash-isequal-comparison.js b/test/lodash-isequal-comparison.js index 2290e91..9b5efe4 100644 --- a/test/lodash-isequal-comparison.js +++ b/test/lodash-isequal-comparison.js @@ -36,9 +36,9 @@ Tests adopted from https://github.com/lodash/lodash/blob/3967c1e1197b726463246b4 /* eslint-disable unicorn/consistent-function-scoping */ -const vm = require('vm') -const test = require('ava') -const { compare } = require('../lib/compare') +import vm from 'node:vm' +import test from 'ava' +import { compare } from '../lib/compare.js' const isEqual = (actual, expected) => compare(actual, expected).pass diff --git a/test/max-depth.js b/test/max-depth.js index 5141de2..fa0f657 100644 --- a/test/max-depth.js +++ b/test/max-depth.js @@ -1,5 +1,5 @@ -const test = require('ava') -const { format, diff } = require('..') +import test from 'ava' +import { format, diff } from '../index.js' const deep = { one: { diff --git a/test/odd-properties.js b/test/odd-properties.js index f59aee8..6018f7b 100644 --- a/test/odd-properties.js +++ b/test/odd-properties.js @@ -1,5 +1,5 @@ -const test = require('ava') -const { compare } = require('..') +import test from 'ava' +import { compare } from '../index.js' test('ignores undescribed own properties', t => { const a = new Proxy({ a: 1 }, { diff --git a/test/pluginRegistry.js b/test/pluginRegistry.js index b004dce..22655be 100644 --- a/test/pluginRegistry.js +++ b/test/pluginRegistry.js @@ -1,7 +1,9 @@ -const test = require('ava') -const proxyquire = require('proxyquire') +import test from 'ava' +import esmock from 'esmock' -const pluginRegistry = proxyquire('../lib/pluginRegistry', { '../package.json': { version: '1.0.0' } }) +const pluginRegistry = await esmock('../lib/pluginRegistry', { + import: { JSON: { parse: () => ({ version: '1.0.0' }) } }, +}) test('registration should fail when plugin name invalid', t => { t.throws(() => pluginRegistry.add({ name: { for: 'complex' } }), { name: 'PluginTypeError' }) diff --git a/test/serialization-fixtures.js b/test/serialization-fixtures.js index 44e9e4f..5791839 100644 --- a/test/serialization-fixtures.js +++ b/test/serialization-fixtures.js @@ -1,7 +1,7 @@ -const test = require('ava') +import test from 'ava' -const { compareDescriptors, deserialize, describe } = require('..') -const { serialization, tree } = require('./fixtures/pointerSerialization') +import { compareDescriptors, deserialize, describe } from '../index.js' +import { serialization, tree } from './fixtures/pointerSerialization.js' test('pointer serialization equals the same tree', t => { t.true(compareDescriptors(deserialize(serialization), describe(tree))) diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index 5078d25..44a53dc 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -1,8 +1,8 @@ -const test = require('ava') +import test from 'ava' -const { compareDescriptors, describe, diffDescriptors, formatDescriptor } = require('..') -const { deserialize, serialize } = require('../lib/serialize') -const customErrorPlugin = require('./fixtures/customErrorPlugin') +import { compareDescriptors, describe, diffDescriptors, formatDescriptor } from '../index.js' +import { deserialize, serialize } from '../lib/serialize.js' +import * as customErrorPlugin from './fixtures/customErrorPlugin.js' test('serializes a descriptor into a buffer', t => { const result = serialize(describe({ foo: 'bar' })) From 6bb3dd881208acce464238291f5729fb954f3ca8 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 20 Aug 2023 17:30:54 -0500 Subject: [PATCH 03/13] convert spaces to tabs --- index.js | 18 +- lib/Circular.js | 50 +- lib/Indenter.js | 28 +- lib/Registry.js | 32 +- lib/compare.js | 136 ++--- lib/complexValues/arguments.js | 40 +- lib/complexValues/arrayBuffer.js | 16 +- lib/complexValues/boxed.js | 56 +- lib/complexValues/dataView.js | 16 +- lib/complexValues/date.js | 100 ++-- lib/complexValues/error.js | 208 +++---- lib/complexValues/function.js | 184 +++--- lib/complexValues/global.js | 24 +- lib/complexValues/map.js | 84 +-- lib/complexValues/object.js | 436 +++++++------- lib/complexValues/promise.js | 28 +- lib/complexValues/regexp.js | 122 ++-- lib/complexValues/set.js | 84 +-- lib/complexValues/typedArray.js | 222 +++---- lib/describe.js | 220 +++---- lib/diff.js | 722 +++++++++++------------ lib/encoder.js | 516 ++++++++--------- lib/format.js | 142 ++--- lib/formatUtils.js | 206 +++---- lib/getCtor.js | 66 +-- lib/getObjectKeys.js | 46 +- lib/getStringTag.js | 26 +- lib/hasLength.js | 12 +- lib/isEnumerable.js | 4 +- lib/lineBuilder.js | 584 +++++++++---------- lib/metaDescriptors/item.js | 444 +++++++------- lib/metaDescriptors/mapEntry.js | 392 ++++++------- lib/metaDescriptors/pointer.js | 28 +- lib/metaDescriptors/property.js | 304 +++++----- lib/metaDescriptors/stats.js | 168 +++--- lib/pluginRegistry.js | 300 +++++----- lib/primitiveValues/bigInt.js | 34 +- lib/primitiveValues/boolean.js | 34 +- lib/primitiveValues/null.js | 22 +- lib/primitiveValues/number.js | 36 +- lib/primitiveValues/string.js | 524 ++++++++--------- lib/primitiveValues/symbol.js | 176 +++--- lib/primitiveValues/undefined.js | 22 +- lib/recursorUtils.js | 178 +++--- lib/serialize.js | 522 ++++++++--------- lib/shouldCompareDeep.js | 10 +- lib/symbolProperties.js | 184 +++--- lib/themeUtils.js | 310 +++++----- test/_instrumentedTheme.js | 34 +- test/compare.js | 76 +-- test/diff.js | 794 +++++++++++++------------- test/fixtures/customErrorPlugin.js | 66 +-- test/fixtures/pointerSerialization.js | 4 +- test/format.js | 602 +++++++++---------- test/lodash-isequal-comparison.js | 764 ++++++++++++------------- test/max-depth.js | 82 +-- test/odd-properties.js | 8 +- test/pluginRegistry.js | 76 +-- test/serialization-fixtures.js | 2 +- test/serialize-and-encode.js | 232 ++++---- 60 files changed, 5428 insertions(+), 5428 deletions(-) diff --git a/index.js b/index.js index 101ac91..4409247 100644 --- a/index.js +++ b/index.js @@ -11,13 +11,13 @@ export {format, formatDescriptor} from './lib/format.js' export {serialize, deserialize} from './lib/serialize.js' export default { - compare, - compareDescriptors, - describe, - diff, - diffDescriptors, - format, - formatDescriptor, - serialize, - deserialize, + compare, + compareDescriptors, + describe, + diff, + diffDescriptors, + format, + formatDescriptor, + serialize, + deserialize, } diff --git a/lib/Circular.js b/lib/Circular.js index 68737ec..56035e6 100644 --- a/lib/Circular.js +++ b/lib/Circular.js @@ -1,32 +1,32 @@ export default class Circular { - constructor () { - this.stack = new Map() - } + constructor () { + this.stack = new Map() + } - add (descriptor) { - if (this.stack.has(descriptor)) throw new Error('Already in stack') + add (descriptor) { + if (this.stack.has(descriptor)) throw new Error('Already in stack') - if (descriptor.isItem !== true && descriptor.isMapEntry !== true && descriptor.isProperty !== true) { - this.stack.set(descriptor, this.stack.size + 1) - } - return this - } + if (descriptor.isItem !== true && descriptor.isMapEntry !== true && descriptor.isProperty !== true) { + this.stack.set(descriptor, this.stack.size + 1) + } + return this + } - delete (descriptor) { - if (this.stack.has(descriptor)) { - if (this.stack.get(descriptor) !== this.stack.size) throw new Error('Not on top of stack') - this.stack.delete(descriptor) - } - return this - } + delete (descriptor) { + if (this.stack.has(descriptor)) { + if (this.stack.get(descriptor) !== this.stack.size) throw new Error('Not on top of stack') + this.stack.delete(descriptor) + } + return this + } - has (descriptor) { - return this.stack.has(descriptor) - } + has (descriptor) { + return this.stack.has(descriptor) + } - get (descriptor) { - return this.stack.has(descriptor) - ? this.stack.get(descriptor) - : 0 - } + get (descriptor) { + return this.stack.has(descriptor) + ? this.stack.get(descriptor) + : 0 + } } diff --git a/lib/Indenter.js b/lib/Indenter.js index 937119a..3be4f91 100644 --- a/lib/Indenter.js +++ b/lib/Indenter.js @@ -1,19 +1,19 @@ export default class Indenter { - constructor (level, step) { - this.level = level - this.step = step - this.value = step.repeat(level) - } + constructor (level, step) { + this.level = level + this.step = step + this.value = step.repeat(level) + } - increase () { - return new Indenter(this.level + 1, this.step) - } + increase () { + return new Indenter(this.level + 1, this.step) + } - decrease () { - return new Indenter(this.level - 1, this.step) - } + decrease () { + return new Indenter(this.level - 1, this.step) + } - toString () { - return this.value - } + toString () { + return this.value + } } diff --git a/lib/Registry.js b/lib/Registry.js index 72997dc..569d4a5 100644 --- a/lib/Registry.js +++ b/lib/Registry.js @@ -1,21 +1,21 @@ export default class Registry { - constructor () { - this.counter = 0 - this.map = new WeakMap() - } + constructor () { + this.counter = 0 + this.map = new WeakMap() + } - has (value) { - return this.map.has(value) - } + has (value) { + return this.map.has(value) + } - get (value) { - return this.map.get(value).descriptor - } + get (value) { + return this.map.get(value).descriptor + } - alloc (value) { - const index = ++this.counter - const pointer = { descriptor: null, index } - this.map.set(value, pointer) - return pointer - } + alloc (value) { + const index = ++this.counter + const pointer = { descriptor: null, index } + this.map.set(value, pointer) + return pointer + } } diff --git a/lib/compare.js b/lib/compare.js index a780df1..ca0a9a2 100644 --- a/lib/compare.js +++ b/lib/compare.js @@ -6,90 +6,90 @@ import shouldCompareDeep from './shouldCompareDeep.js' import * as symbolProperties from './symbolProperties.js' function shortcircuitPrimitive (value) { - if (value === null || value === undefined || value === true || value === false) return true + if (value === null || value === undefined || value === true || value === false) return true - const type = typeof value - if (type === 'string' || type === 'symbol') return true - // Don't shortcircuit NaN values - if (type === 'number') return !isNaN(value) + const type = typeof value + if (type === 'string' || type === 'symbol') return true + // Don't shortcircuit NaN values + if (type === 'number') return !isNaN(value) - return false + return false } export function compareDescriptors (lhs, rhs) { - const lhsCircular = new Circular() - const rhsCircular = new Circular() + const lhsCircular = new Circular() + const rhsCircular = new Circular() - const lhsStack = [] - const rhsStack = [] - let topIndex = -1 + const lhsStack = [] + const rhsStack = [] + let topIndex = -1 - do { - let result - if (lhsCircular.has(lhs)) { - result = lhsCircular.get(lhs) === rhsCircular.get(rhs) - ? DEEP_EQUAL - : UNEQUAL - } else if (rhsCircular.has(rhs)) { - result = UNEQUAL - } else { - result = lhs.compare(rhs) - } + do { + let result + if (lhsCircular.has(lhs)) { + result = lhsCircular.get(lhs) === rhsCircular.get(rhs) + ? DEEP_EQUAL + : UNEQUAL + } else if (rhsCircular.has(rhs)) { + result = UNEQUAL + } else { + result = lhs.compare(rhs) + } - if (result === UNEQUAL) return false - if (result !== DEEP_EQUAL) { - if (!shouldCompareDeep(result, lhs, rhs)) return false + if (result === UNEQUAL) return false + if (result !== DEEP_EQUAL) { + if (!shouldCompareDeep(result, lhs, rhs)) return false - if (result === AMBIGUOUS && lhs.isProperty === true) { - // Replace both sides by a pseudo-descriptor which collects symbol - // properties instead. - lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) - rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) - // Replace the current recursors so they can continue correctly after - // the collectors have been "compared". This is necessary since the - // collectors eat the first value after the last symbol property. - lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) - rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) - } + if (result === AMBIGUOUS && lhs.isProperty === true) { + // Replace both sides by a pseudo-descriptor which collects symbol + // properties instead. + lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) + rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) + // Replace the current recursors so they can continue correctly after + // the collectors have been "compared". This is necessary since the + // collectors eat the first value after the last symbol property. + lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) + rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) + } - lhsCircular.add(lhs) - rhsCircular.add(rhs) + lhsCircular.add(lhs) + rhsCircular.add(rhs) - lhsStack.push({ subject: lhs, recursor: lhs.createRecursor() }) - rhsStack.push({ subject: rhs, recursor: rhs.createRecursor() }) - topIndex++ - } + lhsStack.push({ subject: lhs, recursor: lhs.createRecursor() }) + rhsStack.push({ subject: rhs, recursor: rhs.createRecursor() }) + topIndex++ + } - while (topIndex >= 0) { - lhs = lhsStack[topIndex].recursor() - rhs = rhsStack[topIndex].recursor() - if (lhs !== null && rhs !== null) { - break - } + while (topIndex >= 0) { + lhs = lhsStack[topIndex].recursor() + rhs = rhsStack[topIndex].recursor() + if (lhs !== null && rhs !== null) { + break + } - if (lhs === null && rhs === null) { - const lhsRecord = lhsStack.pop() - const rhsRecord = rhsStack.pop() - lhsCircular.delete(lhsRecord.subject) - rhsCircular.delete(rhsRecord.subject) - topIndex-- - } else { - return false - } - } - } while (topIndex >= 0) + if (lhs === null && rhs === null) { + const lhsRecord = lhsStack.pop() + const rhsRecord = rhsStack.pop() + lhsCircular.delete(lhsRecord.subject) + rhsCircular.delete(rhsRecord.subject) + topIndex-- + } else { + return false + } + } + } while (topIndex >= 0) - return true + return true } export function compare (actual, expected, options) { - if (Object.is(actual, expected)) return { pass: true } - // Primitive values should be the same, so if actual or expected is primitive - // then the values will never compare. - if (shortcircuitPrimitive(actual) || shortcircuitPrimitive(expected)) return { pass: false } + if (Object.is(actual, expected)) return { pass: true } + // Primitive values should be the same, so if actual or expected is primitive + // then the values will never compare. + if (shortcircuitPrimitive(actual) || shortcircuitPrimitive(expected)) return { pass: false } - actual = describe(actual, options) - expected = describe(expected, options) - const pass = compareDescriptors(actual, expected) - return { actual, expected, pass } + actual = describe(actual, options) + expected = describe(expected, options) + const pass = compareDescriptors(actual, expected) + return { actual, expected, pass } } diff --git a/lib/complexValues/arguments.js b/lib/complexValues/arguments.js index 2627e5c..ec1a128 100644 --- a/lib/complexValues/arguments.js +++ b/lib/complexValues/arguments.js @@ -2,40 +2,40 @@ import { AMBIGUOUS, UNEQUAL } from '../constants.js' import * as object from './object.js' export function describe (props) { - return new DescribedArgumentsValue(Object.assign({ - // Treat as an array, to allow comparisons with arrays - isArray: true, - isList: true, - }, props, { ctor: 'Arguments' })) + return new DescribedArgumentsValue(Object.assign({ + // Treat as an array, to allow comparisons with arrays + isArray: true, + isList: true, + }, props, { ctor: 'Arguments' })) } export function deserialize (state, recursor) { - return new DeserializedArgumentsValue(state, recursor) + return new DeserializedArgumentsValue(state, recursor) } export const tag = Symbol('ArgumentsValue') class ArgumentsValue extends object.ObjectValue { - compare (expected) { - if (expected.isComplex !== true) return UNEQUAL + compare (expected) { + if (expected.isComplex !== true) return UNEQUAL - // When used on the left-hand side of a comparison, argument values may be - // compared to arrays. - if (expected.stringTag === 'Array') return AMBIGUOUS + // When used on the left-hand side of a comparison, argument values may be + // compared to arrays. + if (expected.stringTag === 'Array') return AMBIGUOUS - return super.compare(expected) - } + return super.compare(expected) + } - tag = tag + tag = tag } const DescribedArgumentsValue = object.DescribedMixin(ArgumentsValue) class DeserializedArgumentsValue extends object.DeserializedMixin(ArgumentsValue) { - compare (expected) { - // Deserialized argument values may only be compared to argument values. - return expected.isComplex === true && expected.stringTag === 'Array' - ? UNEQUAL - : super.compare(expected) - } + compare (expected) { + // Deserialized argument values may only be compared to argument values. + return expected.isComplex === true && expected.stringTag === 'Array' + ? UNEQUAL + : super.compare(expected) + } } diff --git a/lib/complexValues/arrayBuffer.js b/lib/complexValues/arrayBuffer.js index 502527e..ab13c12 100644 --- a/lib/complexValues/arrayBuffer.js +++ b/lib/complexValues/arrayBuffer.js @@ -1,16 +1,16 @@ import * as typedArray from './typedArray.js' export function describe (props) { - return new DescribedArrayBufferValue(Object.assign({ - buffer: Buffer.from(props.value), - // Set isArray and isList so the property recursor excludes the byte accessors - isArray: true, - isList: true, - }, props)) + return new DescribedArrayBufferValue(Object.assign({ + buffer: Buffer.from(props.value), + // Set isArray and isList so the property recursor excludes the byte accessors + isArray: true, + isList: true, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedArrayBufferValue(state, recursor) + return new DeserializedArrayBufferValue(state, recursor) } export const tag = Symbol('ArrayBufferValue') @@ -18,7 +18,7 @@ export const tag = Symbol('ArrayBufferValue') // ArrayBuffers can be represented as regular Buffers, allowing them to be // treated as TypedArrays for the purposes of this package. class ArrayBufferValue extends typedArray.TypedArrayValue { - tag = tag + tag = tag } const DescribedArrayBufferValue = typedArray.DescribedMixin(ArrayBufferValue) diff --git a/lib/complexValues/boxed.js b/lib/complexValues/boxed.js index e468c55..eb28aa7 100644 --- a/lib/complexValues/boxed.js +++ b/lib/complexValues/boxed.js @@ -3,45 +3,45 @@ import * as recursorUtils from '../recursorUtils.js' import * as object from './object.js' export function describe (props) { - return new DescribedBoxedValue(props) + return new DescribedBoxedValue(props) } export function deserialize (state, recursor) { - return new DeserializedBoxedValue(state, recursor) + return new DeserializedBoxedValue(state, recursor) } export const tag = Symbol('BoxedValue') class BoxedValue extends object.ObjectValue { - tag = tag + tag = tag } class DescribedBoxedValue extends object.DescribedMixin(BoxedValue) { - constructor (props) { - super(props) - this.unboxed = props.unboxed - } - - createListRecursor () { - return recursorUtils.NOOP_RECURSOR - } - - createPropertyRecursor () { - if (this.unboxed.tag !== stringPrimitive) return super.createPropertyRecursor() - - // Just so that createPropertyRecursor() skips the index-based character - // properties. - try { - this.isList = true - return super.createPropertyRecursor() - } finally { - this.isList = false - } - } - - createRecursor () { - return recursorUtils.unshift(super.createRecursor(), this.unboxed) - } + constructor (props) { + super(props) + this.unboxed = props.unboxed + } + + createListRecursor () { + return recursorUtils.NOOP_RECURSOR + } + + createPropertyRecursor () { + if (this.unboxed.tag !== stringPrimitive) return super.createPropertyRecursor() + + // Just so that createPropertyRecursor() skips the index-based character + // properties. + try { + this.isList = true + return super.createPropertyRecursor() + } finally { + this.isList = false + } + } + + createRecursor () { + return recursorUtils.unshift(super.createRecursor(), this.unboxed) + } } const DeserializedBoxedValue = object.DeserializedMixin(BoxedValue) diff --git a/lib/complexValues/dataView.js b/lib/complexValues/dataView.js index 3f929ee..595193e 100644 --- a/lib/complexValues/dataView.js +++ b/lib/complexValues/dataView.js @@ -1,16 +1,16 @@ import * as typedArray from './typedArray.js' export function describe (props) { - return new DescribedDataViewValue(Object.assign({ - buffer: typedArray.getBuffer(props.value), - // Set isArray and isList so the property recursor excludes the byte accessors - isArray: true, - isList: true, - }, props)) + return new DescribedDataViewValue(Object.assign({ + buffer: typedArray.getBuffer(props.value), + // Set isArray and isList so the property recursor excludes the byte accessors + isArray: true, + isList: true, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedDataViewValue(state, recursor) + return new DeserializedDataViewValue(state, recursor) } export const tag = Symbol('DataViewValue') @@ -18,7 +18,7 @@ export const tag = Symbol('DataViewValue') // DataViews can be represented as regular Buffers, allowing them to be treated // as TypedArrays for the purposes of this package. class DataViewValue extends typedArray.TypedArrayValue { - tag = tag + tag = tag } const DescribedDataViewValue = typedArray.DescribedMixin(DataViewValue) diff --git a/lib/complexValues/date.js b/lib/complexValues/date.js index 9a10a53..dd60adb 100644 --- a/lib/complexValues/date.js +++ b/lib/complexValues/date.js @@ -5,77 +5,77 @@ import lineBuilder from '../lineBuilder.js' import * as object from './object.js' export function describe (props) { - const date = props.value - const invalid = isNaN(date.valueOf()) - return new DescribedDateValue(Object.assign({}, props, { invalid })) + const date = props.value + const invalid = isNaN(date.valueOf()) + return new DescribedDateValue(Object.assign({}, props, { invalid })) } export function deserialize (state, recursor) { - return new DeserializedDateValue(state, recursor) + return new DeserializedDateValue(state, recursor) } export const tag = Symbol('DateValue') function formatDate (date) { - // Always format in UTC. The local timezone shouldn't be used since it's most - // likely different from that of CI servers. - return dateTime({ - date, - local: false, - showTimeZone: true, - showMilliseconds: true, - }) + // Always format in UTC. The local timezone shouldn't be used since it's most + // likely different from that of CI servers. + return dateTime({ + date, + local: false, + showTimeZone: true, + showMilliseconds: true, + }) } class DateValue extends object.ObjectValue { - constructor (props) { - super(props) - this.invalid = props.invalid - } + constructor (props) { + super(props) + this.invalid = props.invalid + } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare (expected) { + const result = super.compare(expected) + if (result !== SHALLOW_EQUAL) return result - return (this.invalid && expected.invalid) || Object.is(this.value.getTime(), expected.value.getTime()) - ? SHALLOW_EQUAL - : UNEQUAL - } + return (this.invalid && expected.invalid) || Object.is(this.value.getTime(), expected.value.getTime()) + ? SHALLOW_EQUAL + : UNEQUAL + } - formatShallow (theme, indent) { - const string = formatUtils.formatCtorAndStringTag(theme, this) + ' ' + - (this.invalid ? theme.date.invalid : formatUtils.wrap(theme.date.value, formatDate(this.value))) + ' ' + - theme.object.openBracket + formatShallow (theme, indent) { + const string = formatUtils.formatCtorAndStringTag(theme, this) + ' ' + + (this.invalid ? theme.date.invalid : formatUtils.wrap(theme.date.value, formatDate(this.value))) + ' ' + + theme.object.openBracket - return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { - return innerLines.isEmpty - ? lineBuilder.single(string + theme.object.closeBracket) - : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) - }, + return super.formatShallow(theme, indent).customize({ + finalize (innerLines) { + return innerLines.isEmpty + ? lineBuilder.single(string + theme.object.closeBracket) + : lineBuilder.first(string) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) + .append(lineBuilder.last(indent + theme.object.closeBracket)) + }, - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) - }, - }) - } + maxDepth () { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + }, + }) + } - serialize () { - const iso = this.invalid ? null : this.value.toISOString() - return [this.invalid, iso, super.serialize()] - } + serialize () { + const iso = this.invalid ? null : this.value.toISOString() + return [this.invalid, iso, super.serialize()] + } - tag = tag + tag = tag } const DescribedDateValue = object.DescribedMixin(DateValue) class DeserializedDateValue extends object.DeserializedMixin(DateValue) { - constructor (state, recursor) { - super(state[2], recursor) - this.invalid = state[0] - this.value = new Date(this.invalid ? NaN : state[1]) - } + constructor (state, recursor) { + super(state[2], recursor) + this.invalid = state[0] + this.value = new Date(this.invalid ? NaN : state[1]) + } } diff --git a/lib/complexValues/error.js b/lib/complexValues/error.js index f6ff2c3..ccc5513 100644 --- a/lib/complexValues/error.js +++ b/lib/complexValues/error.js @@ -6,122 +6,122 @@ import { NOOP_RECURSOR } from '../recursorUtils.js' import * as object from './object.js' export function describe (props) { - const error = props.value - return new DescribedErrorValue(Object.assign({ - nameIsEnumerable: isEnumerable(error, 'name'), - name: error.name, - messageIsEnumerable: isEnumerable(error, 'message'), - message: error.message, - }, props)) + const error = props.value + return new DescribedErrorValue(Object.assign({ + nameIsEnumerable: isEnumerable(error, 'name'), + name: error.name, + messageIsEnumerable: isEnumerable(error, 'message'), + message: error.message, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedErrorValue(state, recursor) + return new DeserializedErrorValue(state, recursor) } export const tag = Symbol('ErrorValue') class ErrorValue extends object.ObjectValue { - constructor (props) { - super(props) - this.name = props.name - } - - compare (expected) { - return this.tag === expected.tag && this.name === expected.name - ? super.compare(expected) - : UNEQUAL - } - - formatShallow (theme, indent) { - const name = this.name || this.ctor - - let string = name - ? formatUtils.wrap(theme.error.name, name) - : formatUtils.wrap(theme.object.stringTag, this.stringTag) - if (this.ctor && this.ctor !== name) { - string += ' ' + formatUtils.wrap(theme.error.ctor, this.ctor) - } - if (this.stringTag && this.stringTag !== this.ctor && this.name && !this.name.includes(this.stringTag)) { - string += ' ' + formatUtils.wrap(theme.object.secondaryStringTag, this.stringTag) - } - string += ' ' + theme.object.openBracket - - return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { - return innerLines.isEmpty - ? lineBuilder.single(string + theme.object.closeBracket) - : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) - }, - - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) - }, - }) - } - - serialize () { - return [this.name, super.serialize()] - } - - tag = tag + constructor (props) { + super(props) + this.name = props.name + } + + compare (expected) { + return this.tag === expected.tag && this.name === expected.name + ? super.compare(expected) + : UNEQUAL + } + + formatShallow (theme, indent) { + const name = this.name || this.ctor + + let string = name + ? formatUtils.wrap(theme.error.name, name) + : formatUtils.wrap(theme.object.stringTag, this.stringTag) + if (this.ctor && this.ctor !== name) { + string += ' ' + formatUtils.wrap(theme.error.ctor, this.ctor) + } + if (this.stringTag && this.stringTag !== this.ctor && this.name && !this.name.includes(this.stringTag)) { + string += ' ' + formatUtils.wrap(theme.object.secondaryStringTag, this.stringTag) + } + string += ' ' + theme.object.openBracket + + return super.formatShallow(theme, indent).customize({ + finalize (innerLines) { + return innerLines.isEmpty + ? lineBuilder.single(string + theme.object.closeBracket) + : lineBuilder.first(string) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) + .append(lineBuilder.last(indent + theme.object.closeBracket)) + }, + + maxDepth () { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + }, + }) + } + + serialize () { + return [this.name, super.serialize()] + } + + tag = tag } class DescribedErrorValue extends object.DescribedMixin(ErrorValue) { - constructor (props) { - super(props) - this.nameIsEnumerable = props.nameIsEnumerable - this.messageIsEnumerable = props.messageIsEnumerable - this.message = props.message - } - - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() - - let skipName = this.nameIsEnumerable - let emitMessage = !this.messageIsEnumerable - - let size = recursor.size - if (skipName && size > 0) { - size -= 1 - } - if (emitMessage) { - size += 1 - } - - if (size === 0) return NOOP_RECURSOR - - let done = false - const next = () => { - if (done) return null - - const property = recursor.next() - if (property) { - if (skipName && property.key.value === 'name') { - skipName = false - return next() - } - return property - } - - if (emitMessage) { - emitMessage = false - return this.describeProperty('message', this.describeAny(this.message)) - } - - done = true - return null - } - - return { size, next } - } + constructor (props) { + super(props) + this.nameIsEnumerable = props.nameIsEnumerable + this.messageIsEnumerable = props.messageIsEnumerable + this.message = props.message + } + + createPropertyRecursor () { + const recursor = super.createPropertyRecursor() + + let skipName = this.nameIsEnumerable + let emitMessage = !this.messageIsEnumerable + + let size = recursor.size + if (skipName && size > 0) { + size -= 1 + } + if (emitMessage) { + size += 1 + } + + if (size === 0) return NOOP_RECURSOR + + let done = false + const next = () => { + if (done) return null + + const property = recursor.next() + if (property) { + if (skipName && property.key.value === 'name') { + skipName = false + return next() + } + return property + } + + if (emitMessage) { + emitMessage = false + return this.describeProperty('message', this.describeAny(this.message)) + } + + done = true + return null + } + + return { size, next } + } } class DeserializedErrorValue extends object.DeserializedMixin(ErrorValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.name = state[0] - } + constructor (state, recursor) { + super(state[1], recursor) + this.name = state[0] + } } diff --git a/lib/complexValues/function.js b/lib/complexValues/function.js index 690d948..0539fa4 100644 --- a/lib/complexValues/function.js +++ b/lib/complexValues/function.js @@ -6,110 +6,110 @@ import { NOOP_RECURSOR } from '../recursorUtils.js' import * as object from './object.js' export function describe (props) { - const fn = props.value - return new DescribedFunctionValue(Object.assign({ - nameIsEnumerable: isEnumerable(fn, 'name'), - name: typeof fn.name === 'string' ? fn.name : null, - }, props)) + const fn = props.value + return new DescribedFunctionValue(Object.assign({ + nameIsEnumerable: isEnumerable(fn, 'name'), + name: typeof fn.name === 'string' ? fn.name : null, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedFunctionValue(state, recursor) + return new DeserializedFunctionValue(state, recursor) } export const tag = Symbol('FunctionValue') class FunctionValue extends object.ObjectValue { - constructor (props) { - super(props) - this.name = props.name - } - - formatShallow (theme, indent) { - const string = formatUtils.wrap(theme.function.stringTag, this.stringTag) + - (this.name ? ' ' + formatUtils.wrap(theme.function.name, this.name) : '') + - ' ' + theme.object.openBracket - - return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { - return innerLines.isEmpty - ? lineBuilder.single(string + theme.object.closeBracket) - : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) - }, - - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) - }, - }) - } - - tag = tag + constructor (props) { + super(props) + this.name = props.name + } + + formatShallow (theme, indent) { + const string = formatUtils.wrap(theme.function.stringTag, this.stringTag) + + (this.name ? ' ' + formatUtils.wrap(theme.function.name, this.name) : '') + + ' ' + theme.object.openBracket + + return super.formatShallow(theme, indent).customize({ + finalize (innerLines) { + return innerLines.isEmpty + ? lineBuilder.single(string + theme.object.closeBracket) + : lineBuilder.first(string) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) + .append(lineBuilder.last(indent + theme.object.closeBracket)) + }, + + maxDepth () { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + }, + }) + } + + tag = tag } class DescribedFunctionValue extends object.DescribedMixin(FunctionValue) { - constructor (props) { - super(props) - this.nameIsEnumerable = props.nameIsEnumerable - } - - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.name !== expected.name) return UNEQUAL - if (this.value && expected.value && this.value !== expected.value) return UNEQUAL - - return super.compare(expected) - } - - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() - - const skipName = this.nameIsEnumerable - if (!skipName) return recursor - - let size = recursor.size - if (skipName) { - size -= 1 - } - - if (size === 0) return NOOP_RECURSOR - - const next = () => { - const property = recursor.next() - if (property) { - if (skipName && property.key.value === 'name') { - return next() - } - return property - } - - return null - } - - return { size, next } - } - - serialize () { - return [this.name, super.serialize()] - } + constructor (props) { + super(props) + this.nameIsEnumerable = props.nameIsEnumerable + } + + compare (expected) { + if (this.tag !== expected.tag) return UNEQUAL + if (this.name !== expected.name) return UNEQUAL + if (this.value && expected.value && this.value !== expected.value) return UNEQUAL + + return super.compare(expected) + } + + createPropertyRecursor () { + const recursor = super.createPropertyRecursor() + + const skipName = this.nameIsEnumerable + if (!skipName) return recursor + + let size = recursor.size + if (skipName) { + size -= 1 + } + + if (size === 0) return NOOP_RECURSOR + + const next = () => { + const property = recursor.next() + if (property) { + if (skipName && property.key.value === 'name') { + return next() + } + return property + } + + return null + } + + return { size, next } + } + + serialize () { + return [this.name, super.serialize()] + } } class DeserializedFunctionValue extends object.DeserializedMixin(FunctionValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.name = state[0] - } - - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.name !== expected.name) return UNEQUAL - if (this.stringTag !== expected.stringTag) return UNEQUAL - - return SHALLOW_EQUAL - } - - serialize () { - return [this.name, super.serialize()] - } + constructor (state, recursor) { + super(state[1], recursor) + this.name = state[0] + } + + compare (expected) { + if (this.tag !== expected.tag) return UNEQUAL + if (this.name !== expected.name) return UNEQUAL + if (this.stringTag !== expected.stringTag) return UNEQUAL + + return SHALLOW_EQUAL + } + + serialize () { + return [this.name, super.serialize()] + } } diff --git a/lib/complexValues/global.js b/lib/complexValues/global.js index 25b9c5b..3a34f4f 100644 --- a/lib/complexValues/global.js +++ b/lib/complexValues/global.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe () { - return new GlobalValue() + return new GlobalValue() } export const deserialize = describe @@ -11,18 +11,18 @@ export const deserialize = describe export const tag = Symbol('GlobalValue') class GlobalValue { - compare (expected) { - return this.tag === expected.tag - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return this.tag === expected.tag + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - return lineBuilder.single( - formatUtils.wrap(theme.global, 'Global') + ' ' + theme.object.openBracket + theme.object.closeBracket) - } + formatDeep (theme) { + return lineBuilder.single( + formatUtils.wrap(theme.global, 'Global') + ' ' + theme.object.openBracket + theme.object.closeBracket) + } - isComplex = true + isComplex = true - tag = tag + tag = tag } diff --git a/lib/complexValues/map.js b/lib/complexValues/map.js index c158324..a690921 100644 --- a/lib/complexValues/map.js +++ b/lib/complexValues/map.js @@ -3,69 +3,69 @@ import * as recursorUtils from '../recursorUtils.js' import * as object from './object.js' export function describe (props) { - return new DescribedMapValue(Object.assign({ - size: props.value.size, - }, props)) + return new DescribedMapValue(Object.assign({ + size: props.value.size, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedMapValue(state, recursor) + return new DeserializedMapValue(state, recursor) } export const tag = Symbol('MapValue') class MapValue extends object.ObjectValue { - constructor (props) { - super(props) - this.size = props.size - } + constructor (props) { + super(props) + this.size = props.size + } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare (expected) { + const result = super.compare(expected) + if (result !== SHALLOW_EQUAL) return result - return this.size === expected.size - ? SHALLOW_EQUAL - : UNEQUAL - } + return this.size === expected.size + ? SHALLOW_EQUAL + : UNEQUAL + } - prepareDiff (expected) { - // Maps should be compared, even if they have a different number of entries. - return { compareResult: super.compare(expected) } - } + prepareDiff (expected) { + // Maps should be compared, even if they have a different number of entries. + return { compareResult: super.compare(expected) } + } - serialize () { - return [this.size, super.serialize()] - } + serialize () { + return [this.size, super.serialize()] + } - tag = tag + tag = tag } class DescribedMapValue extends object.DescribedMixin(MapValue) { - createIterableRecursor () { - const size = this.size - if (size === 0) return recursorUtils.NOOP_RECURSOR + createIterableRecursor () { + const size = this.size + if (size === 0) return recursorUtils.NOOP_RECURSOR - let index = 0 - let entries - const next = () => { - if (index === size) return null + let index = 0 + let entries + const next = () => { + if (index === size) return null - if (!entries) { - entries = Array.from(this.value) - } + if (!entries) { + entries = Array.from(this.value) + } - const entry = entries[index++] - return this.describeMapEntry(this.describeAny(entry[0]), this.describeAny(entry[1])) - } + const entry = entries[index++] + return this.describeMapEntry(this.describeAny(entry[0]), this.describeAny(entry[1])) + } - return { size, next } - } + return { size, next } + } } class DeserializedMapValue extends object.DeserializedMixin(MapValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.size = state[0] - } + constructor (state, recursor) { + super(state[1], recursor) + this.size = state[0] + } } diff --git a/lib/complexValues/object.js b/lib/complexValues/object.js index ec214c7..4521047 100644 --- a/lib/complexValues/object.js +++ b/lib/complexValues/object.js @@ -6,239 +6,239 @@ import * as stats from '../metaDescriptors/stats.js' import * as recursorUtils from '../recursorUtils.js' export function describe (props) { - const isArray = props.stringTag === 'Array' - const object = props.value - return new DescribedObjectValue(Object.assign({ - isArray, - isIterable: object[Symbol.iterator] !== undefined, - isList: isArray || hasLength(object), - }, props)) + const isArray = props.stringTag === 'Array' + const object = props.value + return new DescribedObjectValue(Object.assign({ + isArray, + isIterable: object[Symbol.iterator] !== undefined, + isList: isArray || hasLength(object), + }, props)) } export function deserialize (state, recursor) { - return new DeserializedObjectValue(state, recursor) + return new DeserializedObjectValue(state, recursor) } export const tag = Symbol('ObjectValue') export class ObjectValue { - constructor (props) { - this.ctor = props.ctor - this.pointer = props.pointer - this.stringTag = props.stringTag - - this.isArray = props.isArray === true - this.isIterable = props.isIterable === true - this.isList = props.isList === true - } - - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.stringTag !== expected.stringTag || !this.hasSameCtor(expected)) return UNEQUAL - return SHALLOW_EQUAL - } - - hasSameCtor (expected) { - return this.ctor === expected.ctor - } - - formatShallow (theme, indent) { - return new ObjectFormatter(this, theme, indent) - } - - serialize () { - return [ - this.ctor, this.pointer, this.stringTag, - this.isArray, this.isIterable, this.isList, - ] - } - - isComplex = true - - tag = tag + constructor (props) { + this.ctor = props.ctor + this.pointer = props.pointer + this.stringTag = props.stringTag + + this.isArray = props.isArray === true + this.isIterable = props.isIterable === true + this.isList = props.isList === true + } + + compare (expected) { + if (this.tag !== expected.tag) return UNEQUAL + if (this.stringTag !== expected.stringTag || !this.hasSameCtor(expected)) return UNEQUAL + return SHALLOW_EQUAL + } + + hasSameCtor (expected) { + return this.ctor === expected.ctor + } + + formatShallow (theme, indent) { + return new ObjectFormatter(this, theme, indent) + } + + serialize () { + return [ + this.ctor, this.pointer, this.stringTag, + this.isArray, this.isIterable, this.isList, + ] + } + + isComplex = true + + tag = tag } const DescribedObjectValue = DescribedMixin(ObjectValue) const DeserializedObjectValue = DeserializedMixin(ObjectValue) export function DescribedMixin (base) { - return class extends base { - constructor (props) { - super(props) - - this.value = props.value - this.describeAny = props.describeAny - this.describeItem = props.describeItem - this.describeMapEntry = props.describeMapEntry - this.describeProperty = props.describeProperty - - this.iterableState = null - this.listState = null - this.propertyState = null - } - - compare (expected) { - return this.value === expected.value - ? DEEP_EQUAL - : super.compare(expected) - } - - createPropertyRecursor () { - const objectKeys = getObjectKeys(this.value, this.isList ? this.value.length : 0) - const size = objectKeys.size - if (size === 0) return recursorUtils.NOOP_RECURSOR - - let index = 0 - const next = () => { - if (index === size) return null - - const key = objectKeys.keys[index++] - return this.describeProperty(key, this.describeAny(this.value[key])) - } - - return { size, next } - } - - createListRecursor () { - if (!this.isList) return recursorUtils.NOOP_RECURSOR - - const size = this.value.length - if (size === 0) return recursorUtils.NOOP_RECURSOR - - let index = 0 - const next = () => { - if (index === size) return null - - const current = index - index++ - return this.describeItem(current, this.describeAny(this.value[current])) - } - - return { size, next } - } - - createIterableRecursor () { - if (this.isArray || !this.isIterable) return recursorUtils.NOOP_RECURSOR - - const iterator = this.value[Symbol.iterator]() - let first = iterator.next() - - let done = false - let size = -1 - if (first.done) { - if (first.value === undefined) { - size = 0 - done = true - } else { - size = 1 - } - } - - let index = 0 - const next = () => { - if (done) return null - - while (!done) { - const current = first || iterator.next() - if (current === first) { - first = null - } - if (current.done) { - done = true - } - - const item = current.value - if (done && item === undefined) return null - - if (this.isList && this.value[index] === item) { - index++ - } else { - return this.describeItem(index++, this.describeAny(item)) - } - } - } - - return { size, next } - } - - createRecursor () { - let recursedProperty = false - let recursedList = false - let recursedIterable = false - - let recursor = null - return () => { - let retval = null - do { - if (recursor !== null) { - retval = recursor.next() - if (retval === null) { - recursor = null - } - } - - while (recursor === null && (!recursedList || !recursedProperty || !recursedIterable)) { - // Prioritize recursing lists - if (!recursedList) { - const replay = recursorUtils.replay(this.listState, () => this.createListRecursor()) - this.listState = replay.state - recursor = replay.recursor - recursedList = true - if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describeListRecursor(recursor) - } - } else if (!recursedProperty) { - const replay = recursorUtils.replay(this.propertyState, () => this.createPropertyRecursor()) - this.propertyState = replay.state - recursor = replay.recursor - recursedProperty = true - if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describePropertyRecursor(recursor) - } - } else if (!recursedIterable) { - const replay = recursorUtils.replay(this.iterableState, () => this.createIterableRecursor()) - this.iterableState = replay.state - recursor = replay.recursor - recursedIterable = true - if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describeIterableRecursor(recursor) - } - } - } - } while (recursor !== null && retval === null) - - return retval - } - } - } + return class extends base { + constructor (props) { + super(props) + + this.value = props.value + this.describeAny = props.describeAny + this.describeItem = props.describeItem + this.describeMapEntry = props.describeMapEntry + this.describeProperty = props.describeProperty + + this.iterableState = null + this.listState = null + this.propertyState = null + } + + compare (expected) { + return this.value === expected.value + ? DEEP_EQUAL + : super.compare(expected) + } + + createPropertyRecursor () { + const objectKeys = getObjectKeys(this.value, this.isList ? this.value.length : 0) + const size = objectKeys.size + if (size === 0) return recursorUtils.NOOP_RECURSOR + + let index = 0 + const next = () => { + if (index === size) return null + + const key = objectKeys.keys[index++] + return this.describeProperty(key, this.describeAny(this.value[key])) + } + + return { size, next } + } + + createListRecursor () { + if (!this.isList) return recursorUtils.NOOP_RECURSOR + + const size = this.value.length + if (size === 0) return recursorUtils.NOOP_RECURSOR + + let index = 0 + const next = () => { + if (index === size) return null + + const current = index + index++ + return this.describeItem(current, this.describeAny(this.value[current])) + } + + return { size, next } + } + + createIterableRecursor () { + if (this.isArray || !this.isIterable) return recursorUtils.NOOP_RECURSOR + + const iterator = this.value[Symbol.iterator]() + let first = iterator.next() + + let done = false + let size = -1 + if (first.done) { + if (first.value === undefined) { + size = 0 + done = true + } else { + size = 1 + } + } + + let index = 0 + const next = () => { + if (done) return null + + while (!done) { + const current = first || iterator.next() + if (current === first) { + first = null + } + if (current.done) { + done = true + } + + const item = current.value + if (done && item === undefined) return null + + if (this.isList && this.value[index] === item) { + index++ + } else { + return this.describeItem(index++, this.describeAny(item)) + } + } + } + + return { size, next } + } + + createRecursor () { + let recursedProperty = false + let recursedList = false + let recursedIterable = false + + let recursor = null + return () => { + let retval = null + do { + if (recursor !== null) { + retval = recursor.next() + if (retval === null) { + recursor = null + } + } + + while (recursor === null && (!recursedList || !recursedProperty || !recursedIterable)) { + // Prioritize recursing lists + if (!recursedList) { + const replay = recursorUtils.replay(this.listState, () => this.createListRecursor()) + this.listState = replay.state + recursor = replay.recursor + recursedList = true + if (recursor !== recursorUtils.NOOP_RECURSOR) { + retval = stats.describeListRecursor(recursor) + } + } else if (!recursedProperty) { + const replay = recursorUtils.replay(this.propertyState, () => this.createPropertyRecursor()) + this.propertyState = replay.state + recursor = replay.recursor + recursedProperty = true + if (recursor !== recursorUtils.NOOP_RECURSOR) { + retval = stats.describePropertyRecursor(recursor) + } + } else if (!recursedIterable) { + const replay = recursorUtils.replay(this.iterableState, () => this.createIterableRecursor()) + this.iterableState = replay.state + recursor = replay.recursor + recursedIterable = true + if (recursor !== recursorUtils.NOOP_RECURSOR) { + retval = stats.describeIterableRecursor(recursor) + } + } + } + } while (recursor !== null && retval === null) + + return retval + } + } + } } export function DeserializedMixin (base) { - return class extends base { - constructor (state, recursor) { - super({ - ctor: state[0], - pointer: state[1], - stringTag: state[2], - isArray: state[3], - isIterable: state[4], - isList: state[5], - }) - - this.deserializedRecursor = recursor - this.replayState = null - } - - createRecursor () { - if (!this.deserializedRecursor) return () => null - - const replay = recursorUtils.replay(this.replayState, () => ({ size: -1, next: this.deserializedRecursor })) - this.replayState = replay.state - return replay.recursor.next - } - - hasSameCtor (expected) { - return this.ctor === expected.ctor - } - } + return class extends base { + constructor (state, recursor) { + super({ + ctor: state[0], + pointer: state[1], + stringTag: state[2], + isArray: state[3], + isIterable: state[4], + isList: state[5], + }) + + this.deserializedRecursor = recursor + this.replayState = null + } + + createRecursor () { + if (!this.deserializedRecursor) return () => null + + const replay = recursorUtils.replay(this.replayState, () => ({ size: -1, next: this.deserializedRecursor })) + this.replayState = replay.state + return replay.recursor.next + } + + hasSameCtor (expected) { + return this.ctor === expected.ctor + } + } } diff --git a/lib/complexValues/promise.js b/lib/complexValues/promise.js index 291b414..69bf85e 100644 --- a/lib/complexValues/promise.js +++ b/lib/complexValues/promise.js @@ -2,32 +2,32 @@ import {DEEP_EQUAL, UNEQUAL} from '../constants.js' import * as object from './object.js' export function describe (props) { - return new DescribedPromiseValue(props) + return new DescribedPromiseValue(props) } export function deserialize (props) { - return new DeserializedPromiseValue(props) + return new DeserializedPromiseValue(props) } export const tag = Symbol('PromiseValue') class PromiseValue extends object.ObjectValue { - tag = tag + tag = tag } class DescribedPromiseValue extends object.DescribedMixin(PromiseValue) { - compare (expected) { - // When comparing described promises, require them to be the exact same - // object. - return super.compare(expected) === DEEP_EQUAL - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + // When comparing described promises, require them to be the exact same + // object. + return super.compare(expected) === DEEP_EQUAL + ? DEEP_EQUAL + : UNEQUAL + } } class DeserializedPromiseValue extends object.DeserializedMixin(PromiseValue) { - compare (expected) { - // Deserialized promises can never be compared using object references. - return super.compare(expected) - } + compare (expected) { + // Deserialized promises can never be compared using object references. + return super.compare(expected) + } } diff --git a/lib/complexValues/regexp.js b/lib/complexValues/regexp.js index 2750086..9c8c0b4 100644 --- a/lib/complexValues/regexp.js +++ b/lib/complexValues/regexp.js @@ -4,81 +4,81 @@ import lineBuilder from '../lineBuilder.js' import * as object from './object.js' export function describe (props) { - const regexp = props.value - return new DescribedRegexpValue(Object.assign({ - flags: getSortedFlags(regexp), - source: regexp.source, - }, props)) + const regexp = props.value + return new DescribedRegexpValue(Object.assign({ + flags: getSortedFlags(regexp), + source: regexp.source, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedRegexpValue(state, recursor) + return new DeserializedRegexpValue(state, recursor) } export const tag = Symbol('RegexpValue') function getSortedFlags (regexp) { - const flags = regexp.flags || String(regexp).slice(regexp.source.length + 2) - return flags.split('').sort().join('') + const flags = regexp.flags || String(regexp).slice(regexp.source.length + 2) + return flags.split('').sort().join('') } class RegexpValue extends object.ObjectValue { - constructor (props) { - super(props) - this.flags = props.flags - this.source = props.source - } - - compare (expected) { - return this.tag === expected.tag && this.flags === expected.flags && this.source === expected.source - ? super.compare(expected) - : UNEQUAL - } - - formatShallow (theme, indent) { - const ctor = this.ctor || this.stringTag - const regexp = formatUtils.wrap(theme.regexp.source, this.source) + formatUtils.wrap(theme.regexp.flags, this.flags) - - return super.formatShallow(theme, indent).customize({ - finalize: innerLines => { - if (ctor === 'RegExp' && innerLines.isEmpty) return lineBuilder.single(regexp) - - const innerIndentation = indent.increase() - const header = lineBuilder.first(formatUtils.formatCtorAndStringTag(theme, this) + ' ' + theme.object.openBracket) - .concat(lineBuilder.line(innerIndentation + regexp)) - - if (!innerLines.isEmpty) { - header.append(lineBuilder.line(innerIndentation + theme.regexp.separator)) - header.append(innerLines.withFirstPrefixed(innerIndentation).stripFlags()) - } - - return header.append(lineBuilder.last(indent + theme.object.closeBracket)) - }, - - maxDepth: () => { - return lineBuilder.single( - formatUtils.formatCtorAndStringTag(theme, this) + ' ' + - theme.object.openBracket + ' ' + - regexp + ' ' + - theme.maxDepth + ' ' + - theme.object.closeBracket) - }, - }) - } - - serialize () { - return [this.flags, this.source, super.serialize()] - } - - tag = tag + constructor (props) { + super(props) + this.flags = props.flags + this.source = props.source + } + + compare (expected) { + return this.tag === expected.tag && this.flags === expected.flags && this.source === expected.source + ? super.compare(expected) + : UNEQUAL + } + + formatShallow (theme, indent) { + const ctor = this.ctor || this.stringTag + const regexp = formatUtils.wrap(theme.regexp.source, this.source) + formatUtils.wrap(theme.regexp.flags, this.flags) + + return super.formatShallow(theme, indent).customize({ + finalize: innerLines => { + if (ctor === 'RegExp' && innerLines.isEmpty) return lineBuilder.single(regexp) + + const innerIndentation = indent.increase() + const header = lineBuilder.first(formatUtils.formatCtorAndStringTag(theme, this) + ' ' + theme.object.openBracket) + .concat(lineBuilder.line(innerIndentation + regexp)) + + if (!innerLines.isEmpty) { + header.append(lineBuilder.line(innerIndentation + theme.regexp.separator)) + header.append(innerLines.withFirstPrefixed(innerIndentation).stripFlags()) + } + + return header.append(lineBuilder.last(indent + theme.object.closeBracket)) + }, + + maxDepth: () => { + return lineBuilder.single( + formatUtils.formatCtorAndStringTag(theme, this) + ' ' + + theme.object.openBracket + ' ' + + regexp + ' ' + + theme.maxDepth + ' ' + + theme.object.closeBracket) + }, + }) + } + + serialize () { + return [this.flags, this.source, super.serialize()] + } + + tag = tag } const DescribedRegexpValue = object.DescribedMixin(RegexpValue) class DeserializedRegexpValue extends object.DeserializedMixin(RegexpValue) { - constructor (state, recursor) { - super(state[2], recursor) - this.flags = state[0] - this.source = state[1] - } + constructor (state, recursor) { + super(state[2], recursor) + this.flags = state[0] + this.source = state[1] + } } diff --git a/lib/complexValues/set.js b/lib/complexValues/set.js index b9d3e42..c78689b 100644 --- a/lib/complexValues/set.js +++ b/lib/complexValues/set.js @@ -3,69 +3,69 @@ import * as recursorUtils from '../recursorUtils.js' import * as object from './object.js' export function describe (props) { - return new DescribedSetValue(Object.assign({ - size: props.value.size, - }, props)) + return new DescribedSetValue(Object.assign({ + size: props.value.size, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedSetValue(state, recursor) + return new DeserializedSetValue(state, recursor) } export const tag = Symbol('SetValue') class SetValue extends object.ObjectValue { - constructor (props) { - super(props) - this.size = props.size - } + constructor (props) { + super(props) + this.size = props.size + } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare (expected) { + const result = super.compare(expected) + if (result !== SHALLOW_EQUAL) return result - return this.size === expected.size - ? SHALLOW_EQUAL - : UNEQUAL - } + return this.size === expected.size + ? SHALLOW_EQUAL + : UNEQUAL + } - prepareDiff (expected) { - // Sets should be compared, even if they have a different number of items. - return { compareResult: super.compare(expected) } - } + prepareDiff (expected) { + // Sets should be compared, even if they have a different number of items. + return { compareResult: super.compare(expected) } + } - serialize () { - return [this.size, super.serialize()] - } + serialize () { + return [this.size, super.serialize()] + } - tag = tag + tag = tag } class DescribedSetValue extends object.DescribedMixin(SetValue) { - createIterableRecursor () { - const size = this.size - if (size === 0) return recursorUtils.NOOP_RECURSOR + createIterableRecursor () { + const size = this.size + if (size === 0) return recursorUtils.NOOP_RECURSOR - let index = 0 - let members - const next = () => { - if (index === size) return null + let index = 0 + let members + const next = () => { + if (index === size) return null - if (!members) { - members = Array.from(this.value) - } + if (!members) { + members = Array.from(this.value) + } - const value = members[index] - return this.describeItem(index++, this.describeAny(value)) - } + const value = members[index] + return this.describeItem(index++, this.describeAny(value)) + } - return { size, next } - } + return { size, next } + } } class DeserializedSetValue extends object.DeserializedMixin(SetValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.size = state[0] - } + constructor (state, recursor) { + super(state[1], recursor) + this.size = state[0] + } } diff --git a/lib/complexValues/typedArray.js b/lib/complexValues/typedArray.js index 208842c..ad7a4f7 100644 --- a/lib/complexValues/typedArray.js +++ b/lib/complexValues/typedArray.js @@ -6,27 +6,27 @@ import * as recursorUtils from '../recursorUtils.js' import * as object from './object.js' export function getBuffer (value) { - const buffer = Buffer.from(value.buffer) - return value.byteLength !== value.buffer.byteLength - ? buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) - : buffer + const buffer = Buffer.from(value.buffer) + return value.byteLength !== value.buffer.byteLength + ? buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) + : buffer } export function describe (props) { - return new DescribedTypedArrayValue(Object.assign({ - buffer: getBuffer(props.value), - // Set isArray and isList so the property recursor excludes the byte accessors - isArray: true, - isList: true, - }, props)) + return new DescribedTypedArrayValue(Object.assign({ + buffer: getBuffer(props.value), + // Set isArray and isList so the property recursor excludes the byte accessors + isArray: true, + isList: true, + }, props)) } export function deserialize (state, recursor) { - return new DeserializedTypedArrayValue(state, recursor) + return new DeserializedTypedArrayValue(state, recursor) } export function deserializeBytes (buffer) { - return new Bytes(buffer) + return new Bytes(buffer) } export const bytesTag = Symbol('Bytes') @@ -34,116 +34,116 @@ export const bytesTag = Symbol('Bytes') export const tag = Symbol('TypedArrayValue') class Bytes { - constructor (buffer) { - this.buffer = buffer - } - - compare (expected) { - return expected.tag === bytesTag && this.buffer.equals(expected.buffer) - ? DEEP_EQUAL - : UNEQUAL - } - - formatDeep (theme, indent) { - const indentation = indent - const lines = lineBuilder.buffer() - - // Display 4-byte words, 8 per line - let string = '' - let isFirst = true - for (let offset = 0; offset < this.buffer.length; offset += 4) { - if (offset > 0) { - if (offset % 32 === 0) { - if (isFirst) { - lines.append(lineBuilder.first(string)) - isFirst = false - } else { - lines.append(lineBuilder.line(string)) - } - string = String(indentation) - } else { - string += ' ' - } - } - string += formatUtils.wrap(theme.typedArray.bytes, this.buffer.toString('hex', offset, offset + 4)) - } - - return isFirst - ? lineBuilder.single(string) - : lines.append(lineBuilder.last(string)) - } - - serialize () { - return this.buffer - } - - tag = bytesTag + constructor (buffer) { + this.buffer = buffer + } + + compare (expected) { + return expected.tag === bytesTag && this.buffer.equals(expected.buffer) + ? DEEP_EQUAL + : UNEQUAL + } + + formatDeep (theme, indent) { + const indentation = indent + const lines = lineBuilder.buffer() + + // Display 4-byte words, 8 per line + let string = '' + let isFirst = true + for (let offset = 0; offset < this.buffer.length; offset += 4) { + if (offset > 0) { + if (offset % 32 === 0) { + if (isFirst) { + lines.append(lineBuilder.first(string)) + isFirst = false + } else { + lines.append(lineBuilder.line(string)) + } + string = String(indentation) + } else { + string += ' ' + } + } + string += formatUtils.wrap(theme.typedArray.bytes, this.buffer.toString('hex', offset, offset + 4)) + } + + return isFirst + ? lineBuilder.single(string) + : lines.append(lineBuilder.last(string)) + } + + serialize () { + return this.buffer + } + + tag = bytesTag } export class TypedArrayValue extends object.ObjectValue { - constructor (props) { - super(props) - this.buffer = props.buffer - } - - formatShallow (theme, indent) { - return super.formatShallow(theme, indent).customize({ - shouldFormat (subject) { - if (subject.tag === propertyStatsTag) return subject.size > 1 - if (subject.isProperty === true) return subject.key.value !== 'byteLength' - if (subject.tag === bytesTag) return subject.buffer.byteLength > 0 - return true - }, - }) - } - - tag = tag + constructor (props) { + super(props) + this.buffer = props.buffer + } + + formatShallow (theme, indent) { + return super.formatShallow(theme, indent).customize({ + shouldFormat (subject) { + if (subject.tag === propertyStatsTag) return subject.size > 1 + if (subject.isProperty === true) return subject.key.value !== 'byteLength' + if (subject.tag === bytesTag) return subject.buffer.byteLength > 0 + return true + }, + }) + } + + tag = tag } export function DescribedMixin (base) { - return class extends object.DescribedMixin(base) { - // The list isn't recursed. Instead a Bytes instance is returned by the main - // recursor. - createListRecursor () { - return recursorUtils.NOOP_RECURSOR - } - - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() - const size = recursor.size + 1 - - let done = false - const next = () => { - if (done) return null - - const property = recursor.next() - if (property) return property - - done = true - return this.describeProperty('byteLength', this.describeAny(this.buffer.byteLength)) - } - - return { size, next } - } - - createRecursor () { - return recursorUtils.unshift(super.createRecursor(), new Bytes(this.buffer)) - } - } + return class extends object.DescribedMixin(base) { + // The list isn't recursed. Instead a Bytes instance is returned by the main + // recursor. + createListRecursor () { + return recursorUtils.NOOP_RECURSOR + } + + createPropertyRecursor () { + const recursor = super.createPropertyRecursor() + const size = recursor.size + 1 + + let done = false + const next = () => { + if (done) return null + + const property = recursor.next() + if (property) return property + + done = true + return this.describeProperty('byteLength', this.describeAny(this.buffer.byteLength)) + } + + return { size, next } + } + + createRecursor () { + return recursorUtils.unshift(super.createRecursor(), new Bytes(this.buffer)) + } + } } const DescribedTypedArrayValue = DescribedMixin(TypedArrayValue) export function DeserializedMixin (base) { - return class extends object.DeserializedMixin(base) { - constructor (state, recursor) { - super(state, recursor) - - // Get the Bytes descriptor from the recursor. It contains the buffer. - const bytesDescriptor = this.createRecursor()() - this.buffer = bytesDescriptor.buffer - } - } + return class extends object.DeserializedMixin(base) { + constructor (state, recursor) { + super(state, recursor) + + // Get the Bytes descriptor from the recursor. It contains the buffer. + const bytesDescriptor = this.createRecursor()() + this.buffer = bytesDescriptor.buffer + } + } } const DeserializedTypedArrayValue = DeserializedMixin(TypedArrayValue) diff --git a/lib/describe.js b/lib/describe.js index fe8cdcb..25baca4 100644 --- a/lib/describe.js +++ b/lib/describe.js @@ -30,139 +30,139 @@ import * as symbolValue from './primitiveValues/symbol.js' import * as undefinedValue from './primitiveValues/undefined.js' const SpecializedComplexes = new Map([ - ['Arguments', argumentsValue.describe], - ['ArrayBuffer', arrayBufferValue.describe], - ['DataView', dataViewValue.describe], - ['Date', dateValue.describe], - ['Error', errorValue.describe], - ['Float32Array', typedArrayValue.describe], - ['Float64Array', typedArrayValue.describe], - ['Function', functionValue.describe], - ['GeneratorFunction', functionValue.describe], - ['global', globalValue.describe], - ['Int16Array', typedArrayValue.describe], - ['Int32Array', typedArrayValue.describe], - ['Int8Array', typedArrayValue.describe], - ['Map', mapValue.describe], - ['Promise', promiseValue.describe], - ['RegExp', regexpValue.describe], - ['Set', setValue.describe], - ['Uint16Array', typedArrayValue.describe], - ['Uint32Array', typedArrayValue.describe], - ['Uint8Array', typedArrayValue.describe], - ['Uint8ClampedArray', typedArrayValue.describe], + ['Arguments', argumentsValue.describe], + ['ArrayBuffer', arrayBufferValue.describe], + ['DataView', dataViewValue.describe], + ['Date', dateValue.describe], + ['Error', errorValue.describe], + ['Float32Array', typedArrayValue.describe], + ['Float64Array', typedArrayValue.describe], + ['Function', functionValue.describe], + ['GeneratorFunction', functionValue.describe], + ['global', globalValue.describe], + ['Int16Array', typedArrayValue.describe], + ['Int32Array', typedArrayValue.describe], + ['Int8Array', typedArrayValue.describe], + ['Map', mapValue.describe], + ['Promise', promiseValue.describe], + ['RegExp', regexpValue.describe], + ['Set', setValue.describe], + ['Uint16Array', typedArrayValue.describe], + ['Uint32Array', typedArrayValue.describe], + ['Uint8Array', typedArrayValue.describe], + ['Uint8ClampedArray', typedArrayValue.describe], ]) function describePrimitive (value) { - if (value === null) return nullValue.describe() - if (value === undefined) return undefinedValue.describe() - if (value === true || value === false) return booleanValue.describe(value) + if (value === null) return nullValue.describe() + if (value === undefined) return undefinedValue.describe() + if (value === true || value === false) return booleanValue.describe(value) - const type = typeof value - if (type === 'bigint') return bigIntValue.describe(value) - if (type === 'number') return numberValue.describe(value) - if (type === 'string') return stringValue.describe(value) - if (type === 'symbol') return symbolValue.describe(value) + const type = typeof value + if (type === 'bigint') return bigIntValue.describe(value) + if (type === 'number') return numberValue.describe(value) + if (type === 'string') return stringValue.describe(value) + if (type === 'symbol') return symbolValue.describe(value) - return null + return null } function unboxComplex (tag, complex) { - // Try to unbox by calling `valueOf()`. `describePrimitive()` will return - // `null` if the resulting value is not a primitive, in which case it's - // ignored. - if (typeof complex.valueOf === 'function') { - const value = complex.valueOf() - if (value !== complex) return describePrimitive(value) - } - - return null + // Try to unbox by calling `valueOf()`. `describePrimitive()` will return + // `null` if the resulting value is not a primitive, in which case it's + // ignored. + if (typeof complex.valueOf === 'function') { + const value = complex.valueOf() + if (value !== complex) return describePrimitive(value) + } + + return null } function registerPlugins (plugins) { - if (!Array.isArray(plugins) || plugins.length === 0) return () => null + if (!Array.isArray(plugins) || plugins.length === 0) return () => null - const tryFns = pluginRegistry.getTryDescribeValues(plugins) - return (value, stringTag, ctor) => { - for (const tryDescribeValue of tryFns) { - const describeValue = tryDescribeValue(value, stringTag, ctor) - if (describeValue) return describeValue - } + const tryFns = pluginRegistry.getTryDescribeValues(plugins) + return (value, stringTag, ctor) => { + for (const tryDescribeValue of tryFns) { + const describeValue = tryDescribeValue(value, stringTag, ctor) + if (describeValue) return describeValue + } - return null - } + return null + } } function describeComplex (value, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) { - if (registry.has(value)) return registry.get(value) - - const stringTag = getStringTag(value) - const ctor = getCtor(stringTag, value) - const pointer = registry.alloc(value) - - let unboxed - let describeValue = tryPlugins(value, stringTag, ctor) - if (describeValue === null) { - if (SpecializedComplexes.has(stringTag)) { - describeValue = SpecializedComplexes.get(stringTag) - } else { - unboxed = unboxComplex(stringTag, value) - if (unboxed !== null) { - describeValue = boxedValue.describe - } else { - describeValue = objectValue.describe - } - } - } - - const descriptor = describeValue({ - ctor, - describeAny, - describeItem, - describeMapEntry, - describeProperty, - pointer: pointer.index, - stringTag, - unboxed, - value, - }) - pointer.descriptor = descriptor - return descriptor + if (registry.has(value)) return registry.get(value) + + const stringTag = getStringTag(value) + const ctor = getCtor(stringTag, value) + const pointer = registry.alloc(value) + + let unboxed + let describeValue = tryPlugins(value, stringTag, ctor) + if (describeValue === null) { + if (SpecializedComplexes.has(stringTag)) { + describeValue = SpecializedComplexes.get(stringTag) + } else { + unboxed = unboxComplex(stringTag, value) + if (unboxed !== null) { + describeValue = boxedValue.describe + } else { + describeValue = objectValue.describe + } + } + } + + const descriptor = describeValue({ + ctor, + describeAny, + describeItem, + describeMapEntry, + describeProperty, + pointer: pointer.index, + stringTag, + unboxed, + value, + }) + pointer.descriptor = descriptor + return descriptor } const describeItem = (index, valueDescriptor) => { - return valueDescriptor.isPrimitive === true - ? itemDescriptor.describePrimitive(index, valueDescriptor) - : itemDescriptor.describeComplex(index, valueDescriptor) + return valueDescriptor.isPrimitive === true + ? itemDescriptor.describePrimitive(index, valueDescriptor) + : itemDescriptor.describeComplex(index, valueDescriptor) } const describeMapEntry = (keyDescriptor, valueDescriptor) => { - return mapEntryDescriptor.describe(keyDescriptor, valueDescriptor) + return mapEntryDescriptor.describe(keyDescriptor, valueDescriptor) } export default function describe (value, options) { - const primitive = describePrimitive(value) - if (primitive !== null) return primitive - - const registry = new Registry() - const tryPlugins = registerPlugins(options && options.plugins) - const curriedComplex = c => { - return describeComplex(c, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) - } - - const describeAny = any => { - const descriptor = describePrimitive(any) - return descriptor !== null - ? descriptor - : curriedComplex(any) - } - - const describeProperty = (key, valueDescriptor) => { - const keyDescriptor = describePrimitive(key) - return valueDescriptor.isPrimitive === true - ? propertyDescriptor.describePrimitive(keyDescriptor, valueDescriptor) - : propertyDescriptor.describeComplex(keyDescriptor, valueDescriptor) - } - - return curriedComplex(value) + const primitive = describePrimitive(value) + if (primitive !== null) return primitive + + const registry = new Registry() + const tryPlugins = registerPlugins(options && options.plugins) + const curriedComplex = c => { + return describeComplex(c, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) + } + + const describeAny = any => { + const descriptor = describePrimitive(any) + return descriptor !== null + ? descriptor + : curriedComplex(any) + } + + const describeProperty = (key, valueDescriptor) => { + const keyDescriptor = describePrimitive(key) + return valueDescriptor.isPrimitive === true + ? propertyDescriptor.describePrimitive(keyDescriptor, valueDescriptor) + : propertyDescriptor.describeComplex(keyDescriptor, valueDescriptor) + } + + return curriedComplex(value) } diff --git a/lib/diff.js b/lib/diff.js index 94144cf..d0e2037 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -13,371 +13,371 @@ const NOOP = Symbol('NOOP') const alwaysFormat = () => true function compareComplexShape (lhs, rhs) { - let result = lhs.compare(rhs) - if (result === DEEP_EQUAL) return DEEP_EQUAL - if (result === UNEQUAL || !shouldCompareDeep(result, lhs, rhs)) return UNEQUAL - - let collectedSymbolProperties = false - let lhsRecursor = lhs.createRecursor() - let rhsRecursor = rhs.createRecursor() - - do { - lhs = lhsRecursor() - rhs = rhsRecursor() - - if (lhs === null && rhs === null) return SHALLOW_EQUAL - if (lhs === null || rhs === null) return UNEQUAL - - result = lhs.compare(rhs) - if (result === UNEQUAL) return UNEQUAL - if ( - result === AMBIGUOUS && - lhs.isProperty === true && !collectedSymbolProperties && - shouldCompareDeep(result, lhs, rhs) - ) { - collectedSymbolProperties = true - const lhsCollector = new symbolProperties.Collector(lhs, lhsRecursor) - const rhsCollector = new symbolProperties.Collector(rhs, rhsRecursor) - - lhsRecursor = recursorUtils.sequence( - lhsCollector.createRecursor(), - recursorUtils.unshift(lhsRecursor, lhsCollector.collectAll())) - rhsRecursor = recursorUtils.sequence( - rhsCollector.createRecursor(), - recursorUtils.unshift(rhsRecursor, rhsCollector.collectAll())) - } - } while (true) + let result = lhs.compare(rhs) + if (result === DEEP_EQUAL) return DEEP_EQUAL + if (result === UNEQUAL || !shouldCompareDeep(result, lhs, rhs)) return UNEQUAL + + let collectedSymbolProperties = false + let lhsRecursor = lhs.createRecursor() + let rhsRecursor = rhs.createRecursor() + + do { + lhs = lhsRecursor() + rhs = rhsRecursor() + + if (lhs === null && rhs === null) return SHALLOW_EQUAL + if (lhs === null || rhs === null) return UNEQUAL + + result = lhs.compare(rhs) + if (result === UNEQUAL) return UNEQUAL + if ( + result === AMBIGUOUS && + lhs.isProperty === true && !collectedSymbolProperties && + shouldCompareDeep(result, lhs, rhs) + ) { + collectedSymbolProperties = true + const lhsCollector = new symbolProperties.Collector(lhs, lhsRecursor) + const rhsCollector = new symbolProperties.Collector(rhs, rhsRecursor) + + lhsRecursor = recursorUtils.sequence( + lhsCollector.createRecursor(), + recursorUtils.unshift(lhsRecursor, lhsCollector.collectAll())) + rhsRecursor = recursorUtils.sequence( + rhsCollector.createRecursor(), + recursorUtils.unshift(rhsRecursor, rhsCollector.collectAll())) + } + } while (true) } export function diffDescriptors (lhs, rhs, options) { - const theme = themeUtils.normalize(options) - const invert = options ? options.invert === true : false - - const lhsCircular = new Circular() - const rhsCircular = new Circular() - const maxDepth = (options && options.maxDepth) || 0 - - let indent = new Indenter(0, ' ') - - const lhsStack = [] - const rhsStack = [] - let topIndex = -1 - - const buffer = lineBuilder.buffer() - const diffStack = [] - let diffIndex = -1 - - const isCircular = descriptor => lhsCircular.has(descriptor) || rhsCircular.has(descriptor) - - const format = (builder, subject, circular, depthOffset = 0) => { - if (diffIndex >= 0 && !diffStack[diffIndex].shouldFormat(subject)) return - - if (circular.has(subject)) { - diffStack[diffIndex].formatter.append(builder.single(theme.circular)) - return - } - - const formatStack = [] - let formatIndex = -1 - - do { - if (circular.has(subject)) { - formatStack[formatIndex].formatter.append(builder.single(theme.circular), subject) - } else { - let didFormat = false - if (typeof subject.formatDeep === 'function') { - let formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) - if (formatted !== null) { - didFormat = true - - if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) - if (diffIndex === -1) { - buffer.append(formatted) - } else { - diffStack[diffIndex].formatter.append(formatted, subject) - } - } else { - formatStack[formatIndex].formatter.append(formatted, subject) - } - } - } - - if (!didFormat && typeof subject.formatShallow === 'function') { - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const recursor = subject.createRecursor() - - if (formatter.increaseIndent && maxDepth > 0 && indent.level === (maxDepth + depthOffset)) { - const isEmpty = recursor() === null - let formatted = !isEmpty && typeof formatter.maxDepth === 'function' - ? formatter.maxDepth() - : formatter.finalize() - - if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) - diffStack[diffIndex].formatter.append(formatted, subject) - } else { - formatStack[formatIndex].formatter.append(formatted, subject) - } - } else { - formatStack.push({ - formatter, - recursor, - decreaseIndent: formatter.increaseIndent, - shouldFormat: formatter.shouldFormat || alwaysFormat, - subject, - }) - formatIndex++ - - if (formatter.increaseIndent) indent = indent.increase() - circular.add(subject) - } - } - } - - while (formatIndex >= 0) { - do { - subject = formatStack[formatIndex].recursor() - } while (subject && !formatStack[formatIndex].shouldFormat(subject)) - - if (subject) { - break - } - - const record = formatStack.pop() - formatIndex-- - if (record.decreaseIndent) indent = indent.decrease() - circular.delete(record.subject) - - let formatted = record.formatter.finalize() - if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) - if (diffIndex === -1) { - buffer.append(formatted) - } else { - diffStack[diffIndex].formatter.append(formatted, record.subject) - } - } else { - formatStack[formatIndex].formatter.append(formatted, record.subject) - } - } - } while (formatIndex >= 0) - } - - do { - let compareResult = NOOP - if (lhsCircular.has(lhs)) { - compareResult = lhsCircular.get(lhs) === rhsCircular.get(rhs) - ? DEEP_EQUAL - : UNEQUAL - } else if (rhsCircular.has(rhs)) { - compareResult = UNEQUAL - } - - let firstPassSymbolProperty = false - if (lhs.isProperty === true) { - compareResult = lhs.compare(rhs) - if (compareResult === AMBIGUOUS) { - const parent = lhsStack[topIndex].subject - firstPassSymbolProperty = parent.isSymbolPropertiesCollector !== true && parent.isSymbolPropertiesComparable !== true - } - } - - let didFormat = false - let mustRecurse = false - if (compareResult !== DEEP_EQUAL && !firstPassSymbolProperty && typeof lhs.prepareDiff === 'function') { - const lhsRecursor = topIndex === -1 ? null : lhsStack[topIndex].recursor - const rhsRecursor = topIndex === -1 ? null : rhsStack[topIndex].recursor - - const instructions = lhs.prepareDiff( - rhs, - lhsRecursor, - rhsRecursor, - compareComplexShape, - isCircular) - - if (instructions !== null) { - if (topIndex >= 0) { - if (typeof instructions.lhsRecursor === 'function') { - lhsStack[topIndex].recursor = instructions.lhsRecursor - } - if (typeof instructions.rhsRecursor === 'function') { - rhsStack[topIndex].recursor = instructions.rhsRecursor - } - } - - if (instructions.compareResult) { - compareResult = instructions.compareResult - } - if (instructions.mustRecurse === true) { - mustRecurse = true - } else { - if (instructions.actualIsExtraneous === true) { - format(lineBuilder.actual, lhs, lhsCircular) - didFormat = true - } else if (instructions.multipleAreExtraneous === true) { - for (const extraneous of instructions.descriptors) { - format(lineBuilder.actual, extraneous, lhsCircular) - } - didFormat = true - } else if (instructions.expectedIsMissing === true) { - format(lineBuilder.expected, rhs, rhsCircular) - didFormat = true - } else if (instructions.multipleAreMissing === true) { - for (const missing of instructions.descriptors) { - format(lineBuilder.expected, missing, rhsCircular) - } - didFormat = true - } else if (instructions.isUnequal === true) { - format(lineBuilder.actual, lhs, lhsCircular) - format(lineBuilder.expected, rhs, rhsCircular) - didFormat = true - } else if (!instructions.compareResult) { - // TODO: Throw a useful, custom error - throw new Error('Illegal result of prepareDiff()') - } - } - } - } - - if (!didFormat) { - if (compareResult === NOOP) { - compareResult = lhs.compare(rhs) - } - - if (!mustRecurse) { - mustRecurse = shouldCompareDeep(compareResult, lhs, rhs) - } - - if (compareResult === DEEP_EQUAL) { - format(lineBuilder, lhs, lhsCircular) - } else if (mustRecurse) { - if (compareResult === AMBIGUOUS && lhs.isProperty === true) { - // Replace both sides by a pseudo-descriptor which collects symbol - // properties instead. - lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) - rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) - // Replace the current recursors so they can continue correctly after - // the collectors have been "compared". This is necessary since the - // collectors eat the first value after the last symbol property. - lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) - rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) - } - - if (typeof lhs.diffShallow === 'function') { - const formatter = lhs.diffShallow(rhs, themeUtils.applyModifiers(lhs, theme), indent) - diffStack.push({ - formatter, - origin: lhs, - decreaseIndent: formatter.increaseIndent, - exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, - shouldFormat: formatter.shouldFormat || alwaysFormat, - }) - diffIndex++ - - if (formatter.increaseIndent) indent = indent.increase() - } else if (typeof lhs.formatShallow === 'function') { - const formatter = lhs.formatShallow(themeUtils.applyModifiers(lhs, theme), indent) - diffStack.push({ - formatter, - decreaseIndent: formatter.increaseIndent, - exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, - shouldFormat: formatter.shouldFormat || alwaysFormat, - subject: lhs, - }) - diffIndex++ - - if (formatter.increaseIndent) indent = indent.increase() - } - - lhsCircular.add(lhs) - rhsCircular.add(rhs) - - lhsStack.push({ diffIndex, subject: lhs, recursor: lhs.createRecursor() }) - rhsStack.push({ diffIndex, subject: rhs, recursor: rhs.createRecursor() }) - topIndex++ - } else { - const diffed = typeof lhs.diffDeep === 'function' - ? lhs.diffDeep(rhs, themeUtils.applyModifiers(lhs, theme), indent, invert) - : null - - if (diffed === null) { - format(lineBuilder.actual, lhs, lhsCircular) - format(lineBuilder.expected, rhs, rhsCircular) - } else { - if (diffIndex === -1) { - buffer.append(diffed) - } else { - diffStack[diffIndex].formatter.append(diffed, lhs) - } - } - } - } - - while (topIndex >= 0) { - lhs = lhsStack[topIndex].recursor() - rhs = rhsStack[topIndex].recursor() - - if (lhs !== null && rhs !== null) { - break - } - - if (lhs === null && rhs === null) { - const lhsRecord = lhsStack.pop() - const rhsRecord = rhsStack.pop() - lhsCircular.delete(lhsRecord.subject) - rhsCircular.delete(rhsRecord.subject) - topIndex-- - - if (lhsRecord.diffIndex === diffIndex) { - const record = diffStack.pop() - diffIndex-- - if (record.decreaseIndent) indent = indent.decrease() - - let formatted = record.formatter.finalize() - if (record.exceedsMaxDepth && !formatted.hasGutter) { - // The record exceeds the max depth, but contains no actual diff. - // Discard the potentially deep formatting and format just the - // original subject. - const subject = lhsRecord.subject - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const isEmpty = subject.createRecursor()() === null - formatted = !isEmpty && typeof formatter.maxDepth === 'function' - ? formatter.maxDepth() - : formatter.finalize() - } - - if (diffIndex === -1) { - buffer.append(formatted) - } else { - diffStack[diffIndex].formatter.append(formatted, record.subject) - } - } - } else { - let builder, circular, stack, subject - if (lhs === null) { - builder = lineBuilder.expected - circular = rhsCircular - stack = rhsStack - subject = rhs - } else { - builder = lineBuilder.actual - circular = lhsCircular - stack = lhsStack - subject = lhs - } - - do { - format(builder, subject, circular, indent.level) - subject = stack[topIndex].recursor() - } while (subject !== null) - } - } - } while (topIndex >= 0) - - return buffer.toString({ diff: true, invert, theme }) + const theme = themeUtils.normalize(options) + const invert = options ? options.invert === true : false + + const lhsCircular = new Circular() + const rhsCircular = new Circular() + const maxDepth = (options && options.maxDepth) || 0 + + let indent = new Indenter(0, ' ') + + const lhsStack = [] + const rhsStack = [] + let topIndex = -1 + + const buffer = lineBuilder.buffer() + const diffStack = [] + let diffIndex = -1 + + const isCircular = descriptor => lhsCircular.has(descriptor) || rhsCircular.has(descriptor) + + const format = (builder, subject, circular, depthOffset = 0) => { + if (diffIndex >= 0 && !diffStack[diffIndex].shouldFormat(subject)) return + + if (circular.has(subject)) { + diffStack[diffIndex].formatter.append(builder.single(theme.circular)) + return + } + + const formatStack = [] + let formatIndex = -1 + + do { + if (circular.has(subject)) { + formatStack[formatIndex].formatter.append(builder.single(theme.circular), subject) + } else { + let didFormat = false + if (typeof subject.formatDeep === 'function') { + let formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) + if (formatted !== null) { + didFormat = true + + if (formatIndex === -1) { + formatted = builder.setDefaultGutter(formatted) + if (diffIndex === -1) { + buffer.append(formatted) + } else { + diffStack[diffIndex].formatter.append(formatted, subject) + } + } else { + formatStack[formatIndex].formatter.append(formatted, subject) + } + } + } + + if (!didFormat && typeof subject.formatShallow === 'function') { + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) + const recursor = subject.createRecursor() + + if (formatter.increaseIndent && maxDepth > 0 && indent.level === (maxDepth + depthOffset)) { + const isEmpty = recursor() === null + let formatted = !isEmpty && typeof formatter.maxDepth === 'function' + ? formatter.maxDepth() + : formatter.finalize() + + if (formatIndex === -1) { + formatted = builder.setDefaultGutter(formatted) + diffStack[diffIndex].formatter.append(formatted, subject) + } else { + formatStack[formatIndex].formatter.append(formatted, subject) + } + } else { + formatStack.push({ + formatter, + recursor, + decreaseIndent: formatter.increaseIndent, + shouldFormat: formatter.shouldFormat || alwaysFormat, + subject, + }) + formatIndex++ + + if (formatter.increaseIndent) indent = indent.increase() + circular.add(subject) + } + } + } + + while (formatIndex >= 0) { + do { + subject = formatStack[formatIndex].recursor() + } while (subject && !formatStack[formatIndex].shouldFormat(subject)) + + if (subject) { + break + } + + const record = formatStack.pop() + formatIndex-- + if (record.decreaseIndent) indent = indent.decrease() + circular.delete(record.subject) + + let formatted = record.formatter.finalize() + if (formatIndex === -1) { + formatted = builder.setDefaultGutter(formatted) + if (diffIndex === -1) { + buffer.append(formatted) + } else { + diffStack[diffIndex].formatter.append(formatted, record.subject) + } + } else { + formatStack[formatIndex].formatter.append(formatted, record.subject) + } + } + } while (formatIndex >= 0) + } + + do { + let compareResult = NOOP + if (lhsCircular.has(lhs)) { + compareResult = lhsCircular.get(lhs) === rhsCircular.get(rhs) + ? DEEP_EQUAL + : UNEQUAL + } else if (rhsCircular.has(rhs)) { + compareResult = UNEQUAL + } + + let firstPassSymbolProperty = false + if (lhs.isProperty === true) { + compareResult = lhs.compare(rhs) + if (compareResult === AMBIGUOUS) { + const parent = lhsStack[topIndex].subject + firstPassSymbolProperty = parent.isSymbolPropertiesCollector !== true && parent.isSymbolPropertiesComparable !== true + } + } + + let didFormat = false + let mustRecurse = false + if (compareResult !== DEEP_EQUAL && !firstPassSymbolProperty && typeof lhs.prepareDiff === 'function') { + const lhsRecursor = topIndex === -1 ? null : lhsStack[topIndex].recursor + const rhsRecursor = topIndex === -1 ? null : rhsStack[topIndex].recursor + + const instructions = lhs.prepareDiff( + rhs, + lhsRecursor, + rhsRecursor, + compareComplexShape, + isCircular) + + if (instructions !== null) { + if (topIndex >= 0) { + if (typeof instructions.lhsRecursor === 'function') { + lhsStack[topIndex].recursor = instructions.lhsRecursor + } + if (typeof instructions.rhsRecursor === 'function') { + rhsStack[topIndex].recursor = instructions.rhsRecursor + } + } + + if (instructions.compareResult) { + compareResult = instructions.compareResult + } + if (instructions.mustRecurse === true) { + mustRecurse = true + } else { + if (instructions.actualIsExtraneous === true) { + format(lineBuilder.actual, lhs, lhsCircular) + didFormat = true + } else if (instructions.multipleAreExtraneous === true) { + for (const extraneous of instructions.descriptors) { + format(lineBuilder.actual, extraneous, lhsCircular) + } + didFormat = true + } else if (instructions.expectedIsMissing === true) { + format(lineBuilder.expected, rhs, rhsCircular) + didFormat = true + } else if (instructions.multipleAreMissing === true) { + for (const missing of instructions.descriptors) { + format(lineBuilder.expected, missing, rhsCircular) + } + didFormat = true + } else if (instructions.isUnequal === true) { + format(lineBuilder.actual, lhs, lhsCircular) + format(lineBuilder.expected, rhs, rhsCircular) + didFormat = true + } else if (!instructions.compareResult) { + // TODO: Throw a useful, custom error + throw new Error('Illegal result of prepareDiff()') + } + } + } + } + + if (!didFormat) { + if (compareResult === NOOP) { + compareResult = lhs.compare(rhs) + } + + if (!mustRecurse) { + mustRecurse = shouldCompareDeep(compareResult, lhs, rhs) + } + + if (compareResult === DEEP_EQUAL) { + format(lineBuilder, lhs, lhsCircular) + } else if (mustRecurse) { + if (compareResult === AMBIGUOUS && lhs.isProperty === true) { + // Replace both sides by a pseudo-descriptor which collects symbol + // properties instead. + lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) + rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) + // Replace the current recursors so they can continue correctly after + // the collectors have been "compared". This is necessary since the + // collectors eat the first value after the last symbol property. + lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) + rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) + } + + if (typeof lhs.diffShallow === 'function') { + const formatter = lhs.diffShallow(rhs, themeUtils.applyModifiers(lhs, theme), indent) + diffStack.push({ + formatter, + origin: lhs, + decreaseIndent: formatter.increaseIndent, + exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, + shouldFormat: formatter.shouldFormat || alwaysFormat, + }) + diffIndex++ + + if (formatter.increaseIndent) indent = indent.increase() + } else if (typeof lhs.formatShallow === 'function') { + const formatter = lhs.formatShallow(themeUtils.applyModifiers(lhs, theme), indent) + diffStack.push({ + formatter, + decreaseIndent: formatter.increaseIndent, + exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, + shouldFormat: formatter.shouldFormat || alwaysFormat, + subject: lhs, + }) + diffIndex++ + + if (formatter.increaseIndent) indent = indent.increase() + } + + lhsCircular.add(lhs) + rhsCircular.add(rhs) + + lhsStack.push({ diffIndex, subject: lhs, recursor: lhs.createRecursor() }) + rhsStack.push({ diffIndex, subject: rhs, recursor: rhs.createRecursor() }) + topIndex++ + } else { + const diffed = typeof lhs.diffDeep === 'function' + ? lhs.diffDeep(rhs, themeUtils.applyModifiers(lhs, theme), indent, invert) + : null + + if (diffed === null) { + format(lineBuilder.actual, lhs, lhsCircular) + format(lineBuilder.expected, rhs, rhsCircular) + } else { + if (diffIndex === -1) { + buffer.append(diffed) + } else { + diffStack[diffIndex].formatter.append(diffed, lhs) + } + } + } + } + + while (topIndex >= 0) { + lhs = lhsStack[topIndex].recursor() + rhs = rhsStack[topIndex].recursor() + + if (lhs !== null && rhs !== null) { + break + } + + if (lhs === null && rhs === null) { + const lhsRecord = lhsStack.pop() + const rhsRecord = rhsStack.pop() + lhsCircular.delete(lhsRecord.subject) + rhsCircular.delete(rhsRecord.subject) + topIndex-- + + if (lhsRecord.diffIndex === diffIndex) { + const record = diffStack.pop() + diffIndex-- + if (record.decreaseIndent) indent = indent.decrease() + + let formatted = record.formatter.finalize() + if (record.exceedsMaxDepth && !formatted.hasGutter) { + // The record exceeds the max depth, but contains no actual diff. + // Discard the potentially deep formatting and format just the + // original subject. + const subject = lhsRecord.subject + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) + const isEmpty = subject.createRecursor()() === null + formatted = !isEmpty && typeof formatter.maxDepth === 'function' + ? formatter.maxDepth() + : formatter.finalize() + } + + if (diffIndex === -1) { + buffer.append(formatted) + } else { + diffStack[diffIndex].formatter.append(formatted, record.subject) + } + } + } else { + let builder, circular, stack, subject + if (lhs === null) { + builder = lineBuilder.expected + circular = rhsCircular + stack = rhsStack + subject = rhs + } else { + builder = lineBuilder.actual + circular = lhsCircular + stack = lhsStack + subject = lhs + } + + do { + format(builder, subject, circular, indent.level) + subject = stack[topIndex].recursor() + } while (subject !== null) + } + } + } while (topIndex >= 0) + + return buffer.toString({ diff: true, invert, theme }) } export function diff (actual, expected, options) { - return diffDescriptors(describe(actual, options), describe(expected, options), options) + return diffDescriptors(describe(actual, options), describe(expected, options), options) } diff --git a/lib/encoder.js b/lib/encoder.js index 153a437..5d55f48 100644 --- a/lib/encoder.js +++ b/lib/encoder.js @@ -2,294 +2,294 @@ import {flattenDeep} from './lodash/index.js' // Indexes are hexadecimal to make reading the binary output easier. const valueTypes = { - zero: 0x00, - int8: 0x01, // Note that the hex value equals the number of bytes required - int16: 0x02, // to store the integer. - int24: 0x03, - int32: 0x04, - int40: 0x05, - int48: 0x06, - numberString: 0x07, - negativeZero: 0x08, - notANumber: 0x09, - infinity: 0x0A, - negativeInfinity: 0x0B, - bigInt: 0x0C, - undefined: 0x0D, - null: 0x0E, - true: 0x0F, - false: 0x10, - utf8: 0x11, - bytes: 0x12, - list: 0x13, - descriptor: 0x14, + zero: 0x00, + int8: 0x01, // Note that the hex value equals the number of bytes required + int16: 0x02, // to store the integer. + int24: 0x03, + int32: 0x04, + int40: 0x05, + int48: 0x06, + numberString: 0x07, + negativeZero: 0x08, + notANumber: 0x09, + infinity: 0x0A, + negativeInfinity: 0x0B, + bigInt: 0x0C, + undefined: 0x0D, + null: 0x0E, + true: 0x0F, + false: 0x10, + utf8: 0x11, + bytes: 0x12, + list: 0x13, + descriptor: 0x14, } export const descriptorSymbol = Symbol('descriptor') function encodeInteger (type, value) { - const encoded = Buffer.alloc(type) - encoded.writeIntLE(value, 0, type) - return [type, encoded] + const encoded = Buffer.alloc(type) + encoded.writeIntLE(value, 0, type) + return [type, encoded] } function encodeValue (value) { - if (Object.is(value, 0)) return valueTypes.zero - if (Object.is(value, -0)) return valueTypes.negativeZero - if (Object.is(value, NaN)) return valueTypes.notANumber - if (value === Infinity) return valueTypes.infinity - if (value === -Infinity) return valueTypes.negativeInfinity - if (value === undefined) return valueTypes.undefined - if (value === null) return valueTypes.null - if (value === true) return valueTypes.true - if (value === false) return valueTypes.false - - const type = typeof value - if (type === 'number') { - if (Number.isInteger(value)) { - // The integer types are signed, so int8 can only store 7 bits, int16 - // only 15, etc. - if (value >= -0x80 && value < 0x80) return encodeInteger(valueTypes.int8, value) - if (value >= -0x8000 && value < 0x8000) return encodeInteger(valueTypes.int16, value) - if (value >= -0x800000 && value < 0x800000) return encodeInteger(valueTypes.int24, value) - if (value >= -0x80000000 && value < 0x80000000) return encodeInteger(valueTypes.int32, value) - if (value >= -0x8000000000 && value < 0x8000000000) return encodeInteger(valueTypes.int40, value) - if (value >= -0x800000000000 && value < 0x800000000000) return encodeInteger(valueTypes.int48, value) - // Fall through to encoding the value as a number string. - } - - const encoded = Buffer.from(String(value), 'utf8') - return [valueTypes.numberString, encodeValue(encoded.length), encoded] - } - - if (type === 'string') { - const encoded = Buffer.from(value, 'utf8') - return [valueTypes.utf8, encodeValue(encoded.length), encoded] - } - - if (type === 'bigint') { - const encoded = Buffer.from(String(value), 'utf8') - return [valueTypes.bigInt, encodeValue(encoded.length), encoded] - } - - if (Buffer.isBuffer(value)) { - return [valueTypes.bytes, encodeValue(value.byteLength), value] - } - - if (Array.isArray(value)) { - return [ - value[descriptorSymbol] === true ? valueTypes.descriptor : valueTypes.list, - encodeValue(value.length), - value.map(x => encodeValue(x)), - ] - } - - const hex = `0x${type.toString(16).toUpperCase()}` - throw new TypeError(`Unexpected value with type ${hex}`) + if (Object.is(value, 0)) return valueTypes.zero + if (Object.is(value, -0)) return valueTypes.negativeZero + if (Object.is(value, NaN)) return valueTypes.notANumber + if (value === Infinity) return valueTypes.infinity + if (value === -Infinity) return valueTypes.negativeInfinity + if (value === undefined) return valueTypes.undefined + if (value === null) return valueTypes.null + if (value === true) return valueTypes.true + if (value === false) return valueTypes.false + + const type = typeof value + if (type === 'number') { + if (Number.isInteger(value)) { + // The integer types are signed, so int8 can only store 7 bits, int16 + // only 15, etc. + if (value >= -0x80 && value < 0x80) return encodeInteger(valueTypes.int8, value) + if (value >= -0x8000 && value < 0x8000) return encodeInteger(valueTypes.int16, value) + if (value >= -0x800000 && value < 0x800000) return encodeInteger(valueTypes.int24, value) + if (value >= -0x80000000 && value < 0x80000000) return encodeInteger(valueTypes.int32, value) + if (value >= -0x8000000000 && value < 0x8000000000) return encodeInteger(valueTypes.int40, value) + if (value >= -0x800000000000 && value < 0x800000000000) return encodeInteger(valueTypes.int48, value) + // Fall through to encoding the value as a number string. + } + + const encoded = Buffer.from(String(value), 'utf8') + return [valueTypes.numberString, encodeValue(encoded.length), encoded] + } + + if (type === 'string') { + const encoded = Buffer.from(value, 'utf8') + return [valueTypes.utf8, encodeValue(encoded.length), encoded] + } + + if (type === 'bigint') { + const encoded = Buffer.from(String(value), 'utf8') + return [valueTypes.bigInt, encodeValue(encoded.length), encoded] + } + + if (Buffer.isBuffer(value)) { + return [valueTypes.bytes, encodeValue(value.byteLength), value] + } + + if (Array.isArray(value)) { + return [ + value[descriptorSymbol] === true ? valueTypes.descriptor : valueTypes.list, + encodeValue(value.length), + value.map(x => encodeValue(x)), + ] + } + + const hex = `0x${type.toString(16).toUpperCase()}` + throw new TypeError(`Unexpected value with type ${hex}`) } function decodeValue (buffer, byteOffset) { - const type = buffer.readUInt8(byteOffset) - byteOffset += 1 - - if (type === valueTypes.zero) return { byteOffset, value: 0 } - if (type === valueTypes.negativeZero) return { byteOffset, value: -0 } - if (type === valueTypes.notANumber) return { byteOffset, value: NaN } - if (type === valueTypes.infinity) return { byteOffset, value: Infinity } - if (type === valueTypes.negativeInfinity) return { byteOffset, value: -Infinity } - if (type === valueTypes.undefined) return { byteOffset, value: undefined } - if (type === valueTypes.null) return { byteOffset, value: null } - if (type === valueTypes.true) return { byteOffset, value: true } - if (type === valueTypes.false) return { byteOffset, value: false } - - if ( - type === valueTypes.int8 || type === valueTypes.int16 || type === valueTypes.int24 || - type === valueTypes.int32 || type === valueTypes.int40 || type === valueTypes.int48 - ) { - const value = buffer.readIntLE(byteOffset, type) - byteOffset += type - return { byteOffset, value } - } - - if (type === valueTypes.numberString || type === valueTypes.utf8 || type === valueTypes.bytes || type === valueTypes.bigInt) { - const length = decodeValue(buffer, byteOffset) - const start = length.byteOffset - const end = start + length.value - - if (type === valueTypes.numberString) { - const value = Number(buffer.toString('utf8', start, end)) - return { byteOffset: end, value } - } - - if (type === valueTypes.utf8) { - const value = buffer.toString('utf8', start, end) - return { byteOffset: end, value } - } - - if (type === valueTypes.bigInt) { - const value = BigInt(buffer.toString('utf8', start, end)) // eslint-disable-line no-undef - return { byteOffset: end, value } - } - - const value = buffer.slice(start, end) - return { byteOffset: end, value } - } - - if (type === valueTypes.list || type === valueTypes.descriptor) { - const length = decodeValue(buffer, byteOffset) - byteOffset = length.byteOffset - - const value = new Array(length.value) - if (type === valueTypes.descriptor) { - value[descriptorSymbol] = true - } - - for (let index = 0; index < length.value; index++) { - const item = decodeValue(buffer, byteOffset) - byteOffset = item.byteOffset - value[index] = item.value - } - - return { byteOffset, value } - } - - const hex = `0x${type.toString(16).toUpperCase()}` - throw new TypeError(`Could not decode type ${hex}`) + const type = buffer.readUInt8(byteOffset) + byteOffset += 1 + + if (type === valueTypes.zero) return { byteOffset, value: 0 } + if (type === valueTypes.negativeZero) return { byteOffset, value: -0 } + if (type === valueTypes.notANumber) return { byteOffset, value: NaN } + if (type === valueTypes.infinity) return { byteOffset, value: Infinity } + if (type === valueTypes.negativeInfinity) return { byteOffset, value: -Infinity } + if (type === valueTypes.undefined) return { byteOffset, value: undefined } + if (type === valueTypes.null) return { byteOffset, value: null } + if (type === valueTypes.true) return { byteOffset, value: true } + if (type === valueTypes.false) return { byteOffset, value: false } + + if ( + type === valueTypes.int8 || type === valueTypes.int16 || type === valueTypes.int24 || + type === valueTypes.int32 || type === valueTypes.int40 || type === valueTypes.int48 + ) { + const value = buffer.readIntLE(byteOffset, type) + byteOffset += type + return { byteOffset, value } + } + + if (type === valueTypes.numberString || type === valueTypes.utf8 || type === valueTypes.bytes || type === valueTypes.bigInt) { + const length = decodeValue(buffer, byteOffset) + const start = length.byteOffset + const end = start + length.value + + if (type === valueTypes.numberString) { + const value = Number(buffer.toString('utf8', start, end)) + return { byteOffset: end, value } + } + + if (type === valueTypes.utf8) { + const value = buffer.toString('utf8', start, end) + return { byteOffset: end, value } + } + + if (type === valueTypes.bigInt) { + const value = BigInt(buffer.toString('utf8', start, end)) // eslint-disable-line no-undef + return { byteOffset: end, value } + } + + const value = buffer.slice(start, end) + return { byteOffset: end, value } + } + + if (type === valueTypes.list || type === valueTypes.descriptor) { + const length = decodeValue(buffer, byteOffset) + byteOffset = length.byteOffset + + const value = new Array(length.value) + if (type === valueTypes.descriptor) { + value[descriptorSymbol] = true + } + + for (let index = 0; index < length.value; index++) { + const item = decodeValue(buffer, byteOffset) + byteOffset = item.byteOffset + value[index] = item.value + } + + return { byteOffset, value } + } + + const hex = `0x${type.toString(16).toUpperCase()}` + throw new TypeError(`Could not decode type ${hex}`) } function buildBuffer (numberOrArray) { - if (typeof numberOrArray === 'number') { - const byte = Buffer.alloc(1) - byte.writeUInt8(numberOrArray) - return byte - } - - const array = flattenDeep(numberOrArray) - const buffers = new Array(array.length) - let byteLength = 0 - for (const [index, element] of array.entries()) { - if (typeof element === 'number') { - byteLength += 1 - const byte = Buffer.alloc(1) - byte.writeUInt8(element) - buffers[index] = byte - } else { - byteLength += element.byteLength - buffers[index] = element - } - } - return Buffer.concat(buffers, byteLength) + if (typeof numberOrArray === 'number') { + const byte = Buffer.alloc(1) + byte.writeUInt8(numberOrArray) + return byte + } + + const array = flattenDeep(numberOrArray) + const buffers = new Array(array.length) + let byteLength = 0 + for (const [index, element] of array.entries()) { + if (typeof element === 'number') { + byteLength += 1 + const byte = Buffer.alloc(1) + byte.writeUInt8(element) + buffers[index] = byte + } else { + byteLength += element.byteLength + buffers[index] = element + } + } + return Buffer.concat(buffers, byteLength) } export function encode (serializerVersion, rootRecord, usedPlugins) { - const buffers = [] - let byteOffset = 0 - - const versionHeader = Buffer.alloc(2) - versionHeader.writeUInt16LE(serializerVersion) - buffers.push(versionHeader) - byteOffset += versionHeader.byteLength - - const rootOffset = Buffer.alloc(4) - buffers.push(rootOffset) - byteOffset += rootOffset.byteLength - - const numPlugins = buildBuffer(encodeValue(usedPlugins.size)) - buffers.push(numPlugins) - byteOffset += numPlugins.byteLength - - for (const name of usedPlugins.keys()) { - const plugin = usedPlugins.get(name) - const record = buildBuffer([ - encodeValue(name), - encodeValue(plugin.serializerVersion), - ]) - buffers.push(record) - byteOffset += record.byteLength - } - - const queue = [rootRecord] - const pointers = [rootOffset] - while (queue.length > 0) { - pointers.shift().writeUInt32LE(byteOffset, 0) - - const record = queue.shift() - const recordHeader = buildBuffer([ - encodeValue(record.pluginIndex), - encodeValue(record.id), - encodeValue(record.children.length), - ]) - buffers.push(recordHeader) - byteOffset += recordHeader.byteLength - - // Add pointers before encoding the state. This allows, if it ever becomes - // necessary, for records to be extracted from a buffer without having to - // parse the (variable length) state field. - for (const child of record.children) { - queue.push(child) - - const pointer = Buffer.alloc(4) - pointers.push(pointer) - buffers.push(pointer) - byteOffset += 4 - } - - const state = buildBuffer(encodeValue(record.state)) - buffers.push(state) - byteOffset += state.byteLength - } - - return Buffer.concat(buffers, byteOffset) + const buffers = [] + let byteOffset = 0 + + const versionHeader = Buffer.alloc(2) + versionHeader.writeUInt16LE(serializerVersion) + buffers.push(versionHeader) + byteOffset += versionHeader.byteLength + + const rootOffset = Buffer.alloc(4) + buffers.push(rootOffset) + byteOffset += rootOffset.byteLength + + const numPlugins = buildBuffer(encodeValue(usedPlugins.size)) + buffers.push(numPlugins) + byteOffset += numPlugins.byteLength + + for (const name of usedPlugins.keys()) { + const plugin = usedPlugins.get(name) + const record = buildBuffer([ + encodeValue(name), + encodeValue(plugin.serializerVersion), + ]) + buffers.push(record) + byteOffset += record.byteLength + } + + const queue = [rootRecord] + const pointers = [rootOffset] + while (queue.length > 0) { + pointers.shift().writeUInt32LE(byteOffset, 0) + + const record = queue.shift() + const recordHeader = buildBuffer([ + encodeValue(record.pluginIndex), + encodeValue(record.id), + encodeValue(record.children.length), + ]) + buffers.push(recordHeader) + byteOffset += recordHeader.byteLength + + // Add pointers before encoding the state. This allows, if it ever becomes + // necessary, for records to be extracted from a buffer without having to + // parse the (variable length) state field. + for (const child of record.children) { + queue.push(child) + + const pointer = Buffer.alloc(4) + pointers.push(pointer) + buffers.push(pointer) + byteOffset += 4 + } + + const state = buildBuffer(encodeValue(record.state)) + buffers.push(state) + byteOffset += state.byteLength + } + + return Buffer.concat(buffers, byteOffset) } export function decodePlugins (buffer) { - const $numPlugins = decodeValue(buffer, 0) - let byteOffset = $numPlugins.byteOffset + const $numPlugins = decodeValue(buffer, 0) + let byteOffset = $numPlugins.byteOffset - const usedPlugins = new Map() - const lastIndex = $numPlugins.value - for (let index = 1; index <= lastIndex; index++) { - const $name = decodeValue(buffer, byteOffset) - const name = $name.value - byteOffset = $name.byteOffset + const usedPlugins = new Map() + const lastIndex = $numPlugins.value + for (let index = 1; index <= lastIndex; index++) { + const $name = decodeValue(buffer, byteOffset) + const name = $name.value + byteOffset = $name.byteOffset - const serializerVersion = decodeValue(buffer, byteOffset).value - usedPlugins.set(index, { name, serializerVersion }) - } + const serializerVersion = decodeValue(buffer, byteOffset).value + usedPlugins.set(index, { name, serializerVersion }) + } - return usedPlugins + return usedPlugins } export function decodeRecord (buffer, byteOffset) { - const $pluginIndex = decodeValue(buffer, byteOffset) - const pluginIndex = $pluginIndex.value - byteOffset = $pluginIndex.byteOffset - - const $id = decodeValue(buffer, byteOffset) - const id = $id.value - byteOffset = $id.byteOffset - - const $numPointers = decodeValue(buffer, byteOffset) - const numPointers = $numPointers.value - byteOffset = $numPointers.byteOffset - - const pointerAddresses = new Array(numPointers) - for (let index = 0; index < numPointers; index++) { - pointerAddresses[index] = buffer.readUInt32LE(byteOffset) - byteOffset += 4 - } - - const state = decodeValue(buffer, byteOffset).value - return { id, pluginIndex, state, pointerAddresses } + const $pluginIndex = decodeValue(buffer, byteOffset) + const pluginIndex = $pluginIndex.value + byteOffset = $pluginIndex.byteOffset + + const $id = decodeValue(buffer, byteOffset) + const id = $id.value + byteOffset = $id.byteOffset + + const $numPointers = decodeValue(buffer, byteOffset) + const numPointers = $numPointers.value + byteOffset = $numPointers.byteOffset + + const pointerAddresses = new Array(numPointers) + for (let index = 0; index < numPointers; index++) { + pointerAddresses[index] = buffer.readUInt32LE(byteOffset) + byteOffset += 4 + } + + const state = decodeValue(buffer, byteOffset).value + return { id, pluginIndex, state, pointerAddresses } } export function extractVersion (buffer) { - return buffer.readUInt16LE(0) + return buffer.readUInt16LE(0) } export function decode (buffer) { - const rootOffset = buffer.readUInt32LE(2) - const pluginBuffer = buffer.slice(6, rootOffset) - const rootRecord = decodeRecord(buffer, rootOffset) - return { pluginBuffer, rootRecord } + const rootOffset = buffer.readUInt32LE(2) + const pluginBuffer = buffer.slice(6, rootOffset) + const rootRecord = decodeRecord(buffer, rootOffset) + return { pluginBuffer, rootRecord } } diff --git a/lib/format.js b/lib/format.js index f5c173b..06dc9b2 100644 --- a/lib/format.js +++ b/lib/format.js @@ -8,90 +8,90 @@ const alwaysFormat = () => true const fixedIndent = new Indenter(0, ' ') export function formatDescriptor (subject, options) { - const theme = themeUtils.normalize(options) - if (subject.isPrimitive === true) { - const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), fixedIndent) - return formatted.toString({ diff: false }) - } + const theme = themeUtils.normalize(options) + if (subject.isPrimitive === true) { + const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), fixedIndent) + return formatted.toString({ diff: false }) + } - const circular = new Circular() - const maxDepth = (options && options.maxDepth) || 0 + const circular = new Circular() + const maxDepth = (options && options.maxDepth) || 0 - let indent = fixedIndent + let indent = fixedIndent - const buffer = lineBuilder.buffer() - const stack = [] - let topIndex = -1 + const buffer = lineBuilder.buffer() + const stack = [] + let topIndex = -1 - do { - if (circular.has(subject)) { - stack[topIndex].formatter.append(lineBuilder.single(theme.circular), subject) - } else { - let didFormat = false - if (typeof subject.formatDeep === 'function') { - const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) - if (formatted !== null) { - didFormat = true - if (topIndex === -1) { - buffer.append(formatted) - } else { - stack[topIndex].formatter.append(formatted, subject) - } - } - } + do { + if (circular.has(subject)) { + stack[topIndex].formatter.append(lineBuilder.single(theme.circular), subject) + } else { + let didFormat = false + if (typeof subject.formatDeep === 'function') { + const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) + if (formatted !== null) { + didFormat = true + if (topIndex === -1) { + buffer.append(formatted) + } else { + stack[topIndex].formatter.append(formatted, subject) + } + } + } - if (!didFormat && typeof subject.formatShallow === 'function') { - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const recursor = subject.createRecursor() + if (!didFormat && typeof subject.formatShallow === 'function') { + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) + const recursor = subject.createRecursor() - if (formatter.increaseIndent && maxDepth > 0 && indent.level === maxDepth) { - const isEmpty = recursor() === null - const formatted = !isEmpty && typeof formatter.maxDepth === 'function' - ? formatter.maxDepth() - : formatter.finalize() - stack[topIndex].formatter.append(formatted, subject) - } else { - stack.push({ - formatter, - recursor, - decreaseIndent: formatter.increaseIndent, - shouldFormat: formatter.shouldFormat || alwaysFormat, - subject, - }) - topIndex++ + if (formatter.increaseIndent && maxDepth > 0 && indent.level === maxDepth) { + const isEmpty = recursor() === null + const formatted = !isEmpty && typeof formatter.maxDepth === 'function' + ? formatter.maxDepth() + : formatter.finalize() + stack[topIndex].formatter.append(formatted, subject) + } else { + stack.push({ + formatter, + recursor, + decreaseIndent: formatter.increaseIndent, + shouldFormat: formatter.shouldFormat || alwaysFormat, + subject, + }) + topIndex++ - if (formatter.increaseIndent) indent = indent.increase() - circular.add(subject) - } - } - } + if (formatter.increaseIndent) indent = indent.increase() + circular.add(subject) + } + } + } - while (topIndex >= 0) { - do { - subject = stack[topIndex].recursor() - } while (subject && !stack[topIndex].shouldFormat(subject)) + while (topIndex >= 0) { + do { + subject = stack[topIndex].recursor() + } while (subject && !stack[topIndex].shouldFormat(subject)) - if (subject) { - break - } + if (subject) { + break + } - const record = stack.pop() - topIndex-- - if (record.decreaseIndent) indent = indent.decrease() - circular.delete(record.subject) + const record = stack.pop() + topIndex-- + if (record.decreaseIndent) indent = indent.decrease() + circular.delete(record.subject) - const formatted = record.formatter.finalize() - if (topIndex === -1) { - buffer.append(formatted) - } else { - stack[topIndex].formatter.append(formatted, record.subject) - } - } - } while (topIndex >= 0) + const formatted = record.formatter.finalize() + if (topIndex === -1) { + buffer.append(formatted) + } else { + stack[topIndex].formatter.append(formatted, record.subject) + } + } + } while (topIndex >= 0) - return buffer.toString({ diff: false }) + return buffer.toString({ diff: false }) } export function format (value, options) { - return formatDescriptor(describe(value, options), options) + return formatDescriptor(describe(value, options), options) } diff --git a/lib/formatUtils.js b/lib/formatUtils.js index 934ced3..11a7a0d 100644 --- a/lib/formatUtils.js +++ b/lib/formatUtils.js @@ -1,117 +1,117 @@ import lineBuilder from './lineBuilder.js' export function wrap (fromTheme, value) { - return fromTheme.open + value + fromTheme.close + return fromTheme.open + value + fromTheme.close } export function formatCtorAndStringTag (theme, object) { - if (!object.ctor) return wrap(theme.object.stringTag, object.stringTag) + if (!object.ctor) return wrap(theme.object.stringTag, object.stringTag) - let retval = wrap(theme.object.ctor, object.ctor) - if (object.stringTag && object.stringTag !== object.ctor && object.stringTag !== 'Object') { - retval += ' ' + wrap(theme.object.secondaryStringTag, object.stringTag) - } - return retval + let retval = wrap(theme.object.ctor, object.ctor) + if (object.stringTag && object.stringTag !== object.ctor && object.stringTag !== 'Object') { + retval += ' ' + wrap(theme.object.secondaryStringTag, object.stringTag) + } + return retval } export class ObjectFormatter { - constructor (object, theme, indent) { - this.object = object - this.theme = theme - this.indent = indent - - this.increaseIndent = true - - this.innerLines = lineBuilder.buffer() - this.pendingStats = null - } - - append (formatted, origin) { - if (origin.isStats === true) { - this.pendingStats = formatted - } else { - if (this.pendingStats !== null) { - if (!this.innerLines.isEmpty) { - this.innerLines.append(this.pendingStats) - } - this.pendingStats = null - } - this.innerLines.append(formatted) - } - } - - finalize () { - const variant = this.object.isList - ? this.theme.list - : this.theme.object - - const ctor = this.object.ctor - const stringTag = this.object.stringTag - const prefix = (ctor === 'Array' || ctor === 'Object') && ctor === stringTag - ? '' - : formatCtorAndStringTag(this.theme, this.object) + ' ' - - if (this.innerLines.isEmpty) { - return lineBuilder.single(prefix + variant.openBracket + variant.closeBracket) - } - - return lineBuilder.first(prefix + variant.openBracket) - .concat(this.innerLines.withFirstPrefixed(this.indent.increase()).stripFlags()) - .append(lineBuilder.last(this.indent + variant.closeBracket)) - } - - maxDepth () { - const variant = this.object.isList - ? this.theme.list - : this.theme.object - - return lineBuilder.single( - formatCtorAndStringTag(this.theme, this.object) + ' ' + variant.openBracket + - ' ' + this.theme.maxDepth + ' ' + variant.closeBracket) - } - - shouldFormat () { - return true - } - - customize (methods) { - if (methods.finalize) { - this.finalize = () => methods.finalize(this.innerLines) - } - if (methods.maxDepth) { - this.maxDepth = methods.maxDepth - } - if (methods.shouldFormat) { - this.shouldFormat = methods.shouldFormat - } - - return this - } + constructor (object, theme, indent) { + this.object = object + this.theme = theme + this.indent = indent + + this.increaseIndent = true + + this.innerLines = lineBuilder.buffer() + this.pendingStats = null + } + + append (formatted, origin) { + if (origin.isStats === true) { + this.pendingStats = formatted + } else { + if (this.pendingStats !== null) { + if (!this.innerLines.isEmpty) { + this.innerLines.append(this.pendingStats) + } + this.pendingStats = null + } + this.innerLines.append(formatted) + } + } + + finalize () { + const variant = this.object.isList + ? this.theme.list + : this.theme.object + + const ctor = this.object.ctor + const stringTag = this.object.stringTag + const prefix = (ctor === 'Array' || ctor === 'Object') && ctor === stringTag + ? '' + : formatCtorAndStringTag(this.theme, this.object) + ' ' + + if (this.innerLines.isEmpty) { + return lineBuilder.single(prefix + variant.openBracket + variant.closeBracket) + } + + return lineBuilder.first(prefix + variant.openBracket) + .concat(this.innerLines.withFirstPrefixed(this.indent.increase()).stripFlags()) + .append(lineBuilder.last(this.indent + variant.closeBracket)) + } + + maxDepth () { + const variant = this.object.isList + ? this.theme.list + : this.theme.object + + return lineBuilder.single( + formatCtorAndStringTag(this.theme, this.object) + ' ' + variant.openBracket + + ' ' + this.theme.maxDepth + ' ' + variant.closeBracket) + } + + shouldFormat () { + return true + } + + customize (methods) { + if (methods.finalize) { + this.finalize = () => methods.finalize(this.innerLines) + } + if (methods.maxDepth) { + this.maxDepth = methods.maxDepth + } + if (methods.shouldFormat) { + this.shouldFormat = methods.shouldFormat + } + + return this + } } export class SingleValueFormatter { - constructor (theme, finalizeFn, increaseIndent) { - this.theme = theme - this.finalizeFn = finalizeFn - this.hasValue = false - this.increaseIndent = increaseIndent === true - this.value = null - } - - append (formatted) { - if (this.hasValue) throw new Error('Formatter buffer can only take one formatted value.') - - this.hasValue = true - this.value = formatted - } - - finalize () { - if (!this.hasValue) throw new Error('Formatter buffer never received a formatted value.') - - return this.finalizeFn(this.value) - } - - maxDepth () { - return this.finalizeFn(lineBuilder.single(this.theme.maxDepth)) - } + constructor (theme, finalizeFn, increaseIndent) { + this.theme = theme + this.finalizeFn = finalizeFn + this.hasValue = false + this.increaseIndent = increaseIndent === true + this.value = null + } + + append (formatted) { + if (this.hasValue) throw new Error('Formatter buffer can only take one formatted value.') + + this.hasValue = true + this.value = formatted + } + + finalize () { + if (!this.hasValue) throw new Error('Formatter buffer never received a formatted value.') + + return this.finalizeFn(this.value) + } + + maxDepth () { + return this.finalizeFn(lineBuilder.single(this.theme.maxDepth)) + } } diff --git a/lib/getCtor.js b/lib/getCtor.js index db96604..244708e 100644 --- a/lib/getCtor.js +++ b/lib/getCtor.js @@ -1,39 +1,39 @@ export default function getCtor (stringTag, value) { - if (value.constructor) { - const name = value.constructor.name - return typeof name === 'string' && name !== '' - ? name - : null - } + if (value.constructor) { + const name = value.constructor.name + return typeof name === 'string' && name !== '' + ? name + : null + } - if (value.constructor === undefined) { - if (stringTag !== 'Object' || value instanceof Object) return null + if (value.constructor === undefined) { + if (stringTag !== 'Object' || value instanceof Object) return null - // Values without a constructor, that do not inherit from `Object`, but are - // tagged as objects, may come from `Object.create(null)`. Or they can come - // from a different realm, e.g.: - // - // ``` - // import vm from 'node:vm' - // vm.runInNewContext(` - // const Foo = function () {} - // Foo.prototype.constructor = undefined - // return new Foo() - // `) - // ``` - // - // Treat such objects as if they came from `Object.create(null)` (in the - // current realm) only if they do not have inherited properties. This allows - // these objects to be compared with object literals. - // - // This means `Object.create(null)` is not differentiated from `{}`. + // Values without a constructor, that do not inherit from `Object`, but are + // tagged as objects, may come from `Object.create(null)`. Or they can come + // from a different realm, e.g.: + // + // ``` + // import vm from 'node:vm' + // vm.runInNewContext(` + // const Foo = function () {} + // Foo.prototype.constructor = undefined + // return new Foo() + // `) + // ``` + // + // Treat such objects as if they came from `Object.create(null)` (in the + // current realm) only if they do not have inherited properties. This allows + // these objects to be compared with object literals. + // + // This means `Object.create(null)` is not differentiated from `{}`. - // Using `const` prevents Crankshaft optimizations - for (var p in value) { // eslint-disable-line no-var - if (!Object.hasOwn(value, p)) return null - } - return stringTag - } + // Using `const` prevents Crankshaft optimizations + for (var p in value) { // eslint-disable-line no-var + if (!Object.hasOwn(value, p)) return null + } + return stringTag + } - return null + return null } diff --git a/lib/getObjectKeys.js b/lib/getObjectKeys.js index 3f88941..6f3c521 100644 --- a/lib/getObjectKeys.js +++ b/lib/getObjectKeys.js @@ -1,32 +1,32 @@ import isEnumerable from './isEnumerable.js'; export default function getObjectKeys (obj, excludeListItemAccessorsBelowLength) { - const keys = [] - let size = 0 + const keys = [] + let size = 0 - // Sort property names, they should never be order-sensitive - const nameCandidates = Object.getOwnPropertyNames(obj).sort() - // Comparators should verify symbols in an order-insensitive manner if - // possible. - const symbolCandidates = Object.getOwnPropertySymbols(obj) + // Sort property names, they should never be order-sensitive + const nameCandidates = Object.getOwnPropertyNames(obj).sort() + // Comparators should verify symbols in an order-insensitive manner if + // possible. + const symbolCandidates = Object.getOwnPropertySymbols(obj) - for (const name of nameCandidates) { - let accept = true - if (excludeListItemAccessorsBelowLength > 0) { - const index = Number(name) - accept = !Number.isInteger(index) || index < 0 || index >= excludeListItemAccessorsBelowLength - } + for (const name of nameCandidates) { + let accept = true + if (excludeListItemAccessorsBelowLength > 0) { + const index = Number(name) + accept = !Number.isInteger(index) || index < 0 || index >= excludeListItemAccessorsBelowLength + } - if (accept && isEnumerable(obj, name)) { - keys[size++] = name - } - } + if (accept && isEnumerable(obj, name)) { + keys[size++] = name + } + } - for (const symbol of symbolCandidates) { - if (isEnumerable(obj, symbol)) { - keys[size++] = symbol - } - } + for (const symbol of symbolCandidates) { + if (isEnumerable(obj, symbol)) { + keys[size++] = symbol + } + } - return { keys, size } + return { keys, size } } diff --git a/lib/getStringTag.js b/lib/getStringTag.js index 24dc6c3..c3b8d6e 100644 --- a/lib/getStringTag.js +++ b/lib/getStringTag.js @@ -1,27 +1,27 @@ const ts = Object.prototype.toString function getStringTag (value) { - return ts.call(value).slice(8, -1) + return ts.call(value).slice(8, -1) } const fts = Function.prototype.toString const promiseCtorString = fts.call(Promise) const isPromise = value => { - if (!value.constructor) return false + if (!value.constructor) return false - try { - return fts.call(value.constructor) === promiseCtorString - } catch { - return false - } + try { + return fts.call(value.constructor) === promiseCtorString + } catch { + return false + } } const getStringTagWithPromiseWorkaround = value => { - const stringTag = getStringTag(value) - return stringTag === 'Object' && isPromise(value) - ? 'Promise' - : stringTag + const stringTag = getStringTag(value) + return stringTag === 'Object' && isPromise(value) + ? 'Promise' + : stringTag } export default getStringTag(Promise.resolve()) === 'Promise' - ? getStringTag - : getStringTagWithPromiseWorkaround + ? getStringTag + : getStringTagWithPromiseWorkaround diff --git a/lib/hasLength.js b/lib/hasLength.js index dcba308..e0b96a8 100644 --- a/lib/hasLength.js +++ b/lib/hasLength.js @@ -1,10 +1,10 @@ import {isLength} from './lodash/index.js' export default function hasLength (obj) { - return ( - Array.isArray(obj) || - (Object.hasOwn(obj, 'length') && - isLength(obj.length) && - (obj.length === 0 || '0' in obj)) - ) + return ( + Array.isArray(obj) || + (Object.hasOwn(obj, 'length') && + isLength(obj.length) && + (obj.length === 0 || '0' in obj)) + ) } diff --git a/lib/isEnumerable.js b/lib/isEnumerable.js index a2d97d4..3eab205 100644 --- a/lib/isEnumerable.js +++ b/lib/isEnumerable.js @@ -1,4 +1,4 @@ export default function isEnumerable (obj, key) { - const desc = Object.getOwnPropertyDescriptor(obj, key) - return desc && desc.enumerable + const desc = Object.getOwnPropertyDescriptor(obj, key) + return desc && desc.enumerable } diff --git a/lib/lineBuilder.js b/lib/lineBuilder.js index 60b51dc..2110631 100644 --- a/lib/lineBuilder.js +++ b/lib/lineBuilder.js @@ -2,308 +2,308 @@ const ACTUAL = Symbol('lineBuilder.gutters.ACTUAL') const EXPECTED = Symbol('lineBuilder.gutters.EXPECTED') function translateGutter (theme, invert, gutter) { - if (invert) { - if (gutter === ACTUAL) return theme.diffGutters.expected - if (gutter === EXPECTED) return theme.diffGutters.actual - } else { - if (gutter === ACTUAL) return theme.diffGutters.actual - if (gutter === EXPECTED) return theme.diffGutters.expected - } - return theme.diffGutters.padding + if (invert) { + if (gutter === ACTUAL) return theme.diffGutters.expected + if (gutter === EXPECTED) return theme.diffGutters.actual + } else { + if (gutter === ACTUAL) return theme.diffGutters.actual + if (gutter === EXPECTED) return theme.diffGutters.expected + } + return theme.diffGutters.padding } class Line { - constructor (isFirst, isLast, gutter, stringValue) { - this.isFirst = isFirst - this.isLast = isLast - this.gutter = gutter - this.stringValue = stringValue - } - - * [Symbol.iterator] () { - yield this - } - - get isEmpty () { - return false - } - - get hasGutter () { - return this.gutter !== null - } - - get isSingle () { - return this.isFirst && this.isLast - } - - append (other) { - return this.concat(other) - } - - concat (other) { - return new Collection() - .append(this) - .append(other) - } - - toString (options) { - if (options.diff === false) return this.stringValue - - return translateGutter(options.theme, options.invert, this.gutter) + this.stringValue - } - - mergeWithInfix (infix, other) { - if (other.isLine !== true) { - return new Collection() - .append(this) - .mergeWithInfix(infix, other) - } - - return new Line(this.isFirst, other.isLast, other.gutter, this.stringValue + infix + other.stringValue) - } - - withFirstPrefixed (prefix) { - if (!this.isFirst) return this - - return new Line(true, this.isLast, this.gutter, prefix + this.stringValue) - } - - withLastPostfixed (postfix) { - if (!this.isLast) return this - - return new Line(this.isFirst, true, this.gutter, this.stringValue + postfix) - } - - stripFlags () { - return new Line(false, false, this.gutter, this.stringValue) - } - - decompose () { - return new Collection() - .append(this) - .decompose() - } - - isLine = true + constructor (isFirst, isLast, gutter, stringValue) { + this.isFirst = isFirst + this.isLast = isLast + this.gutter = gutter + this.stringValue = stringValue + } + + * [Symbol.iterator] () { + yield this + } + + get isEmpty () { + return false + } + + get hasGutter () { + return this.gutter !== null + } + + get isSingle () { + return this.isFirst && this.isLast + } + + append (other) { + return this.concat(other) + } + + concat (other) { + return new Collection() + .append(this) + .append(other) + } + + toString (options) { + if (options.diff === false) return this.stringValue + + return translateGutter(options.theme, options.invert, this.gutter) + this.stringValue + } + + mergeWithInfix (infix, other) { + if (other.isLine !== true) { + return new Collection() + .append(this) + .mergeWithInfix(infix, other) + } + + return new Line(this.isFirst, other.isLast, other.gutter, this.stringValue + infix + other.stringValue) + } + + withFirstPrefixed (prefix) { + if (!this.isFirst) return this + + return new Line(true, this.isLast, this.gutter, prefix + this.stringValue) + } + + withLastPostfixed (postfix) { + if (!this.isLast) return this + + return new Line(this.isFirst, true, this.gutter, this.stringValue + postfix) + } + + stripFlags () { + return new Line(false, false, this.gutter, this.stringValue) + } + + decompose () { + return new Collection() + .append(this) + .decompose() + } + + isLine = true } class Collection { - constructor () { - this.buffer = [] - } - - * [Symbol.iterator] () { - for (const appended of this.buffer) { - for (const line of appended) yield line - } - } - - get isEmpty () { - return this.buffer.length === 0 - } - - get hasGutter () { - for (const line of this) { - if (line.hasGutter) return true - } - return false - } - - get isSingle () { - const iterator = this[Symbol.iterator]() - iterator.next() - return iterator.next().done === true - } - - append (lineOrLines) { - if (!lineOrLines.isEmpty) this.buffer.push(lineOrLines) - return this - } - - concat (other) { - return new Collection() - .append(this) - .append(other) - } - - toString (options) { - let lines = this - - if (options.invert) { - lines = new Collection() - let buffer = new Collection() - - let prev = null - for (const line of this) { - if (line.gutter === ACTUAL) { - if (prev !== null && prev.gutter !== ACTUAL && !buffer.isEmpty) { - lines.append(buffer) - buffer = new Collection() - } - - buffer.append(line) - } else if (line.gutter === EXPECTED) { - lines.append(line) - } else { - if (!buffer.isEmpty) { - lines.append(buffer) - buffer = new Collection() - } - - lines.append(line) - } - - prev = line - } - lines.append(buffer) - } - - return Array.from(lines, line => line.toString(options)).join('\n') - } - - mergeWithInfix (infix, from) { - if (from.isEmpty) throw new Error('Cannot merge, `from` is empty.') - - const otherLines = Array.from(from) - if (!otherLines[0].isFirst) throw new Error('Cannot merge, `from` has no first line.') - - const merged = new Collection() - let seenLast = false - for (const line of this) { - if (seenLast) throw new Error('Cannot merge line, the last line has already been seen.') - - if (!line.isLast) { - merged.append(line) - continue - } - - seenLast = true - for (const other of otherLines) { - if (other.isFirst) { - merged.append(line.mergeWithInfix(infix, other)) - } else { - merged.append(other) - } - } - } - return merged - } - - withFirstPrefixed (prefix) { - return new Collection() - .append(Array.from(this, line => line.withFirstPrefixed(prefix))) - } - - withLastPostfixed (postfix) { - return new Collection() - .append(Array.from(this, line => line.withLastPostfixed(postfix))) - } - - stripFlags () { - return new Collection() - .append(Array.from(this, line => line.stripFlags())) - } - - decompose () { - const first = { actual: new Collection(), expected: new Collection() } - const last = { actual: new Collection(), expected: new Collection() } - const remaining = new Collection() - - for (const line of this) { - if (line.isFirst && line.gutter === ACTUAL) { - first.actual.append(line) - } else if (line.isFirst && line.gutter === EXPECTED) { - first.expected.append(line) - } else if (line.isLast && line.gutter === ACTUAL) { - last.actual.append(line) - } else if (line.isLast && line.gutter === EXPECTED) { - last.expected.append(line) - } else { - remaining.append(line) - } - } - - return { first, last, remaining } - } - - isCollection = true + constructor () { + this.buffer = [] + } + + * [Symbol.iterator] () { + for (const appended of this.buffer) { + for (const line of appended) yield line + } + } + + get isEmpty () { + return this.buffer.length === 0 + } + + get hasGutter () { + for (const line of this) { + if (line.hasGutter) return true + } + return false + } + + get isSingle () { + const iterator = this[Symbol.iterator]() + iterator.next() + return iterator.next().done === true + } + + append (lineOrLines) { + if (!lineOrLines.isEmpty) this.buffer.push(lineOrLines) + return this + } + + concat (other) { + return new Collection() + .append(this) + .append(other) + } + + toString (options) { + let lines = this + + if (options.invert) { + lines = new Collection() + let buffer = new Collection() + + let prev = null + for (const line of this) { + if (line.gutter === ACTUAL) { + if (prev !== null && prev.gutter !== ACTUAL && !buffer.isEmpty) { + lines.append(buffer) + buffer = new Collection() + } + + buffer.append(line) + } else if (line.gutter === EXPECTED) { + lines.append(line) + } else { + if (!buffer.isEmpty) { + lines.append(buffer) + buffer = new Collection() + } + + lines.append(line) + } + + prev = line + } + lines.append(buffer) + } + + return Array.from(lines, line => line.toString(options)).join('\n') + } + + mergeWithInfix (infix, from) { + if (from.isEmpty) throw new Error('Cannot merge, `from` is empty.') + + const otherLines = Array.from(from) + if (!otherLines[0].isFirst) throw new Error('Cannot merge, `from` has no first line.') + + const merged = new Collection() + let seenLast = false + for (const line of this) { + if (seenLast) throw new Error('Cannot merge line, the last line has already been seen.') + + if (!line.isLast) { + merged.append(line) + continue + } + + seenLast = true + for (const other of otherLines) { + if (other.isFirst) { + merged.append(line.mergeWithInfix(infix, other)) + } else { + merged.append(other) + } + } + } + return merged + } + + withFirstPrefixed (prefix) { + return new Collection() + .append(Array.from(this, line => line.withFirstPrefixed(prefix))) + } + + withLastPostfixed (postfix) { + return new Collection() + .append(Array.from(this, line => line.withLastPostfixed(postfix))) + } + + stripFlags () { + return new Collection() + .append(Array.from(this, line => line.stripFlags())) + } + + decompose () { + const first = { actual: new Collection(), expected: new Collection() } + const last = { actual: new Collection(), expected: new Collection() } + const remaining = new Collection() + + for (const line of this) { + if (line.isFirst && line.gutter === ACTUAL) { + first.actual.append(line) + } else if (line.isFirst && line.gutter === EXPECTED) { + first.expected.append(line) + } else if (line.isLast && line.gutter === ACTUAL) { + last.actual.append(line) + } else if (line.isLast && line.gutter === EXPECTED) { + last.expected.append(line) + } else { + remaining.append(line) + } + } + + return { first, last, remaining } + } + + isCollection = true } function setDefaultGutter (iterable, gutter) { - return new Collection() - .append(Array.from(iterable, line => { - return line.gutter === null - ? new Line(line.isFirst, line.isLast, gutter, line.stringValue) - : line - })) + return new Collection() + .append(Array.from(iterable, line => { + return line.gutter === null + ? new Line(line.isFirst, line.isLast, gutter, line.stringValue) + : line + })) } export default { - buffer () { - return new Collection() - }, - - first (stringValue) { - return new Line(true, false, null, stringValue) - }, - - last (stringValue) { - return new Line(false, true, null, stringValue) - }, - - line (stringValue) { - return new Line(false, false, null, stringValue) - }, - - single (stringValue) { - return new Line(true, true, null, stringValue) - }, - - setDefaultGutter (lineOrCollection) { - return lineOrCollection - }, - - actual: { - first (stringValue) { - return new Line(true, false, ACTUAL, stringValue) - }, - - last (stringValue) { - return new Line(false, true, ACTUAL, stringValue) - }, - - line (stringValue) { - return new Line(false, false, ACTUAL, stringValue) - }, - - single (stringValue) { - return new Line(true, true, ACTUAL, stringValue) - }, - - setDefaultGutter (lineOrCollection) { - return setDefaultGutter(lineOrCollection, ACTUAL) - }, - }, - - expected: { - first (stringValue) { - return new Line(true, false, EXPECTED, stringValue) - }, - - last (stringValue) { - return new Line(false, true, EXPECTED, stringValue) - }, - - line (stringValue) { - return new Line(false, false, EXPECTED, stringValue) - }, - - single (stringValue) { - return new Line(true, true, EXPECTED, stringValue) - }, - - setDefaultGutter (lineOrCollection) { - return setDefaultGutter(lineOrCollection, EXPECTED) - }, - }, + buffer () { + return new Collection() + }, + + first (stringValue) { + return new Line(true, false, null, stringValue) + }, + + last (stringValue) { + return new Line(false, true, null, stringValue) + }, + + line (stringValue) { + return new Line(false, false, null, stringValue) + }, + + single (stringValue) { + return new Line(true, true, null, stringValue) + }, + + setDefaultGutter (lineOrCollection) { + return lineOrCollection + }, + + actual: { + first (stringValue) { + return new Line(true, false, ACTUAL, stringValue) + }, + + last (stringValue) { + return new Line(false, true, ACTUAL, stringValue) + }, + + line (stringValue) { + return new Line(false, false, ACTUAL, stringValue) + }, + + single (stringValue) { + return new Line(true, true, ACTUAL, stringValue) + }, + + setDefaultGutter (lineOrCollection) { + return setDefaultGutter(lineOrCollection, ACTUAL) + }, + }, + + expected: { + first (stringValue) { + return new Line(true, false, EXPECTED, stringValue) + }, + + last (stringValue) { + return new Line(false, true, EXPECTED, stringValue) + }, + + line (stringValue) { + return new Line(false, false, EXPECTED, stringValue) + }, + + single (stringValue) { + return new Line(true, true, EXPECTED, stringValue) + }, + + setDefaultGutter (lineOrCollection) { + return setDefaultGutter(lineOrCollection, EXPECTED) + }, + }, } diff --git a/lib/metaDescriptors/item.js b/lib/metaDescriptors/item.js index 51f0b58..e11d083 100644 --- a/lib/metaDescriptors/item.js +++ b/lib/metaDescriptors/item.js @@ -3,22 +3,22 @@ import * as formatUtils from '../formatUtils.js' import * as recursorUtils from '../recursorUtils.js' export function describeComplex (index, value) { - return new ComplexItem(index, value) + return new ComplexItem(index, value) } export function deserializeComplex (index, recursor) { - const value = recursor() - return new ComplexItem(index, value) + const value = recursor() + return new ComplexItem(index, value) } export function describePrimitive (index, value) { - return new PrimitiveItem(index, value) + return new PrimitiveItem(index, value) } export function deserializePrimitive (state) { - const index = state[0] - const value = state[1] - return new PrimitiveItem(index, value) + const index = state[0] + const value = state[1] + return new PrimitiveItem(index, value) } export const complexTag = Symbol('ComplexItem') @@ -26,222 +26,222 @@ export const complexTag = Symbol('ComplexItem') export const primitiveTag = Symbol('PrimitiveItem') class ComplexItem { - constructor (index, value) { - this.index = index - this.value = value - } - - createRecursor () { - return recursorUtils.singleValue(this.value) - } - - compare (expected) { - return expected.tag === complexTag && this.index === expected.index - ? this.value.compare(expected.value) - : UNEQUAL - } - - formatShallow (theme, indent) { - const increaseValueIndent = theme.item.increaseValueIndent === true - return new formatUtils.SingleValueFormatter(theme, value => { - if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, value) - } - - return value.withLastPostfixed(theme.item.after) - }, increaseValueIndent) - } - - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { - // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } - - // Try to line up this or remaining items with the expected items. - const lhsFork = recursorUtils.fork(lhsRecursor) - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected - - let expectedIsMissing = false - while (!expectedIsMissing && expected !== null && expected.isItem === true) { - if (expected.tag === complexTag) { - expectedIsMissing = compareComplexShape(this.value, expected.value) !== UNEQUAL - } - - expected = rhsFork.shared() - } - - let actualIsExtraneous = false - if (initialExpected.tag === complexTag) { - let actual = this - while (!actualIsExtraneous && actual !== null && actual.isItem === true) { - if (actual.tag === complexTag) { - actualIsExtraneous = compareComplexShape(actual.value, initialExpected.value) !== UNEQUAL - } - - actual = lhsFork.shared() - } - } else if (initialExpected.tag === primitiveTag) { - let actual = this - while (!actualIsExtraneous && actual !== null && actual.isItem === true) { - if (actual.tag === primitiveTag) { - actualIsExtraneous = initialExpected.value.compare(actual.value) === DEEP_EQUAL - } - - actual = lhsFork.shared() - } - } - - if (actualIsExtraneous && !expectedIsMissing) { - return { - actualIsExtraneous: true, - lhsRecursor: lhsFork.recursor, - rhsRecursor: recursorUtils.map( - recursorUtils.unshift(rhsFork.recursor, initialExpected), - next => { - if (next.isItem !== true) return next - - next.index++ - return next - }), - } - } - - if (expectedIsMissing && !actualIsExtraneous) { - return { - expectedIsMissing: true, - lhsRecursor: recursorUtils.map( - recursorUtils.unshift(lhsFork.recursor, this), - next => { - if (next.isItem !== true) return next - - next.index++ - return next - }), - rhsRecursor: rhsFork.recursor, - } - } - - const mustRecurse = this.tag === complexTag && initialExpected.tag === complexTag && - this.value.compare(initialExpected.value) !== UNEQUAL - return { - mustRecurse, - isUnequal: !mustRecurse, - lhsRecursor: lhsFork.recursor, - rhsRecursor: rhsFork.recursor, - } - } - - serialize () { - return this.index - } - - isItem = true - - tag = complexTag + constructor (index, value) { + this.index = index + this.value = value + } + + createRecursor () { + return recursorUtils.singleValue(this.value) + } + + compare (expected) { + return expected.tag === complexTag && this.index === expected.index + ? this.value.compare(expected.value) + : UNEQUAL + } + + formatShallow (theme, indent) { + const increaseValueIndent = theme.item.increaseValueIndent === true + return new formatUtils.SingleValueFormatter(theme, value => { + if (typeof theme.item.customFormat === 'function') { + return theme.item.customFormat(theme, indent, value) + } + + return value.withLastPostfixed(theme.item.after) + }, increaseValueIndent) + } + + prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // Circular values cannot be compared. They must be treated as being unequal when diffing. + if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + + // Try to line up this or remaining items with the expected items. + const lhsFork = recursorUtils.fork(lhsRecursor) + const rhsFork = recursorUtils.fork(rhsRecursor) + const initialExpected = expected + + let expectedIsMissing = false + while (!expectedIsMissing && expected !== null && expected.isItem === true) { + if (expected.tag === complexTag) { + expectedIsMissing = compareComplexShape(this.value, expected.value) !== UNEQUAL + } + + expected = rhsFork.shared() + } + + let actualIsExtraneous = false + if (initialExpected.tag === complexTag) { + let actual = this + while (!actualIsExtraneous && actual !== null && actual.isItem === true) { + if (actual.tag === complexTag) { + actualIsExtraneous = compareComplexShape(actual.value, initialExpected.value) !== UNEQUAL + } + + actual = lhsFork.shared() + } + } else if (initialExpected.tag === primitiveTag) { + let actual = this + while (!actualIsExtraneous && actual !== null && actual.isItem === true) { + if (actual.tag === primitiveTag) { + actualIsExtraneous = initialExpected.value.compare(actual.value) === DEEP_EQUAL + } + + actual = lhsFork.shared() + } + } + + if (actualIsExtraneous && !expectedIsMissing) { + return { + actualIsExtraneous: true, + lhsRecursor: lhsFork.recursor, + rhsRecursor: recursorUtils.map( + recursorUtils.unshift(rhsFork.recursor, initialExpected), + next => { + if (next.isItem !== true) return next + + next.index++ + return next + }), + } + } + + if (expectedIsMissing && !actualIsExtraneous) { + return { + expectedIsMissing: true, + lhsRecursor: recursorUtils.map( + recursorUtils.unshift(lhsFork.recursor, this), + next => { + if (next.isItem !== true) return next + + next.index++ + return next + }), + rhsRecursor: rhsFork.recursor, + } + } + + const mustRecurse = this.tag === complexTag && initialExpected.tag === complexTag && + this.value.compare(initialExpected.value) !== UNEQUAL + return { + mustRecurse, + isUnequal: !mustRecurse, + lhsRecursor: lhsFork.recursor, + rhsRecursor: rhsFork.recursor, + } + } + + serialize () { + return this.index + } + + isItem = true + + tag = complexTag } class PrimitiveItem { - constructor (index, value) { - this.index = index - this.value = value - } - - compare (expected) { - return expected.tag === primitiveTag && this.index === expected.index - ? this.value.compare(expected.value) - : UNEQUAL - } - - formatDeep (theme, indent) { - const increaseValueIndent = theme.item.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent - - // Since the value is formatted directly, modifiers are not applied. Apply - // modifiers to the item descriptor instead. - const formatted = this.value.formatDeep(theme, valueIndent) - - if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, formatted) - } - - return formatted.withLastPostfixed(theme.item.after) - } - - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { - const compareResult = this.compare(expected) - // Short-circuit when values are deeply equal. - if (compareResult === DEEP_EQUAL) return { compareResult } - - // Short-circut when values can be diffed directly. - if ( - expected.tag === primitiveTag && - this.value.tag === expected.value.tag && typeof this.value.diffDeep === 'function' - ) { - return { compareResult } - } - - // Try to line up this or remaining items with the expected items. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected - - do { - if (expected === null || expected.isItem !== true) { - return { - actualIsExtraneous: true, - rhsRecursor: recursorUtils.map( - recursorUtils.unshift(rhsFork.recursor, initialExpected), - next => { - if (next.isItem !== true) return next - - next.index++ - return next - }), - } - } - - if (this.value.compare(expected.value) === DEEP_EQUAL) { - return { - expectedIsMissing: true, - lhsRecursor: recursorUtils.map( - recursorUtils.unshift(lhsRecursor, this), - next => { - if (next.isItem !== true) return next - - next.index++ - return next - }), - rhsRecursor: rhsFork.recursor, - } - } - - expected = rhsFork.shared() - } while (true) - } - - diffDeep (expected, theme, indent, invert) { - // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null - - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent - - // Since the value is diffed directly, modifiers are not applied. Apply - // modifiers to the item descriptor instead. - const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) - if (diff === null) return null - - if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, diff) - } - - return diff.withLastPostfixed(theme.item.after) - } - - serialize () { - return [this.index, this.value] - } - - isItem = true - - tag = primitiveTag + constructor (index, value) { + this.index = index + this.value = value + } + + compare (expected) { + return expected.tag === primitiveTag && this.index === expected.index + ? this.value.compare(expected.value) + : UNEQUAL + } + + formatDeep (theme, indent) { + const increaseValueIndent = theme.item.increaseValueIndent === true + const valueIndent = increaseValueIndent ? indent.increase() : indent + + // Since the value is formatted directly, modifiers are not applied. Apply + // modifiers to the item descriptor instead. + const formatted = this.value.formatDeep(theme, valueIndent) + + if (typeof theme.item.customFormat === 'function') { + return theme.item.customFormat(theme, indent, formatted) + } + + return formatted.withLastPostfixed(theme.item.after) + } + + prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + const compareResult = this.compare(expected) + // Short-circuit when values are deeply equal. + if (compareResult === DEEP_EQUAL) return { compareResult } + + // Short-circut when values can be diffed directly. + if ( + expected.tag === primitiveTag && + this.value.tag === expected.value.tag && typeof this.value.diffDeep === 'function' + ) { + return { compareResult } + } + + // Try to line up this or remaining items with the expected items. + const rhsFork = recursorUtils.fork(rhsRecursor) + const initialExpected = expected + + do { + if (expected === null || expected.isItem !== true) { + return { + actualIsExtraneous: true, + rhsRecursor: recursorUtils.map( + recursorUtils.unshift(rhsFork.recursor, initialExpected), + next => { + if (next.isItem !== true) return next + + next.index++ + return next + }), + } + } + + if (this.value.compare(expected.value) === DEEP_EQUAL) { + return { + expectedIsMissing: true, + lhsRecursor: recursorUtils.map( + recursorUtils.unshift(lhsRecursor, this), + next => { + if (next.isItem !== true) return next + + next.index++ + return next + }), + rhsRecursor: rhsFork.recursor, + } + } + + expected = rhsFork.shared() + } while (true) + } + + diffDeep (expected, theme, indent, invert) { + // Verify a diff can be returned. + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + + const increaseValueIndent = theme.property.increaseValueIndent === true + const valueIndent = increaseValueIndent ? indent.increase() : indent + + // Since the value is diffed directly, modifiers are not applied. Apply + // modifiers to the item descriptor instead. + const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) + if (diff === null) return null + + if (typeof theme.item.customFormat === 'function') { + return theme.item.customFormat(theme, indent, diff) + } + + return diff.withLastPostfixed(theme.item.after) + } + + serialize () { + return [this.index, this.value] + } + + isItem = true + + tag = primitiveTag } diff --git a/lib/metaDescriptors/mapEntry.js b/lib/metaDescriptors/mapEntry.js index 4166cf9..863ec21 100644 --- a/lib/metaDescriptors/mapEntry.js +++ b/lib/metaDescriptors/mapEntry.js @@ -4,213 +4,213 @@ import * as recursorUtils from '../recursorUtils.js' import * as themeUtils from '../themeUtils.js' export function describe (keyDescriptor, valueDescriptor) { - const keyIsPrimitive = keyDescriptor.isPrimitive === true - const valueIsPrimitive = valueDescriptor.isPrimitive === true + const keyIsPrimitive = keyDescriptor.isPrimitive === true + const valueIsPrimitive = valueDescriptor.isPrimitive === true - return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) + return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) } export function deserialize (state, recursor) { - const keyIsPrimitive = state[0] - const valueIsPrimitive = state[1] - const keyDescriptor = recursor() - const valueDescriptor = recursor() + const keyIsPrimitive = state[0] + const valueIsPrimitive = state[1] + const keyDescriptor = recursor() + const valueDescriptor = recursor() - return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) + return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) } export const tag = Symbol('MapEntry') function mergeWithKey (theme, key, values) { - const lines = lineBuilder.buffer() - const keyRemainder = lineBuilder.buffer() - for (const line of key) { - if (!line.isLast && !line.hasGutter) { - lines.append(line) - } else { - keyRemainder.append(line) - } - } - for (const value of values) { - lines.append(keyRemainder.mergeWithInfix(theme.mapEntry.separator, value).withLastPostfixed(theme.mapEntry.after)) - } - return lines + const lines = lineBuilder.buffer() + const keyRemainder = lineBuilder.buffer() + for (const line of key) { + if (!line.isLast && !line.hasGutter) { + lines.append(line) + } else { + keyRemainder.append(line) + } + } + for (const value of values) { + lines.append(keyRemainder.mergeWithInfix(theme.mapEntry.separator, value).withLastPostfixed(theme.mapEntry.after)) + } + return lines } class MapEntry { - constructor (key, value, keyIsPrimitive, valueIsPrimitive) { - this.key = key - this.value = value - this.keyIsPrimitive = keyIsPrimitive - this.valueIsPrimitive = valueIsPrimitive - } - - createRecursor () { - let emitKey = true - let emitValue = true - - return () => { - if (emitKey) { - emitKey = false - return this.key - } - - if (emitValue) { - emitValue = false - return this.value - } - - return null - } - } - - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.keyIsPrimitive !== expected.keyIsPrimitive) return UNEQUAL - if (this.valueIsPrimitive !== expected.valueIsPrimitive) return UNEQUAL - - if (!this.keyIsPrimitive) return SHALLOW_EQUAL - - const keyResult = this.key.compare(expected.key) - if (keyResult !== DEEP_EQUAL) return keyResult - - if (!this.valueIsPrimitive) return SHALLOW_EQUAL - return this.value.compare(expected.value) - } - - formatDeep (theme, indent) { - // Verify the map entry can be formatted directly. - if (!this.keyIsPrimitive || typeof this.value.formatDeep !== 'function') return null - - // Since formatShallow() would result in theme modifiers being applied - // before the key and value are formatted, do the same here. - const value = this.value.formatDeep(themeUtils.applyModifiersToOriginal(this.value, theme), indent) - if (value === null) return null - - const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent) - return mergeWithKey(theme, key, [value]) - } - - formatShallow (theme, indent) { - let key = null - const values = [] - return { - append: (formatted, origin) => { - if (this.key === origin) { - key = formatted - } else { - values.push(formatted) - } - }, - finalize () { - return mergeWithKey(theme, key, values) - }, - } - } - - diffDeep (expected, theme, indent, invert) { - // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null - // Only use this logic to format value diffs when the keys are primitive and equal. - if (!this.keyIsPrimitive || !expected.keyIsPrimitive || this.key.compare(expected.key) !== DEEP_EQUAL) { - return null - } - - // Since formatShallow() would result in theme modifiers being applied - // before the key and value are formatted, do the same here. - const diff = this.value.diffDeep(expected.value, themeUtils.applyModifiersToOriginal(this.value, theme), indent, invert) - if (diff === null) return null - - const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent, '') - return mergeWithKey(theme, key, [diff]) - } - - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { - // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } - - const compareResult = this.compare(expected) - const keysAreEqual = this.tag === expected.tag && this.key.compare(expected.key) === DEEP_EQUAL - // Short-circuit when keys and/or values are deeply equal. - if (compareResult === DEEP_EQUAL || keysAreEqual) return { compareResult } - - // Try to line up this or remaining map entries with the expected entries. - const lhsFork = recursorUtils.fork(lhsRecursor) - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected - - let expectedIsMissing = false - while (!expectedIsMissing && expected !== null && this.tag === expected.tag) { - if (expected.keyIsPrimitive) { - expectedIsMissing = this.key.compare(expected.key) !== UNEQUAL - } else { - expectedIsMissing = compareComplexShape(this.key, expected.key) !== UNEQUAL - } - - expected = rhsFork.shared() - } - - let actualIsExtraneous = false - if (this.tag === initialExpected.tag) { - if (initialExpected.keyIsPrimitive) { - let actual = this - while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { - if (actual.keyIsPrimitive) { - actualIsExtraneous = initialExpected.key.compare(actual.key) === DEEP_EQUAL - } - - actual = lhsFork.shared() - } - } else { - let actual = this - while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { - if (!actual.keyIsPrimitive) { - actualIsExtraneous = compareComplexShape(actual.key, initialExpected.key) !== UNEQUAL - } - - actual = lhsFork.shared() - } - } - } - - if (actualIsExtraneous && !expectedIsMissing) { - return { - actualIsExtraneous: true, - lhsRecursor: lhsFork.recursor, - rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } - } - - if (expectedIsMissing && !actualIsExtraneous) { - return { - expectedIsMissing: true, - lhsRecursor: recursorUtils.unshift(lhsFork.recursor, this), - rhsRecursor: rhsFork.recursor, - } - } - - let mustRecurse = false - if (!this.keyIsPrimitive && !initialExpected.keyIsPrimitive) { - if (this.valueIsPrimitive || initialExpected.valueIsPrimitive) { - mustRecurse = this.value.compare(initialExpected.value) !== UNEQUAL - } else { - mustRecurse = compareComplexShape(this.value, initialExpected.value) !== UNEQUAL - } - } - - return { - mustRecurse, - isUnequal: !mustRecurse, - lhsRecursor: lhsFork.recursor, - rhsRecursor: rhsFork.recursor, - } - } - - serialize () { - return [this.keyIsPrimitive, this.valueIsPrimitive] - } - - isMapEntry = true - - tag = tag + constructor (key, value, keyIsPrimitive, valueIsPrimitive) { + this.key = key + this.value = value + this.keyIsPrimitive = keyIsPrimitive + this.valueIsPrimitive = valueIsPrimitive + } + + createRecursor () { + let emitKey = true + let emitValue = true + + return () => { + if (emitKey) { + emitKey = false + return this.key + } + + if (emitValue) { + emitValue = false + return this.value + } + + return null + } + } + + compare (expected) { + if (this.tag !== expected.tag) return UNEQUAL + if (this.keyIsPrimitive !== expected.keyIsPrimitive) return UNEQUAL + if (this.valueIsPrimitive !== expected.valueIsPrimitive) return UNEQUAL + + if (!this.keyIsPrimitive) return SHALLOW_EQUAL + + const keyResult = this.key.compare(expected.key) + if (keyResult !== DEEP_EQUAL) return keyResult + + if (!this.valueIsPrimitive) return SHALLOW_EQUAL + return this.value.compare(expected.value) + } + + formatDeep (theme, indent) { + // Verify the map entry can be formatted directly. + if (!this.keyIsPrimitive || typeof this.value.formatDeep !== 'function') return null + + // Since formatShallow() would result in theme modifiers being applied + // before the key and value are formatted, do the same here. + const value = this.value.formatDeep(themeUtils.applyModifiersToOriginal(this.value, theme), indent) + if (value === null) return null + + const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent) + return mergeWithKey(theme, key, [value]) + } + + formatShallow (theme, indent) { + let key = null + const values = [] + return { + append: (formatted, origin) => { + if (this.key === origin) { + key = formatted + } else { + values.push(formatted) + } + }, + finalize () { + return mergeWithKey(theme, key, values) + }, + } + } + + diffDeep (expected, theme, indent, invert) { + // Verify a diff can be returned. + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + // Only use this logic to format value diffs when the keys are primitive and equal. + if (!this.keyIsPrimitive || !expected.keyIsPrimitive || this.key.compare(expected.key) !== DEEP_EQUAL) { + return null + } + + // Since formatShallow() would result in theme modifiers being applied + // before the key and value are formatted, do the same here. + const diff = this.value.diffDeep(expected.value, themeUtils.applyModifiersToOriginal(this.value, theme), indent, invert) + if (diff === null) return null + + const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent, '') + return mergeWithKey(theme, key, [diff]) + } + + prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // Circular values cannot be compared. They must be treated as being unequal when diffing. + if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + + const compareResult = this.compare(expected) + const keysAreEqual = this.tag === expected.tag && this.key.compare(expected.key) === DEEP_EQUAL + // Short-circuit when keys and/or values are deeply equal. + if (compareResult === DEEP_EQUAL || keysAreEqual) return { compareResult } + + // Try to line up this or remaining map entries with the expected entries. + const lhsFork = recursorUtils.fork(lhsRecursor) + const rhsFork = recursorUtils.fork(rhsRecursor) + const initialExpected = expected + + let expectedIsMissing = false + while (!expectedIsMissing && expected !== null && this.tag === expected.tag) { + if (expected.keyIsPrimitive) { + expectedIsMissing = this.key.compare(expected.key) !== UNEQUAL + } else { + expectedIsMissing = compareComplexShape(this.key, expected.key) !== UNEQUAL + } + + expected = rhsFork.shared() + } + + let actualIsExtraneous = false + if (this.tag === initialExpected.tag) { + if (initialExpected.keyIsPrimitive) { + let actual = this + while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { + if (actual.keyIsPrimitive) { + actualIsExtraneous = initialExpected.key.compare(actual.key) === DEEP_EQUAL + } + + actual = lhsFork.shared() + } + } else { + let actual = this + while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { + if (!actual.keyIsPrimitive) { + actualIsExtraneous = compareComplexShape(actual.key, initialExpected.key) !== UNEQUAL + } + + actual = lhsFork.shared() + } + } + } + + if (actualIsExtraneous && !expectedIsMissing) { + return { + actualIsExtraneous: true, + lhsRecursor: lhsFork.recursor, + rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), + } + } + + if (expectedIsMissing && !actualIsExtraneous) { + return { + expectedIsMissing: true, + lhsRecursor: recursorUtils.unshift(lhsFork.recursor, this), + rhsRecursor: rhsFork.recursor, + } + } + + let mustRecurse = false + if (!this.keyIsPrimitive && !initialExpected.keyIsPrimitive) { + if (this.valueIsPrimitive || initialExpected.valueIsPrimitive) { + mustRecurse = this.value.compare(initialExpected.value) !== UNEQUAL + } else { + mustRecurse = compareComplexShape(this.value, initialExpected.value) !== UNEQUAL + } + } + + return { + mustRecurse, + isUnequal: !mustRecurse, + lhsRecursor: lhsFork.recursor, + rhsRecursor: rhsFork.recursor, + } + } + + serialize () { + return [this.keyIsPrimitive, this.valueIsPrimitive] + } + + isMapEntry = true + + tag = tag } diff --git a/lib/metaDescriptors/pointer.js b/lib/metaDescriptors/pointer.js index 28841a9..2e1137c 100644 --- a/lib/metaDescriptors/pointer.js +++ b/lib/metaDescriptors/pointer.js @@ -1,7 +1,7 @@ import { UNEQUAL } from '../constants.js' export function describe (index) { - return new Pointer(index) + return new Pointer(index) } export const deserialize = describe @@ -9,21 +9,21 @@ export const deserialize = describe export const tag = Symbol('Pointer') class Pointer { - constructor (index) { - this.index = index - } + constructor (index) { + this.index = index + } - // Pointers cannot be compared, and are not expected to be part of the - // comparisons. - compare (expected) { - return UNEQUAL - } + // Pointers cannot be compared, and are not expected to be part of the + // comparisons. + compare (expected) { + return UNEQUAL + } - serialize () { - return this.index - } + serialize () { + return this.index + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/metaDescriptors/property.js b/lib/metaDescriptors/property.js index 3537c68..d43a11c 100644 --- a/lib/metaDescriptors/property.js +++ b/lib/metaDescriptors/property.js @@ -4,22 +4,22 @@ import {tag as symbolPrimitive} from '../primitiveValues/symbol.js' import * as recursorUtils from '../recursorUtils.js' export function describeComplex (key, value) { - return new ComplexProperty(key, value) + return new ComplexProperty(key, value) } export function deserializeComplex (key, recursor) { - const value = recursor() - return new ComplexProperty(key, value) + const value = recursor() + return new ComplexProperty(key, value) } export function describePrimitive (key, value) { - return new PrimitiveProperty(key, value) + return new PrimitiveProperty(key, value) } export function deserializePrimitive (state) { - const key = state[0] - const value = state[1] - return new PrimitiveProperty(key, value) + const key = state[0] + const value = state[1] + return new PrimitiveProperty(key, value) } export const complexTag = Symbol('ComplexProperty') @@ -27,155 +27,155 @@ export const complexTag = Symbol('ComplexProperty') export const primitiveTag = Symbol('PrimitiveProperty') class Property { - constructor (key) { - this.key = key - } - - compareKeys (expected) { - const result = this.key.compare(expected.key) - // Return AMBIGUOUS if symbol keys are unequal. It's likely that properties - // are compared in order of declaration, which is not the desired strategy. - // Returning AMBIGUOUS allows compare() and diff() to recognize this - // situation and sort the symbol properties before comparing them. - return result === UNEQUAL && this.key.tag === symbolPrimitive && expected.key.tag === symbolPrimitive - ? AMBIGUOUS - : result - } - - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { - // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } - - // Try to line up this or remaining properties with the expected properties. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected - - do { - if (expected === null || expected.isProperty !== true) { - return { - actualIsExtraneous: true, - rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } - } else if (this.key.compare(expected.key) === DEEP_EQUAL) { - if (expected === initialExpected) { - return null - } else { - return { - expectedIsMissing: true, - lhsRecursor: recursorUtils.unshift(lhsRecursor, this), - rhsRecursor: rhsFork.recursor, - } - } - } - - expected = rhsFork.shared() - } while (true) - } - - isProperty = true + constructor (key) { + this.key = key + } + + compareKeys (expected) { + const result = this.key.compare(expected.key) + // Return AMBIGUOUS if symbol keys are unequal. It's likely that properties + // are compared in order of declaration, which is not the desired strategy. + // Returning AMBIGUOUS allows compare() and diff() to recognize this + // situation and sort the symbol properties before comparing them. + return result === UNEQUAL && this.key.tag === symbolPrimitive && expected.key.tag === symbolPrimitive + ? AMBIGUOUS + : result + } + + prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // Circular values cannot be compared. They must be treated as being unequal when diffing. + if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + + // Try to line up this or remaining properties with the expected properties. + const rhsFork = recursorUtils.fork(rhsRecursor) + const initialExpected = expected + + do { + if (expected === null || expected.isProperty !== true) { + return { + actualIsExtraneous: true, + rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), + } + } else if (this.key.compare(expected.key) === DEEP_EQUAL) { + if (expected === initialExpected) { + return null + } else { + return { + expectedIsMissing: true, + lhsRecursor: recursorUtils.unshift(lhsRecursor, this), + rhsRecursor: rhsFork.recursor, + } + } + } + + expected = rhsFork.shared() + } while (true) + } + + isProperty = true } class ComplexProperty extends Property { - constructor (key, value) { - super(key) - this.value = value - } - - createRecursor () { - return recursorUtils.singleValue(this.value) - } - - compare (expected) { - if (expected.isProperty !== true) return UNEQUAL - - const keyResult = this.compareKeys(expected) - if (keyResult !== DEEP_EQUAL) return keyResult - - return this.tag === expected.tag - ? this.value.compare(expected.value) - : UNEQUAL - } - - formatShallow (theme, indent) { - const increaseValueIndent = theme.property.increaseValueIndent === true - return new formatUtils.SingleValueFormatter(theme, value => { - if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, value) - } - - return value - .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) - }, increaseValueIndent) - } - - serialize () { - return this.key - } - - tag = complexTag + constructor (key, value) { + super(key) + this.value = value + } + + createRecursor () { + return recursorUtils.singleValue(this.value) + } + + compare (expected) { + if (expected.isProperty !== true) return UNEQUAL + + const keyResult = this.compareKeys(expected) + if (keyResult !== DEEP_EQUAL) return keyResult + + return this.tag === expected.tag + ? this.value.compare(expected.value) + : UNEQUAL + } + + formatShallow (theme, indent) { + const increaseValueIndent = theme.property.increaseValueIndent === true + return new formatUtils.SingleValueFormatter(theme, value => { + if (typeof theme.property.customFormat === 'function') { + return theme.property.customFormat(theme, indent, this.key, value) + } + + return value + .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) + .withLastPostfixed(theme.property.after) + }, increaseValueIndent) + } + + serialize () { + return this.key + } + + tag = complexTag } class PrimitiveProperty extends Property { - constructor (key, value) { - super(key) - this.value = value - } - - compare (expected) { - if (expected.isProperty !== true) return UNEQUAL - - const keyResult = this.compareKeys(expected) - if (keyResult !== DEEP_EQUAL) return keyResult - - return this.tag !== expected.tag - ? UNEQUAL - : this.value.compare(expected.value) - } - - formatDeep (theme, indent) { - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent - - // Since the key and value are formatted directly, modifiers are not - // applied. Apply modifiers to the property descriptor instead. - const formatted = this.value.formatDeep(theme, valueIndent) - - if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, formatted) - } - - return formatted - .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) - } - - diffDeep (expected, theme, indent, invert) { - // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null - // Only use this logic to diff values when the keys are the same. - if (this.key.compare(expected.key) !== DEEP_EQUAL) return null - - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent - - // Since the key and value are diffed directly, modifiers are not - // applied. Apply modifiers to the property descriptor instead. - const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) - if (diff === null) return null - - if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, diff) - } - - return diff - .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) - } - - serialize () { - return [this.key, this.value] - } - - tag = primitiveTag + constructor (key, value) { + super(key) + this.value = value + } + + compare (expected) { + if (expected.isProperty !== true) return UNEQUAL + + const keyResult = this.compareKeys(expected) + if (keyResult !== DEEP_EQUAL) return keyResult + + return this.tag !== expected.tag + ? UNEQUAL + : this.value.compare(expected.value) + } + + formatDeep (theme, indent) { + const increaseValueIndent = theme.property.increaseValueIndent === true + const valueIndent = increaseValueIndent ? indent.increase() : indent + + // Since the key and value are formatted directly, modifiers are not + // applied. Apply modifiers to the property descriptor instead. + const formatted = this.value.formatDeep(theme, valueIndent) + + if (typeof theme.property.customFormat === 'function') { + return theme.property.customFormat(theme, indent, this.key, formatted) + } + + return formatted + .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) + .withLastPostfixed(theme.property.after) + } + + diffDeep (expected, theme, indent, invert) { + // Verify a diff can be returned. + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + // Only use this logic to diff values when the keys are the same. + if (this.key.compare(expected.key) !== DEEP_EQUAL) return null + + const increaseValueIndent = theme.property.increaseValueIndent === true + const valueIndent = increaseValueIndent ? indent.increase() : indent + + // Since the key and value are diffed directly, modifiers are not + // applied. Apply modifiers to the property descriptor instead. + const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) + if (diff === null) return null + + if (typeof theme.property.customFormat === 'function') { + return theme.property.customFormat(theme, indent, this.key, diff) + } + + return diff + .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) + .withLastPostfixed(theme.property.after) + } + + serialize () { + return [this.key, this.value] + } + + tag = primitiveTag } diff --git a/lib/metaDescriptors/stats.js b/lib/metaDescriptors/stats.js index 20cafa0..02f6e3f 100644 --- a/lib/metaDescriptors/stats.js +++ b/lib/metaDescriptors/stats.js @@ -3,27 +3,27 @@ import lineBuilder from '../lineBuilder.js' import * as recursorUtils from '../recursorUtils.js' export function describeIterableRecursor (recursor) { - return new IterableStats(recursor.size) + return new IterableStats(recursor.size) } export function describeListRecursor (recursor) { - return new ListStats(recursor.size) + return new ListStats(recursor.size) } export function describePropertyRecursor (recursor) { - return new PropertyStats(recursor.size) + return new PropertyStats(recursor.size) } export function deserializeIterableStats (size) { - return new IterableStats(size) + return new IterableStats(size) } export function deserializeListStats (size) { - return new ListStats(size) + return new ListStats(size) } export function deserializePropertyStats (size) { - return new PropertyStats(size) + return new PropertyStats(size) } export const iterableTag = Symbol('IterableStats') @@ -33,94 +33,94 @@ export const listTag = Symbol('ListStats') export const propertyTag = Symbol('PropertyStats') class Stats { - constructor (size) { - this.size = size - } - - formatDeep (theme) { - return lineBuilder.single(theme.stats.separator) - } - - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape) { - if (expected.isStats !== true || expected.tag === this.tag) return null - - // Try to line up stats descriptors with the same tag. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected - - const missing = [] - while (expected !== null && this.tag !== expected.tag) { - missing.push(expected) - expected = rhsFork.shared() - } - - if (expected !== null && missing.length > 0) { - return { - multipleAreMissing: true, - descriptors: missing, - lhsRecursor: recursorUtils.unshift(lhsRecursor, this), - // Use original `rhsRecursor`, not `rhsFork`, since the consumed - // descriptors are returned with the `missing` array. - rhsRecursor: recursorUtils.unshift(rhsRecursor, expected), - } - } - - const lhsFork = recursorUtils.fork(lhsRecursor) - let actual = this - - const extraneous = [] - while (actual !== null && actual.tag !== initialExpected.tag) { - extraneous.push(actual) - actual = lhsFork.shared() - } - - if (actual !== null && extraneous.length > 0) { - return { - multipleAreExtraneous: true, - descriptors: extraneous, - // Use original `lhsRecursor`, not `lhsFork`, since the consumed - // descriptors are returned with the `extraneous` array. - lhsRecursor: recursorUtils.unshift(lhsRecursor, actual), - rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } - } - - return null - } - - serialize () { - return this.size - } - - isStats = true + constructor (size) { + this.size = size + } + + formatDeep (theme) { + return lineBuilder.single(theme.stats.separator) + } + + prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape) { + if (expected.isStats !== true || expected.tag === this.tag) return null + + // Try to line up stats descriptors with the same tag. + const rhsFork = recursorUtils.fork(rhsRecursor) + const initialExpected = expected + + const missing = [] + while (expected !== null && this.tag !== expected.tag) { + missing.push(expected) + expected = rhsFork.shared() + } + + if (expected !== null && missing.length > 0) { + return { + multipleAreMissing: true, + descriptors: missing, + lhsRecursor: recursorUtils.unshift(lhsRecursor, this), + // Use original `rhsRecursor`, not `rhsFork`, since the consumed + // descriptors are returned with the `missing` array. + rhsRecursor: recursorUtils.unshift(rhsRecursor, expected), + } + } + + const lhsFork = recursorUtils.fork(lhsRecursor) + let actual = this + + const extraneous = [] + while (actual !== null && actual.tag !== initialExpected.tag) { + extraneous.push(actual) + actual = lhsFork.shared() + } + + if (actual !== null && extraneous.length > 0) { + return { + multipleAreExtraneous: true, + descriptors: extraneous, + // Use original `lhsRecursor`, not `lhsFork`, since the consumed + // descriptors are returned with the `extraneous` array. + lhsRecursor: recursorUtils.unshift(lhsRecursor, actual), + rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), + } + } + + return null + } + + serialize () { + return this.size + } + + isStats = true } class IterableStats extends Stats { - compare (expected) { - return expected.tag === iterableTag && this.size === expected.size - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === iterableTag && this.size === expected.size + ? DEEP_EQUAL + : UNEQUAL + } - tag = iterableTag + tag = iterableTag } class ListStats extends Stats { - compare (expected) { - return expected.tag === listTag && this.size === expected.size - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === listTag && this.size === expected.size + ? DEEP_EQUAL + : UNEQUAL + } - tag = listTag + tag = listTag } class PropertyStats extends Stats { - compare (expected) { - return expected.tag === propertyTag && this.size === expected.size - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === propertyTag && this.size === expected.size + ? DEEP_EQUAL + : UNEQUAL + } - tag = propertyTag + tag = propertyTag } diff --git a/lib/pluginRegistry.js b/lib/pluginRegistry.js index fc03fa9..6cb83b0 100644 --- a/lib/pluginRegistry.js +++ b/lib/pluginRegistry.js @@ -19,198 +19,198 @@ const descriptorRegistry = new Map() const registry = new Map() class PluginError extends Error { - constructor (message, plugin) { - super(message) - this.name = 'PluginError' - this.plugin = plugin - } + constructor (message, plugin) { + super(message) + this.name = 'PluginError' + this.plugin = plugin + } } class PluginTypeError extends TypeError { - constructor (message, plugin) { - super(message) - this.name = 'PluginTypeError' - this.plugin = plugin - } + constructor (message, plugin) { + super(message) + this.name = 'PluginTypeError' + this.plugin = plugin + } } class UnsupportedApiError extends PluginError { - constructor (plugin) { - super('Plugin requires an unsupported API version', plugin) - this.name = 'UnsupportedApiError' - } + constructor (plugin) { + super('Plugin requires an unsupported API version', plugin) + this.name = 'UnsupportedApiError' + } } class UnsupportedError extends PluginError { - constructor (plugin) { - super('Plugin does not support this version of Concordance', plugin) - this.name = 'UnsupportedError' - } + constructor (plugin) { + super('Plugin does not support this version of Concordance', plugin) + this.name = 'UnsupportedError' + } } class DuplicateDescriptorTagError extends PluginError { - constructor (tag, plugin) { - super(`Could not add descriptor: tag ${String(tag)} has already been registered`, plugin) - this.name = 'DuplicateDescriptorTagError' - this.tag = tag - } + constructor (tag, plugin) { + super(`Could not add descriptor: tag ${String(tag)} has already been registered`, plugin) + this.name = 'DuplicateDescriptorTagError' + this.tag = tag + } } class DuplicateDescriptorIdError extends PluginError { - constructor (id, plugin) { - const printed = typeof id === 'number' - ? `0x${id.toString(16).toUpperCase()}` - : String(id) - super(`Could not add descriptor: id ${printed} has already been registered`, plugin) - this.name = 'DuplicateDescriptorIdError' - this.id = id - } + constructor (id, plugin) { + const printed = typeof id === 'number' + ? `0x${id.toString(16).toUpperCase()}` + : String(id) + super(`Could not add descriptor: id ${printed} has already been registered`, plugin) + this.name = 'DuplicateDescriptorIdError' + this.id = id + } } function verify (plugin) { - if (typeof plugin.name !== 'string' || !plugin.name) { - throw new PluginTypeError('Plugin must have a `name`', plugin) - } - - if (plugin.apiVersion !== API_VERSION) { - throw new UnsupportedApiError(plugin) - } - - if ('minimalConcordanceVersion' in plugin) { - if (!semver.valid(plugin.minimalConcordanceVersion)) { - throw new PluginTypeError('If specified, `minimalConcordanceVersion` must be a valid SemVer version', plugin) - } - - const range = `>=${plugin.minimalConcordanceVersion}` - if (!semver.satisfies(CONCORDANCE_VERSION, range)) { - throw new UnsupportedError(plugin) - } - } + if (typeof plugin.name !== 'string' || !plugin.name) { + throw new PluginTypeError('Plugin must have a `name`', plugin) + } + + if (plugin.apiVersion !== API_VERSION) { + throw new UnsupportedApiError(plugin) + } + + if ('minimalConcordanceVersion' in plugin) { + if (!semver.valid(plugin.minimalConcordanceVersion)) { + throw new PluginTypeError('If specified, `minimalConcordanceVersion` must be a valid SemVer version', plugin) + } + + const range = `>=${plugin.minimalConcordanceVersion}` + if (!semver.satisfies(CONCORDANCE_VERSION, range)) { + throw new UnsupportedError(plugin) + } + } } // Selectively expose descriptor tags. const publicDescriptorTags = Object.freeze({ - complexItem: itemDescriptor.complexTag, - primitiveItem: itemDescriptor.primitiveTag, - primitiveProperty: propertyDescriptor.primitiveTag, - string: stringDescriptor.tag, + complexItem: itemDescriptor.complexTag, + primitiveItem: itemDescriptor.primitiveTag, + primitiveProperty: propertyDescriptor.primitiveTag, + string: stringDescriptor.tag, }) // Don't expose `setDefaultGutter()`. const publicLineBuilder = Object.freeze({ - buffer: lineBuilder.buffer, - first: lineBuilder.first, - last: lineBuilder.last, - line: lineBuilder.line, - single: lineBuilder.single, - actual: Object.freeze({ - buffer: lineBuilder.actual.buffer, - first: lineBuilder.actual.first, - last: lineBuilder.actual.last, - line: lineBuilder.actual.line, - single: lineBuilder.actual.single, - }), - expected: Object.freeze({ - buffer: lineBuilder.expected.buffer, - first: lineBuilder.expected.first, - last: lineBuilder.expected.last, - line: lineBuilder.expected.line, - single: lineBuilder.expected.single, - }), + buffer: lineBuilder.buffer, + first: lineBuilder.first, + last: lineBuilder.last, + line: lineBuilder.line, + single: lineBuilder.single, + actual: Object.freeze({ + buffer: lineBuilder.actual.buffer, + first: lineBuilder.actual.first, + last: lineBuilder.actual.last, + line: lineBuilder.actual.line, + single: lineBuilder.actual.single, + }), + expected: Object.freeze({ + buffer: lineBuilder.expected.buffer, + first: lineBuilder.expected.first, + last: lineBuilder.expected.last, + line: lineBuilder.expected.line, + single: lineBuilder.expected.single, + }), }) function modifyTheme (descriptor, modifier) { - themeUtils.addModifier(descriptor, modifier) - return descriptor + themeUtils.addModifier(descriptor, modifier) + return descriptor } export function add (plugin) { - verify(plugin) - - const name = plugin.name - if (registry.has(name)) return registry.get(name) - - const id2deserialize = new Map() - const tag2id = new Map() - const addDescriptor = (id, tag, deserialize) => { - if (id2deserialize.has(id)) throw new DuplicateDescriptorIdError(id, plugin) - if (descriptorRegistry.has(tag) || tag2id.has(tag)) throw new DuplicateDescriptorTagError(tag, plugin) - - id2deserialize.set(id, deserialize) - tag2id.set(tag, id) - } - - const tryDescribeValue = plugin.register({ - // Concordance makes assumptions about when AMBIGUOUS occurs. Do not expose - // it to plugins. - UNEQUAL: constants.UNEQUAL, - SHALLOW_EQUAL: constants.SHALLOW_EQUAL, - DEEP_EQUAL: constants.DEEP_EQUAL, - - ObjectValue: object.ObjectValue, - DescribedMixin: object.DescribedMixin, - DeserializedMixin: object.DeserializedMixin, - - addDescriptor, - applyThemeModifiers: themeUtils.applyModifiers, - descriptorTags: publicDescriptorTags, - lineBuilder: publicLineBuilder, - mapRecursor: recursorUtils.map, - modifyTheme, - wrapFromTheme: formatUtils.wrap, - }) - - const registered = { - id2deserialize, - serializerVersion: plugin.serializerVersion, - name, - tag2id, - theme: plugin.theme || {}, - tryDescribeValue, - } - - registry.set(name, registered) - for (const tag of tag2id.keys()) { - descriptorRegistry.set(tag, registered) - } - - return registered + verify(plugin) + + const name = plugin.name + if (registry.has(name)) return registry.get(name) + + const id2deserialize = new Map() + const tag2id = new Map() + const addDescriptor = (id, tag, deserialize) => { + if (id2deserialize.has(id)) throw new DuplicateDescriptorIdError(id, plugin) + if (descriptorRegistry.has(tag) || tag2id.has(tag)) throw new DuplicateDescriptorTagError(tag, plugin) + + id2deserialize.set(id, deserialize) + tag2id.set(tag, id) + } + + const tryDescribeValue = plugin.register({ + // Concordance makes assumptions about when AMBIGUOUS occurs. Do not expose + // it to plugins. + UNEQUAL: constants.UNEQUAL, + SHALLOW_EQUAL: constants.SHALLOW_EQUAL, + DEEP_EQUAL: constants.DEEP_EQUAL, + + ObjectValue: object.ObjectValue, + DescribedMixin: object.DescribedMixin, + DeserializedMixin: object.DeserializedMixin, + + addDescriptor, + applyThemeModifiers: themeUtils.applyModifiers, + descriptorTags: publicDescriptorTags, + lineBuilder: publicLineBuilder, + mapRecursor: recursorUtils.map, + modifyTheme, + wrapFromTheme: formatUtils.wrap, + }) + + const registered = { + id2deserialize, + serializerVersion: plugin.serializerVersion, + name, + tag2id, + theme: plugin.theme || {}, + tryDescribeValue, + } + + registry.set(name, registered) + for (const tag of tag2id.keys()) { + descriptorRegistry.set(tag, registered) + } + + return registered } export function getDeserializers (plugins) { - return plugins.map(plugin => { - const registered = add(plugin) - return { - id2deserialize: registered.id2deserialize, - name: registered.name, - serializerVersion: registered.serializerVersion, - } - }) + return plugins.map(plugin => { + const registered = add(plugin) + return { + id2deserialize: registered.id2deserialize, + name: registered.name, + serializerVersion: registered.serializerVersion, + } + }) } export function getThemes (plugins) { - return plugins.map(plugin => { - const registered = add(plugin) - return { - name: registered.name, - theme: registered.theme, - } - }) + return plugins.map(plugin => { + const registered = add(plugin) + return { + name: registered.name, + theme: registered.theme, + } + }) } export function getTryDescribeValues (plugins) { - return plugins.map(plugin => add(plugin).tryDescribeValue) + return plugins.map(plugin => add(plugin).tryDescribeValue) } export function resolveDescriptorRef (tag) { - if (!descriptorRegistry.has(tag)) return null - - const registered = descriptorRegistry.get(tag) - return { - id: registered.tag2id.get(tag), - name: registered.name, - serialization: { - serializerVersion: registered.serializerVersion, - }, - } + if (!descriptorRegistry.has(tag)) return null + + const registered = descriptorRegistry.get(tag) + return { + id: registered.tag2id.get(tag), + name: registered.name, + serialization: { + serializerVersion: registered.serializerVersion, + }, + } } diff --git a/lib/primitiveValues/bigInt.js b/lib/primitiveValues/bigInt.js index 3955e74..907441e 100644 --- a/lib/primitiveValues/bigInt.js +++ b/lib/primitiveValues/bigInt.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe (value) { - return new BigIntValue(value) + return new BigIntValue(value) } export const deserialize = describe @@ -11,25 +11,25 @@ export const deserialize = describe export const tag = Symbol('BigIntValue') class BigIntValue { - constructor (value) { - this.value = value - } + constructor (value) { + this.value = value + } - compare (expected) { - return expected.tag === tag && Object.is(this.value, expected.value) - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === tag && Object.is(this.value, expected.value) + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.bigInt, `${this.value}n`)) - } + formatDeep (theme) { + return lineBuilder.single(formatUtils.wrap(theme.bigInt, `${this.value}n`)) + } - serialize () { - return this.value - } + serialize () { + return this.value + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/primitiveValues/boolean.js b/lib/primitiveValues/boolean.js index 0b191a8..98aa1f9 100644 --- a/lib/primitiveValues/boolean.js +++ b/lib/primitiveValues/boolean.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe (value) { - return new BooleanValue(value) + return new BooleanValue(value) } export const deserialize = describe @@ -11,25 +11,25 @@ export const deserialize = describe export const tag = Symbol('BooleanValue') class BooleanValue { - constructor (value) { - this.value = value - } + constructor (value) { + this.value = value + } - compare (expected) { - return this.tag === expected.tag && this.value === expected.value - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return this.tag === expected.tag && this.value === expected.value + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.boolean, this.value === true ? 'true' : 'false')) - } + formatDeep (theme) { + return lineBuilder.single(formatUtils.wrap(theme.boolean, this.value === true ? 'true' : 'false')) + } - serialize () { - return this.value - } + serialize () { + return this.value + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/primitiveValues/null.js b/lib/primitiveValues/null.js index e53cfaf..bc62235 100644 --- a/lib/primitiveValues/null.js +++ b/lib/primitiveValues/null.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe () { - return new NullValue() + return new NullValue() } export const deserialize = describe @@ -11,17 +11,17 @@ export const deserialize = describe export const tag = Symbol('NullValue') class NullValue { - compare (expected) { - return expected.tag === tag - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === tag + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.null, 'null')) - } + formatDeep (theme) { + return lineBuilder.single(formatUtils.wrap(theme.null, 'null')) + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/primitiveValues/number.js b/lib/primitiveValues/number.js index 1260af7..bcd1ff4 100644 --- a/lib/primitiveValues/number.js +++ b/lib/primitiveValues/number.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe (value) { - return new NumberValue(value) + return new NumberValue(value) } export const deserialize = describe @@ -11,26 +11,26 @@ export const deserialize = describe export const tag = Symbol('NumberValue') class NumberValue { - constructor (value) { - this.value = value - } + constructor (value) { + this.value = value + } - compare (expected) { - return expected.tag === tag && Object.is(this.value, expected.value) - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === tag && Object.is(this.value, expected.value) + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - const string = Object.is(this.value, -0) ? '-0' : String(this.value) - return lineBuilder.single(formatUtils.wrap(theme.number, string)) - } + formatDeep (theme) { + const string = Object.is(this.value, -0) ? '-0' : String(this.value) + return lineBuilder.single(formatUtils.wrap(theme.number, string)) + } - serialize () { - return this.value - } + serialize () { + return this.value + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/primitiveValues/string.js b/lib/primitiveValues/string.js index 80c27ab..66c9bdc 100644 --- a/lib/primitiveValues/string.js +++ b/lib/primitiveValues/string.js @@ -5,7 +5,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe (value) { - return new StringValue(value) + return new StringValue(value) } export const deserialize = describe @@ -16,7 +16,7 @@ export const tag = Symbol('StringValue') // ambiguous characters (other kinds of spaces, combining characters). Use // http://graphemica.com/blocks/control-pictures where applicable. function basicEscape (string) { - return string.replace(/\\/g, '\\\\') + return string.replace(/\\/g, '\\\\') } const CRLF_CONTROL_PICTURE = '\u240D\u240A' @@ -26,287 +26,287 @@ const CR_CONTROL_PICTURE = '\u240D' const MATCH_CONTROL_PICTURES = new RegExp(`${CR_CONTROL_PICTURE}|${LF_CONTROL_PICTURE}|${CR_CONTROL_PICTURE}`, 'g') function escapeLinebreak (string) { - if (string === '\r\n') return CRLF_CONTROL_PICTURE - if (string === '\n') return LF_CONTROL_PICTURE - if (string === '\r') return CR_CONTROL_PICTURE - return string + if (string === '\r\n') return CRLF_CONTROL_PICTURE + if (string === '\n') return LF_CONTROL_PICTURE + if (string === '\r') return CR_CONTROL_PICTURE + return string } function themeControlPictures (theme, resetWrap, str) { - return str.replace(MATCH_CONTROL_PICTURES, picture => { - return resetWrap.close + formatUtils.wrap(theme.string.controlPicture, picture) + resetWrap.open - }) + return str.replace(MATCH_CONTROL_PICTURES, picture => { + return resetWrap.close + formatUtils.wrap(theme.string.controlPicture, picture) + resetWrap.open + }) } const MATCH_SINGLE_QUOTE = /'/g const MATCH_DOUBLE_QUOTE = /"/g const MATCH_BACKTICKS = /`/g function escapeQuotes (line, string) { - const quote = line.escapeQuote - if (quote === '\'') return string.replace(MATCH_SINGLE_QUOTE, "\\'") - if (quote === '"') return string.replace(MATCH_DOUBLE_QUOTE, '\\"') - if (quote === '`') return string.replace(MATCH_BACKTICKS, '\\`') - return string + const quote = line.escapeQuote + if (quote === '\'') return string.replace(MATCH_SINGLE_QUOTE, "\\'") + if (quote === '"') return string.replace(MATCH_DOUBLE_QUOTE, '\\"') + if (quote === '`') return string.replace(MATCH_BACKTICKS, '\\`') + return string } function includesLinebreaks (string) { - return string.includes('\r') || string.includes('\n') + return string.includes('\r') || string.includes('\n') } function diffLine (theme, actual, expected, invert) { - const outcome = fastDiff(actual, expected) - - // TODO: Compute when line is mostly unequal (80%? 90%?) and treat it as being - // completely unequal. - const isPartiallyEqual = !( - (outcome.length === 2 && outcome[0][1] === actual && outcome[1][1] === expected) || - // Discount line ending control pictures, which will be equal even when the - // rest of the line isn't. - ( - outcome.length === 3 && - outcome[2][0] === fastDiff.EQUAL && - MATCH_CONTROL_PICTURES.test(outcome[2][1]) && - outcome[0][1] + outcome[2][1] === actual && - outcome[1][1] + outcome[2][1] === expected - ) - ) - - let stringActual = '' - let stringExpected = '' - - const noopWrap = { open: '', close: '' } - let deleteWrap = isPartiallyEqual ? theme.string.diff.delete : noopWrap - let insertWrap = isPartiallyEqual ? theme.string.diff.insert : noopWrap - const equalWrap = isPartiallyEqual ? theme.string.diff.equal : noopWrap - - if (invert) { - [deleteWrap, insertWrap] = [insertWrap, deleteWrap] - } - - for (const diff of outcome) { - if (diff[0] === fastDiff.DELETE) { - stringActual += formatUtils.wrap(deleteWrap, diff[1]) - } else if (diff[0] === fastDiff.INSERT) { - stringExpected += formatUtils.wrap(insertWrap, diff[1]) - } else { - const string = formatUtils.wrap(equalWrap, themeControlPictures(theme, equalWrap, diff[1])) - stringActual += string - stringExpected += string - } - } - - if (!isPartiallyEqual) { - const deleteLineWrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine - const insertLineWrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine - - stringActual = formatUtils.wrap(deleteLineWrap, stringActual) - stringExpected = formatUtils.wrap(insertLineWrap, stringExpected) - } - - return [stringActual, stringExpected] + const outcome = fastDiff(actual, expected) + + // TODO: Compute when line is mostly unequal (80%? 90%?) and treat it as being + // completely unequal. + const isPartiallyEqual = !( + (outcome.length === 2 && outcome[0][1] === actual && outcome[1][1] === expected) || + // Discount line ending control pictures, which will be equal even when the + // rest of the line isn't. + ( + outcome.length === 3 && + outcome[2][0] === fastDiff.EQUAL && + MATCH_CONTROL_PICTURES.test(outcome[2][1]) && + outcome[0][1] + outcome[2][1] === actual && + outcome[1][1] + outcome[2][1] === expected + ) + ) + + let stringActual = '' + let stringExpected = '' + + const noopWrap = { open: '', close: '' } + let deleteWrap = isPartiallyEqual ? theme.string.diff.delete : noopWrap + let insertWrap = isPartiallyEqual ? theme.string.diff.insert : noopWrap + const equalWrap = isPartiallyEqual ? theme.string.diff.equal : noopWrap + + if (invert) { + [deleteWrap, insertWrap] = [insertWrap, deleteWrap] + } + + for (const diff of outcome) { + if (diff[0] === fastDiff.DELETE) { + stringActual += formatUtils.wrap(deleteWrap, diff[1]) + } else if (diff[0] === fastDiff.INSERT) { + stringExpected += formatUtils.wrap(insertWrap, diff[1]) + } else { + const string = formatUtils.wrap(equalWrap, themeControlPictures(theme, equalWrap, diff[1])) + stringActual += string + stringExpected += string + } + } + + if (!isPartiallyEqual) { + const deleteLineWrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine + const insertLineWrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine + + stringActual = formatUtils.wrap(deleteLineWrap, stringActual) + stringExpected = formatUtils.wrap(insertLineWrap, stringExpected) + } + + return [stringActual, stringExpected] } const LINEBREAKS = /\r\n|\r|\n/g function gatherLines (string) { - const lines = [] - let prevIndex = 0 - for (let match; (match = LINEBREAKS.exec(string)); prevIndex = match.index + match[0].length) { - lines.push(string.slice(prevIndex, match.index) + escapeLinebreak(match[0])) - } - lines.push(string.slice(prevIndex)) - return lines + const lines = [] + let prevIndex = 0 + for (let match; (match = LINEBREAKS.exec(string)); prevIndex = match.index + match[0].length) { + lines.push(string.slice(prevIndex, match.index) + escapeLinebreak(match[0])) + } + lines.push(string.slice(prevIndex)) + return lines } class StringValue { - constructor (value) { - this.value = value - } - - compare (expected) { - return expected.tag === tag && this.value === expected.value - ? DEEP_EQUAL - : UNEQUAL - } - - get includesLinebreaks () { - return includesLinebreaks(this.value) - } - - formatDeep (theme, indent) { - // Escape backslashes - let escaped = basicEscape(this.value) - - if (!this.includesLinebreaks) { - escaped = escapeQuotes(theme.string.line, escaped) - return lineBuilder.single(formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped))) - } - - escaped = escapeQuotes(theme.string.multiline, escaped) - const lineStrings = gatherLines(escaped).map(string => { - return formatUtils.wrap(theme.string, themeControlPictures(theme, theme.string, string)) - }) - const lastIndex = lineStrings.length - 1 - const indentation = indent - return lineBuilder.buffer() - .append( - lineStrings.map((string, index) => { - if (index === 0) return lineBuilder.first(theme.string.multiline.start + string) - if (index === lastIndex) return lineBuilder.last(indentation + string + theme.string.multiline.end) - return lineBuilder.line(indentation + string) - })) - } - - formatAsKey (theme) { - const key = this.value - if (keyword.isIdentifierNameES6(key, true) || String(parseInt(key, 10)) === key) { - return key - } - - const escaped = basicEscape(key) - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/'/g, "\\'") - return formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped)) - } - - diffDeep (expected, theme, indent, invert) { - if (expected.tag !== tag) return null - - const escapedActual = basicEscape(this.value) - const escapedExpected = basicEscape(expected.value) - - if (!includesLinebreaks(escapedActual) && !includesLinebreaks(escapedExpected)) { - const result = diffLine(theme, - escapeQuotes(theme.string.line, escapedActual), - escapeQuotes(theme.string.line, escapedExpected), - invert, - ) - - return lineBuilder.actual.single(formatUtils.wrap(theme.string.line, result[0])) - .concat(lineBuilder.expected.single(formatUtils.wrap(theme.string.line, result[1]))) - } - - const actualLines = gatherLines(escapeQuotes(theme.string.multiline, escapedActual)) - const expectedLines = gatherLines(escapeQuotes(theme.string.multiline, escapedExpected)) - - const indentation = indent - const lines = lineBuilder.buffer() - const lastActualIndex = actualLines.length - 1 - const lastExpectedIndex = expectedLines.length - 1 - - let actualBuffer = [] - let expectedBuffer = [] - let mustOpenNextExpected = false - for (let actualIndex = 0, expectedIndex = 0, extraneousOffset = 0; actualIndex < actualLines.length;) { - if (actualLines[actualIndex] === expectedLines[expectedIndex]) { - lines.append(actualBuffer) - lines.append(expectedBuffer) - actualBuffer = [] - expectedBuffer = [] - - let string = actualLines[actualIndex] - string = themeControlPictures(theme, theme.string.diff.equal, string) - string = formatUtils.wrap(theme.string.diff.equal, string) - - if (actualIndex === 0) { - lines.append(lineBuilder.first(theme.string.multiline.start + string)) - } else if (actualIndex === lastActualIndex && expectedIndex === lastExpectedIndex) { - lines.append(lineBuilder.last(indentation + string + theme.string.multiline.end)) - } else { - lines.append(lineBuilder.line(indentation + string)) - } - - actualIndex++ - expectedIndex++ - continue - } - - let expectedIsMissing = false - { - const compare = actualLines[actualIndex] - for (let index = expectedIndex; !expectedIsMissing && index < expectedLines.length; index++) { - expectedIsMissing = compare === expectedLines[index] - } - } - - let actualIsExtraneous = (actualIndex - extraneousOffset) > lastExpectedIndex || expectedIndex > lastExpectedIndex - if (!actualIsExtraneous) { - const compare = expectedLines[expectedIndex] - for (let index = actualIndex; !actualIsExtraneous && index < actualLines.length; index++) { - actualIsExtraneous = compare === actualLines[index] - } - - if (!actualIsExtraneous && (actualIndex - extraneousOffset) === lastExpectedIndex && actualIndex < lastActualIndex) { - actualIsExtraneous = true - } - } - - if (actualIsExtraneous && !expectedIsMissing) { - const wrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine - const string = formatUtils.wrap(wrap, actualLines[actualIndex]) - - if (actualIndex === 0) { - actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + string)) - mustOpenNextExpected = true - } else if (actualIndex === lastActualIndex) { - actualBuffer.push(lineBuilder.actual.last(indentation + string + theme.string.multiline.end)) - } else { - actualBuffer.push(lineBuilder.actual.line(indentation + string)) - } - - actualIndex++ - extraneousOffset++ - } else if (expectedIsMissing && !actualIsExtraneous) { - const wrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine - const string = formatUtils.wrap(wrap, expectedLines[expectedIndex]) - - if (mustOpenNextExpected) { - expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + string)) - mustOpenNextExpected = false - } else if (expectedIndex === lastExpectedIndex) { - expectedBuffer.push(lineBuilder.expected.last(indentation + string + theme.string.multiline.end)) - } else { - expectedBuffer.push(lineBuilder.expected.line(indentation + string)) - } - - expectedIndex++ - } else { - const result = diffLine(theme, actualLines[actualIndex], expectedLines[expectedIndex], invert) - - if (actualIndex === 0) { - actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + result[0])) - mustOpenNextExpected = true - } else if (actualIndex === lastActualIndex) { - actualBuffer.push(lineBuilder.actual.last(indentation + result[0] + theme.string.multiline.end)) - } else { - actualBuffer.push(lineBuilder.actual.line(indentation + result[0])) - } - - if (mustOpenNextExpected) { - expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + result[1])) - mustOpenNextExpected = false - } else if (expectedIndex === lastExpectedIndex) { - expectedBuffer.push(lineBuilder.expected.last(indentation + result[1] + theme.string.multiline.end)) - } else { - expectedBuffer.push(lineBuilder.expected.line(indentation + result[1])) - } - - actualIndex++ - expectedIndex++ - } - } - - lines.append(actualBuffer) - lines.append(expectedBuffer) - return lines - } - - serialize () { - return this.value - } - - isPrimitive = true - - tag = tag + constructor (value) { + this.value = value + } + + compare (expected) { + return expected.tag === tag && this.value === expected.value + ? DEEP_EQUAL + : UNEQUAL + } + + get includesLinebreaks () { + return includesLinebreaks(this.value) + } + + formatDeep (theme, indent) { + // Escape backslashes + let escaped = basicEscape(this.value) + + if (!this.includesLinebreaks) { + escaped = escapeQuotes(theme.string.line, escaped) + return lineBuilder.single(formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped))) + } + + escaped = escapeQuotes(theme.string.multiline, escaped) + const lineStrings = gatherLines(escaped).map(string => { + return formatUtils.wrap(theme.string, themeControlPictures(theme, theme.string, string)) + }) + const lastIndex = lineStrings.length - 1 + const indentation = indent + return lineBuilder.buffer() + .append( + lineStrings.map((string, index) => { + if (index === 0) return lineBuilder.first(theme.string.multiline.start + string) + if (index === lastIndex) return lineBuilder.last(indentation + string + theme.string.multiline.end) + return lineBuilder.line(indentation + string) + })) + } + + formatAsKey (theme) { + const key = this.value + if (keyword.isIdentifierNameES6(key, true) || String(parseInt(key, 10)) === key) { + return key + } + + const escaped = basicEscape(key) + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/'/g, "\\'") + return formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped)) + } + + diffDeep (expected, theme, indent, invert) { + if (expected.tag !== tag) return null + + const escapedActual = basicEscape(this.value) + const escapedExpected = basicEscape(expected.value) + + if (!includesLinebreaks(escapedActual) && !includesLinebreaks(escapedExpected)) { + const result = diffLine(theme, + escapeQuotes(theme.string.line, escapedActual), + escapeQuotes(theme.string.line, escapedExpected), + invert, + ) + + return lineBuilder.actual.single(formatUtils.wrap(theme.string.line, result[0])) + .concat(lineBuilder.expected.single(formatUtils.wrap(theme.string.line, result[1]))) + } + + const actualLines = gatherLines(escapeQuotes(theme.string.multiline, escapedActual)) + const expectedLines = gatherLines(escapeQuotes(theme.string.multiline, escapedExpected)) + + const indentation = indent + const lines = lineBuilder.buffer() + const lastActualIndex = actualLines.length - 1 + const lastExpectedIndex = expectedLines.length - 1 + + let actualBuffer = [] + let expectedBuffer = [] + let mustOpenNextExpected = false + for (let actualIndex = 0, expectedIndex = 0, extraneousOffset = 0; actualIndex < actualLines.length;) { + if (actualLines[actualIndex] === expectedLines[expectedIndex]) { + lines.append(actualBuffer) + lines.append(expectedBuffer) + actualBuffer = [] + expectedBuffer = [] + + let string = actualLines[actualIndex] + string = themeControlPictures(theme, theme.string.diff.equal, string) + string = formatUtils.wrap(theme.string.diff.equal, string) + + if (actualIndex === 0) { + lines.append(lineBuilder.first(theme.string.multiline.start + string)) + } else if (actualIndex === lastActualIndex && expectedIndex === lastExpectedIndex) { + lines.append(lineBuilder.last(indentation + string + theme.string.multiline.end)) + } else { + lines.append(lineBuilder.line(indentation + string)) + } + + actualIndex++ + expectedIndex++ + continue + } + + let expectedIsMissing = false + { + const compare = actualLines[actualIndex] + for (let index = expectedIndex; !expectedIsMissing && index < expectedLines.length; index++) { + expectedIsMissing = compare === expectedLines[index] + } + } + + let actualIsExtraneous = (actualIndex - extraneousOffset) > lastExpectedIndex || expectedIndex > lastExpectedIndex + if (!actualIsExtraneous) { + const compare = expectedLines[expectedIndex] + for (let index = actualIndex; !actualIsExtraneous && index < actualLines.length; index++) { + actualIsExtraneous = compare === actualLines[index] + } + + if (!actualIsExtraneous && (actualIndex - extraneousOffset) === lastExpectedIndex && actualIndex < lastActualIndex) { + actualIsExtraneous = true + } + } + + if (actualIsExtraneous && !expectedIsMissing) { + const wrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine + const string = formatUtils.wrap(wrap, actualLines[actualIndex]) + + if (actualIndex === 0) { + actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + string)) + mustOpenNextExpected = true + } else if (actualIndex === lastActualIndex) { + actualBuffer.push(lineBuilder.actual.last(indentation + string + theme.string.multiline.end)) + } else { + actualBuffer.push(lineBuilder.actual.line(indentation + string)) + } + + actualIndex++ + extraneousOffset++ + } else if (expectedIsMissing && !actualIsExtraneous) { + const wrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine + const string = formatUtils.wrap(wrap, expectedLines[expectedIndex]) + + if (mustOpenNextExpected) { + expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + string)) + mustOpenNextExpected = false + } else if (expectedIndex === lastExpectedIndex) { + expectedBuffer.push(lineBuilder.expected.last(indentation + string + theme.string.multiline.end)) + } else { + expectedBuffer.push(lineBuilder.expected.line(indentation + string)) + } + + expectedIndex++ + } else { + const result = diffLine(theme, actualLines[actualIndex], expectedLines[expectedIndex], invert) + + if (actualIndex === 0) { + actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + result[0])) + mustOpenNextExpected = true + } else if (actualIndex === lastActualIndex) { + actualBuffer.push(lineBuilder.actual.last(indentation + result[0] + theme.string.multiline.end)) + } else { + actualBuffer.push(lineBuilder.actual.line(indentation + result[0])) + } + + if (mustOpenNextExpected) { + expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + result[1])) + mustOpenNextExpected = false + } else if (expectedIndex === lastExpectedIndex) { + expectedBuffer.push(lineBuilder.expected.last(indentation + result[1] + theme.string.multiline.end)) + } else { + expectedBuffer.push(lineBuilder.expected.line(indentation + result[1])) + } + + actualIndex++ + expectedIndex++ + } + } + + lines.append(actualBuffer) + lines.append(expectedBuffer) + return lines + } + + serialize () { + return this.value + } + + isPrimitive = true + + tag = tag } diff --git a/lib/primitiveValues/symbol.js b/lib/primitiveValues/symbol.js index a9fe295..6e5f104 100644 --- a/lib/primitiveValues/symbol.js +++ b/lib/primitiveValues/symbol.js @@ -6,103 +6,103 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe (value) { - let stringCompare = null - - const key = Symbol.keyFor(value) - if (key !== undefined) { - stringCompare = `Symbol.for(${stringEscape(key)})` - } else if (wellKnownSymbols.isWellKnown(value)) { - stringCompare = wellKnownSymbols.getLabel(value) - } - - return new SymbolValue({ - stringCompare, - value, - }) + let stringCompare = null + + const key = Symbol.keyFor(value) + if (key !== undefined) { + stringCompare = `Symbol.for(${stringEscape(key)})` + } else if (wellKnownSymbols.isWellKnown(value)) { + stringCompare = wellKnownSymbols.getLabel(value) + } + + return new SymbolValue({ + stringCompare, + value, + }) } export function deserialize (state) { - const stringCompare = state[0] - const string = state[1] || state[0] - - return new DeserializedSymbolValue({ - string, - stringCompare, - value: null, - }) + const stringCompare = state[0] + const string = state[1] || state[0] + + return new DeserializedSymbolValue({ + string, + stringCompare, + value: null, + }) } export const tag = Symbol('SymbolValue') class SymbolValue { - constructor (props) { - this.stringCompare = props.stringCompare - this.value = props.value - } - - compare (expected) { - if (expected.tag !== tag) return UNEQUAL - - if (this.stringCompare !== null) { - return this.stringCompare === expected.stringCompare - ? DEEP_EQUAL - : UNEQUAL - } - - return this.value === expected.value - ? DEEP_EQUAL - : UNEQUAL - } - - formatString () { - if (this.stringCompare !== null) return this.stringCompare - return stringEscape(this.value.toString()) - } - - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.symbol, this.formatString())) - } - - formatAsKey (theme) { - return formatUtils.wrap(theme.property.keyBracket, formatUtils.wrap(theme.symbol, this.formatString())) - } - - serialize () { - const string = this.formatString() - return this.stringCompare === string - ? [this.stringCompare] - : [this.stringCompare, string] - } - - isPrimitive = true - - tag = tag + constructor (props) { + this.stringCompare = props.stringCompare + this.value = props.value + } + + compare (expected) { + if (expected.tag !== tag) return UNEQUAL + + if (this.stringCompare !== null) { + return this.stringCompare === expected.stringCompare + ? DEEP_EQUAL + : UNEQUAL + } + + return this.value === expected.value + ? DEEP_EQUAL + : UNEQUAL + } + + formatString () { + if (this.stringCompare !== null) return this.stringCompare + return stringEscape(this.value.toString()) + } + + formatDeep (theme) { + return lineBuilder.single(formatUtils.wrap(theme.symbol, this.formatString())) + } + + formatAsKey (theme) { + return formatUtils.wrap(theme.property.keyBracket, formatUtils.wrap(theme.symbol, this.formatString())) + } + + serialize () { + const string = this.formatString() + return this.stringCompare === string + ? [this.stringCompare] + : [this.stringCompare, string] + } + + isPrimitive = true + + tag = tag } class DeserializedSymbolValue extends SymbolValue { - constructor (props) { - super(props) - this.string = props.string - } - - compare (expected) { - if (expected.tag !== tag) return UNEQUAL - - if (this.stringCompare !== null) { - return this.stringCompare === expected.stringCompare - ? DEEP_EQUAL - : UNEQUAL - } - - // Symbols that are not in the global symbol registry, and are not - // well-known, cannot be compared when deserialized. Treat symbols - // as equal if they are formatted the same. - return this.string === expected.formatString() - ? DEEP_EQUAL - : UNEQUAL - } - - formatString () { - return this.string - } + constructor (props) { + super(props) + this.string = props.string + } + + compare (expected) { + if (expected.tag !== tag) return UNEQUAL + + if (this.stringCompare !== null) { + return this.stringCompare === expected.stringCompare + ? DEEP_EQUAL + : UNEQUAL + } + + // Symbols that are not in the global symbol registry, and are not + // well-known, cannot be compared when deserialized. Treat symbols + // as equal if they are formatted the same. + return this.string === expected.formatString() + ? DEEP_EQUAL + : UNEQUAL + } + + formatString () { + return this.string + } } diff --git a/lib/primitiveValues/undefined.js b/lib/primitiveValues/undefined.js index ee87162..2c1acf8 100644 --- a/lib/primitiveValues/undefined.js +++ b/lib/primitiveValues/undefined.js @@ -3,7 +3,7 @@ import * as formatUtils from '../formatUtils.js' import lineBuilder from '../lineBuilder.js' export function describe () { - return new UndefinedValue() + return new UndefinedValue() } export const deserialize = describe @@ -11,17 +11,17 @@ export const deserialize = describe export const tag = Symbol('UndefinedValue') class UndefinedValue { - compare (expected) { - return expected.tag === tag - ? DEEP_EQUAL - : UNEQUAL - } + compare (expected) { + return expected.tag === tag + ? DEEP_EQUAL + : UNEQUAL + } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.undefined, 'undefined')) - } + formatDeep (theme) { + return lineBuilder.single(formatUtils.wrap(theme.undefined, 'undefined')) + } - isPrimitive = true + isPrimitive = true - tag = tag + tag = tag } diff --git a/lib/recursorUtils.js b/lib/recursorUtils.js index 001dbbf..135a586 100644 --- a/lib/recursorUtils.js +++ b/lib/recursorUtils.js @@ -1,116 +1,116 @@ export const NOOP_RECURSOR = { - size: 0, - next () { return null }, + size: 0, + next () { return null }, } export function fork (recursor) { - const buffer = [] - - return { - shared () { - const next = recursor() - if (next !== null) buffer.push(next) - return next - }, - - recursor () { - if (buffer.length > 0) return buffer.shift() - return recursor() - }, - } + const buffer = [] + + return { + shared () { + const next = recursor() + if (next !== null) buffer.push(next) + return next + }, + + recursor () { + if (buffer.length > 0) return buffer.shift() + return recursor() + }, + } } export function consumeDeep (recursor) { - const stack = [recursor] - while (stack.length > 0) { - const subject = stack[stack.length - 1]() - if (subject === null) { - stack.pop() - continue - } - - if (typeof subject.createRecursor === 'function') { - stack.push(subject.createRecursor()) - } - } + const stack = [recursor] + while (stack.length > 0) { + const subject = stack[stack.length - 1]() + if (subject === null) { + stack.pop() + continue + } + + if (typeof subject.createRecursor === 'function') { + stack.push(subject.createRecursor()) + } + } } export function map (recursor, mapFn) { - return () => { - const next = recursor() - if (next === null) return null + return () => { + const next = recursor() + if (next === null) return null - return mapFn(next) - } + return mapFn(next) + } } export function replay (state, create) { - if (!state) { - const recursor = create() - if (recursor === NOOP_RECURSOR) { - state = recursor - } else { - state = Object.assign({ - buffer: [], - done: false, - }, recursor) - } - } - - if (state === NOOP_RECURSOR) return { state, recursor: state } - - let done = false - let index = 0 - const next = () => { - if (done) return null - - let retval = state.buffer[index] - if (retval === undefined) { - retval = state.buffer[index] = state.next() - } - - index++ - if (retval === null) { - done = true - } - return retval - } - - return { state, recursor: { next, size: state.size } } + if (!state) { + const recursor = create() + if (recursor === NOOP_RECURSOR) { + state = recursor + } else { + state = Object.assign({ + buffer: [], + done: false, + }, recursor) + } + } + + if (state === NOOP_RECURSOR) return { state, recursor: state } + + let done = false + let index = 0 + const next = () => { + if (done) return null + + let retval = state.buffer[index] + if (retval === undefined) { + retval = state.buffer[index] = state.next() + } + + index++ + if (retval === null) { + done = true + } + return retval + } + + return { state, recursor: { next, size: state.size } } } export function sequence (first, second) { - let fromFirst = true - return () => { - if (fromFirst) { - const next = first() - if (next !== null) return next + let fromFirst = true + return () => { + if (fromFirst) { + const next = first() + if (next !== null) return next - fromFirst = false - } + fromFirst = false + } - return second() - } + return second() + } } export function singleValue (value) { - let done = false - return () => { - if (done) return null + let done = false + return () => { + if (done) return null - done = true - return value - } + done = true + return value + } } export function unshift (recursor, value) { - return () => { - if (value !== null) { - const next = value - value = null - return next - } - - return recursor() - } + return () => { + if (value !== null) { + const next = value + value = null + return next + } + + return recursor() + } } diff --git a/lib/serialize.js b/lib/serialize.js index b774b55..10363af 100644 --- a/lib/serialize.js +++ b/lib/serialize.js @@ -46,312 +46,312 @@ const VERSION = 3 // Concordance itself. Indexes are hexadecimal to make reading the binary // output easier. const mappings = [ - [0x01, bigIntValue.tag, bigIntValue.deserialize], - [0x02, booleanValue.tag, booleanValue.deserialize], - [0x03, nullValue.tag, nullValue.deserialize], - [0x04, numberValue.tag, numberValue.deserialize], - [0x05, stringValue.tag, stringValue.deserialize], - [0x06, symbolValue.tag, symbolValue.deserialize], - [0x07, undefinedValue.tag, undefinedValue.deserialize], - - [0x08, objectValue.tag, objectValue.deserialize], - [0x09, statsDescriptors.iterableTag, statsDescriptors.deserializeIterableStats], - [0x0A, statsDescriptors.listTag, statsDescriptors.deserializeListStats], - [0x0B, itemDescriptor.complexTag, itemDescriptor.deserializeComplex], - [0x0C, itemDescriptor.primitiveTag, itemDescriptor.deserializePrimitive], - [0x0D, statsDescriptors.propertyTag, statsDescriptors.deserializePropertyStats], - [0x0E, propertyDescriptor.complexTag, propertyDescriptor.deserializeComplex], - [0x0F, propertyDescriptor.primitiveTag, propertyDescriptor.deserializePrimitive], - [0x10, pointerDescriptor.tag, pointerDescriptor.deserialize], - - [0x11, mapValue.tag, mapValue.deserialize], - [0x12, mapEntryDescriptor.tag, mapEntryDescriptor.deserialize], - - [0x13, argumentsValue.tag, argumentsValue.deserialize], - [0x14, arrayBufferValue.tag, arrayBufferValue.deserialize], - [0x15, boxedValue.tag, boxedValue.deserialize], - [0x16, dataViewValue.tag, dataViewValue.deserialize], - [0x17, dateValue.tag, dateValue.deserialize], - [0x18, errorValue.tag, errorValue.deserialize], - [0x19, functionValue.tag, functionValue.deserialize], - [0x1A, globalValue.tag, globalValue.deserialize], - [0x1B, promiseValue.tag, promiseValue.deserialize], - [0x1C, regexpValue.tag, regexpValue.deserialize], - [0x1D, setValue.tag, setValue.deserialize], - [0x1E, typedArrayValue.tag, typedArrayValue.deserialize], - [0x1F, typedArrayValue.bytesTag, typedArrayValue.deserializeBytes], + [0x01, bigIntValue.tag, bigIntValue.deserialize], + [0x02, booleanValue.tag, booleanValue.deserialize], + [0x03, nullValue.tag, nullValue.deserialize], + [0x04, numberValue.tag, numberValue.deserialize], + [0x05, stringValue.tag, stringValue.deserialize], + [0x06, symbolValue.tag, symbolValue.deserialize], + [0x07, undefinedValue.tag, undefinedValue.deserialize], + + [0x08, objectValue.tag, objectValue.deserialize], + [0x09, statsDescriptors.iterableTag, statsDescriptors.deserializeIterableStats], + [0x0A, statsDescriptors.listTag, statsDescriptors.deserializeListStats], + [0x0B, itemDescriptor.complexTag, itemDescriptor.deserializeComplex], + [0x0C, itemDescriptor.primitiveTag, itemDescriptor.deserializePrimitive], + [0x0D, statsDescriptors.propertyTag, statsDescriptors.deserializePropertyStats], + [0x0E, propertyDescriptor.complexTag, propertyDescriptor.deserializeComplex], + [0x0F, propertyDescriptor.primitiveTag, propertyDescriptor.deserializePrimitive], + [0x10, pointerDescriptor.tag, pointerDescriptor.deserialize], + + [0x11, mapValue.tag, mapValue.deserialize], + [0x12, mapEntryDescriptor.tag, mapEntryDescriptor.deserialize], + + [0x13, argumentsValue.tag, argumentsValue.deserialize], + [0x14, arrayBufferValue.tag, arrayBufferValue.deserialize], + [0x15, boxedValue.tag, boxedValue.deserialize], + [0x16, dataViewValue.tag, dataViewValue.deserialize], + [0x17, dateValue.tag, dateValue.deserialize], + [0x18, errorValue.tag, errorValue.deserialize], + [0x19, functionValue.tag, functionValue.deserialize], + [0x1A, globalValue.tag, globalValue.deserialize], + [0x1B, promiseValue.tag, promiseValue.deserialize], + [0x1C, regexpValue.tag, regexpValue.deserialize], + [0x1D, setValue.tag, setValue.deserialize], + [0x1E, typedArrayValue.tag, typedArrayValue.deserialize], + [0x1F, typedArrayValue.bytesTag, typedArrayValue.deserializeBytes], ] const tag2id = new Map(mappings.map(mapping => [mapping[1], mapping[0]])) const id2deserialize = new Map(mappings.map(mapping => [mapping[0], mapping[2]])) class DescriptorSerializationError extends Error { - constructor (descriptor) { - super('Could not serialize descriptor') - this.name = 'DescriptorSerializationError' - this.descriptor = descriptor - } + constructor (descriptor) { + super('Could not serialize descriptor') + this.name = 'DescriptorSerializationError' + this.descriptor = descriptor + } } class MissingPluginError extends Error { - constructor (pluginName) { - super(`Could not deserialize buffer: missing plugin ${JSON.stringify(pluginName)}`) - this.name = 'MissingPluginError' - this.pluginName = pluginName - } + constructor (pluginName) { + super(`Could not deserialize buffer: missing plugin ${JSON.stringify(pluginName)}`) + this.name = 'MissingPluginError' + this.pluginName = pluginName + } } class PointerLookupError extends Error { - constructor (index) { - super(`Could not deserialize buffer: pointer ${index} could not be resolved`) - this.name = 'PointerLookupError' - this.index = index - } + constructor (index) { + super(`Could not deserialize buffer: pointer ${index} could not be resolved`) + this.name = 'PointerLookupError' + this.index = index + } } class UnsupportedPluginError extends Error { - constructor (pluginName, serializerVersion) { - super(`Could not deserialize buffer: plugin ${JSON.stringify(pluginName)} expects a different serialization`) - this.name = 'UnsupportedPluginError' - this.pluginName = pluginName - this.serializerVersion = serializerVersion - } + constructor (pluginName, serializerVersion) { + super(`Could not deserialize buffer: plugin ${JSON.stringify(pluginName)} expects a different serialization`) + this.name = 'UnsupportedPluginError' + this.pluginName = pluginName + this.serializerVersion = serializerVersion + } } class UnsupportedVersion extends Error { // eslint-disable-line unicorn/custom-error-definition - constructor (serializerVersion) { - super('Could not deserialize buffer: a different serialization was expected') - this.name = 'UnsupportedVersion' - this.serializerVersion = serializerVersion - } + constructor (serializerVersion) { + super('Could not deserialize buffer: a different serialization was expected') + this.name = 'UnsupportedVersion' + this.serializerVersion = serializerVersion + } } function shallowSerializeDescriptor (descriptor, resolvePluginRef) { - if (!descriptor.serialize) return undefined + if (!descriptor.serialize) return undefined - return serializeState(descriptor.serialize(), resolvePluginRef) + return serializeState(descriptor.serialize(), resolvePluginRef) } function serializeState (state, resolvePluginRef) { - if (Array.isArray(state)) return state.map(x => serializeState(x)) - - if (state && state.tag) { - let id, pluginIndex - if (tag2id.has(state.tag)) { - id = tag2id.get(state.tag) - pluginIndex = 0 - } else { - const ref = resolvePluginRef(state.tag) - if (ref) { - id = ref.id - pluginIndex = ref.pluginIndex - } - } - - if (id !== undefined) { - const serialized = [pluginIndex, id, shallowSerializeDescriptor(state, resolvePluginRef)] - serialized[encoder.descriptorSymbol] = true - return serialized - } - } - - return state + if (Array.isArray(state)) return state.map(x => serializeState(x)) + + if (state && state.tag) { + let id, pluginIndex + if (tag2id.has(state.tag)) { + id = tag2id.get(state.tag) + pluginIndex = 0 + } else { + const ref = resolvePluginRef(state.tag) + if (ref) { + id = ref.id + pluginIndex = ref.pluginIndex + } + } + + if (id !== undefined) { + const serialized = [pluginIndex, id, shallowSerializeDescriptor(state, resolvePluginRef)] + serialized[encoder.descriptorSymbol] = true + return serialized + } + } + + return state } export function serialize (descriptor) { - const usedPlugins = new Map() - const resolvePluginRef = tag => { - const ref = pluginRegistry.resolveDescriptorRef(tag) - if (!ref) return null - - if (!usedPlugins.has(ref.name)) { - // Start at 1, since 0 is reserved for Concordance's descriptors. - const index = usedPlugins.size + 1 - usedPlugins.set(ref.name, Object.assign({ index }, ref.serialization)) - } - - return { - id: ref.id, - pluginIndex: usedPlugins.get(ref.name).index, - } - } - - const seen = new Set() - - const stack = [] - let topIndex = -1 - - let rootRecord - do { - if (descriptor.isComplex === true) { - if (seen.has(descriptor.pointer)) { - descriptor = pointerDescriptor.describe(descriptor.pointer) - } else { - seen.add(descriptor.pointer) - } - } - - let id - let pluginIndex = 0 - if (tag2id.has(descriptor.tag)) { - id = tag2id.get(descriptor.tag) - } else { - const ref = resolvePluginRef(descriptor.tag) - if (!ref) throw new DescriptorSerializationError(descriptor) - - id = ref.id - pluginIndex = ref.pluginIndex - } - - const record = { - id, - pluginIndex, - children: [], - state: shallowSerializeDescriptor(descriptor, resolvePluginRef), - } - if (!rootRecord) { - rootRecord = record - } else { - stack[topIndex].children.push(record) - } - - if (descriptor.createRecursor) { - stack.push({ recursor: descriptor.createRecursor(), children: record.children }) - topIndex++ - } - - while (topIndex >= 0) { - descriptor = stack[topIndex].recursor() - if (descriptor === null) { - stack.pop() - topIndex-- - } else { - break - } - } - } while (topIndex >= 0) - - return encoder.encode(VERSION, rootRecord, usedPlugins) + const usedPlugins = new Map() + const resolvePluginRef = tag => { + const ref = pluginRegistry.resolveDescriptorRef(tag) + if (!ref) return null + + if (!usedPlugins.has(ref.name)) { + // Start at 1, since 0 is reserved for Concordance's descriptors. + const index = usedPlugins.size + 1 + usedPlugins.set(ref.name, Object.assign({ index }, ref.serialization)) + } + + return { + id: ref.id, + pluginIndex: usedPlugins.get(ref.name).index, + } + } + + const seen = new Set() + + const stack = [] + let topIndex = -1 + + let rootRecord + do { + if (descriptor.isComplex === true) { + if (seen.has(descriptor.pointer)) { + descriptor = pointerDescriptor.describe(descriptor.pointer) + } else { + seen.add(descriptor.pointer) + } + } + + let id + let pluginIndex = 0 + if (tag2id.has(descriptor.tag)) { + id = tag2id.get(descriptor.tag) + } else { + const ref = resolvePluginRef(descriptor.tag) + if (!ref) throw new DescriptorSerializationError(descriptor) + + id = ref.id + pluginIndex = ref.pluginIndex + } + + const record = { + id, + pluginIndex, + children: [], + state: shallowSerializeDescriptor(descriptor, resolvePluginRef), + } + if (!rootRecord) { + rootRecord = record + } else { + stack[topIndex].children.push(record) + } + + if (descriptor.createRecursor) { + stack.push({ recursor: descriptor.createRecursor(), children: record.children }) + topIndex++ + } + + while (topIndex >= 0) { + descriptor = stack[topIndex].recursor() + if (descriptor === null) { + stack.pop() + topIndex-- + } else { + break + } + } + } while (topIndex >= 0) + + return encoder.encode(VERSION, rootRecord, usedPlugins) } function deserializeState (state, getDescriptorDeserializer) { - if (state && state[encoder.descriptorSymbol] === true) { - return shallowDeserializeDescriptor(state, getDescriptorDeserializer) - } + if (state && state[encoder.descriptorSymbol] === true) { + return shallowDeserializeDescriptor(state, getDescriptorDeserializer) + } - return Array.isArray(state) - ? state.map(item => deserializeState(item, getDescriptorDeserializer)) - : state + return Array.isArray(state) + ? state.map(item => deserializeState(item, getDescriptorDeserializer)) + : state } function shallowDeserializeDescriptor (entry, getDescriptorDeserializer) { - const deserializeDescriptor = getDescriptorDeserializer(entry[0], entry[1]) - return deserializeDescriptor(entry[2]) + const deserializeDescriptor = getDescriptorDeserializer(entry[0], entry[1]) + return deserializeDescriptor(entry[2]) } function deserializeRecord (record, getDescriptorDeserializer, buffer) { - const deserializeDescriptor = getDescriptorDeserializer(record.pluginIndex, record.id) - const state = deserializeState(record.state, getDescriptorDeserializer) + const deserializeDescriptor = getDescriptorDeserializer(record.pluginIndex, record.id) + const state = deserializeState(record.state, getDescriptorDeserializer) - if (record.pointerAddresses.length === 0) { - return deserializeDescriptor(state) - } + if (record.pointerAddresses.length === 0) { + return deserializeDescriptor(state) + } - const endIndex = record.pointerAddresses.length - let index = 0 - const recursor = () => { - if (index === endIndex) return null + const endIndex = record.pointerAddresses.length + let index = 0 + const recursor = () => { + if (index === endIndex) return null - const recursorRecord = encoder.decodeRecord(buffer, record.pointerAddresses[index++]) - return deserializeRecord(recursorRecord, getDescriptorDeserializer, buffer) - } + const recursorRecord = encoder.decodeRecord(buffer, record.pointerAddresses[index++]) + return deserializeRecord(recursorRecord, getDescriptorDeserializer, buffer) + } - return deserializeDescriptor(state, recursor) + return deserializeDescriptor(state, recursor) } function buildPluginMap (buffer, options) { - const cache = options && options.deserializedPluginsCache - const cacheKey = md5hex(buffer) - if (cache && cache.has(cacheKey)) return cache.get(cacheKey) - - const decodedPlugins = encoder.decodePlugins(buffer) - if (decodedPlugins.size === 0) { - const pluginMap = new Map() - if (cache) cache.set(cacheKey, pluginMap) - return pluginMap - } - - const deserializerLookup = new Map() - if (Array.isArray(options && options.plugins)) { - for (const deserializer of pluginRegistry.getDeserializers(options.plugins)) { - deserializerLookup.set(deserializer.name, deserializer) - } - } - - const pluginMap = new Map() - for (const index of decodedPlugins.keys()) { - const used = decodedPlugins.get(index) - const pluginName = used.name - const serializerVersion = used.serializerVersion - - // TODO: Allow plugin author to encode a helpful message in its serialization - if (!deserializerLookup.has(pluginName)) { - throw new MissingPluginError(pluginName) - } - if (serializerVersion !== deserializerLookup.get(pluginName).serializerVersion) { - throw new UnsupportedPluginError(pluginName, serializerVersion) - } - - pluginMap.set(index, deserializerLookup.get(pluginName).id2deserialize) - } - - if (cache) cache.set(cacheKey, pluginMap) - return pluginMap + const cache = options && options.deserializedPluginsCache + const cacheKey = md5hex(buffer) + if (cache && cache.has(cacheKey)) return cache.get(cacheKey) + + const decodedPlugins = encoder.decodePlugins(buffer) + if (decodedPlugins.size === 0) { + const pluginMap = new Map() + if (cache) cache.set(cacheKey, pluginMap) + return pluginMap + } + + const deserializerLookup = new Map() + if (Array.isArray(options && options.plugins)) { + for (const deserializer of pluginRegistry.getDeserializers(options.plugins)) { + deserializerLookup.set(deserializer.name, deserializer) + } + } + + const pluginMap = new Map() + for (const index of decodedPlugins.keys()) { + const used = decodedPlugins.get(index) + const pluginName = used.name + const serializerVersion = used.serializerVersion + + // TODO: Allow plugin author to encode a helpful message in its serialization + if (!deserializerLookup.has(pluginName)) { + throw new MissingPluginError(pluginName) + } + if (serializerVersion !== deserializerLookup.get(pluginName).serializerVersion) { + throw new UnsupportedPluginError(pluginName, serializerVersion) + } + + pluginMap.set(index, deserializerLookup.get(pluginName).id2deserialize) + } + + if (cache) cache.set(cacheKey, pluginMap) + return pluginMap } export function deserialize (buffer, options) { - const version = encoder.extractVersion(buffer) - if (version !== VERSION) throw new UnsupportedVersion(version) - - const decoded = encoder.decode(buffer) - const pluginMap = buildPluginMap(decoded.pluginBuffer, options) - - const descriptorsByPointerIndex = new Map() - const mapPointerDescriptor = descriptor => { - if (descriptor.isPointer === true) { - if (descriptorsByPointerIndex.has(descriptor.index)) { - return descriptorsByPointerIndex.get(descriptor.index) - } - - if (typeof rootDescriptor.createRecursor === 'function') { - // The descriptor we're pointing to may be elsewhere in the serialized - // structure. Consume the entire structure and check again. - recursorUtils.consumeDeep(rootDescriptor.createRecursor()) - - if (descriptorsByPointerIndex.has(descriptor.index)) { - return descriptorsByPointerIndex.get(descriptor.index) - } - } - - throw new PointerLookupError(descriptor.index) - } - - if (descriptor.isComplex === true) { - descriptorsByPointerIndex.set(descriptor.pointer, descriptor) - } - - return descriptor - } - - const getDescriptorDeserializer = (pluginIndex, id) => { - return (state, recursor) => { - const deserializeDescriptor = pluginIndex === 0 - ? id2deserialize.get(id) - : pluginMap.get(pluginIndex).get(id) - - return mapPointerDescriptor(deserializeDescriptor(state, recursor)) - } - } - - const rootDescriptor = deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer) - return rootDescriptor + const version = encoder.extractVersion(buffer) + if (version !== VERSION) throw new UnsupportedVersion(version) + + const decoded = encoder.decode(buffer) + const pluginMap = buildPluginMap(decoded.pluginBuffer, options) + + const descriptorsByPointerIndex = new Map() + const mapPointerDescriptor = descriptor => { + if (descriptor.isPointer === true) { + if (descriptorsByPointerIndex.has(descriptor.index)) { + return descriptorsByPointerIndex.get(descriptor.index) + } + + if (typeof rootDescriptor.createRecursor === 'function') { + // The descriptor we're pointing to may be elsewhere in the serialized + // structure. Consume the entire structure and check again. + recursorUtils.consumeDeep(rootDescriptor.createRecursor()) + + if (descriptorsByPointerIndex.has(descriptor.index)) { + return descriptorsByPointerIndex.get(descriptor.index) + } + } + + throw new PointerLookupError(descriptor.index) + } + + if (descriptor.isComplex === true) { + descriptorsByPointerIndex.set(descriptor.pointer, descriptor) + } + + return descriptor + } + + const getDescriptorDeserializer = (pluginIndex, id) => { + return (state, recursor) => { + const deserializeDescriptor = pluginIndex === 0 + ? id2deserialize.get(id) + : pluginMap.get(pluginIndex).get(id) + + return mapPointerDescriptor(deserializeDescriptor(state, recursor)) + } + } + + const rootDescriptor = deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer) + return rootDescriptor } diff --git a/lib/shouldCompareDeep.js b/lib/shouldCompareDeep.js index b806a09..1d34152 100644 --- a/lib/shouldCompareDeep.js +++ b/lib/shouldCompareDeep.js @@ -2,10 +2,10 @@ import { tag as argumentsObject } from './complexValues/arguments.js' import { AMBIGUOUS, SHALLOW_EQUAL } from './constants.js' export default function shouldCompareDeep (result, lhs, rhs) { - if (result === SHALLOW_EQUAL) return true - if (result !== AMBIGUOUS) return false + if (result === SHALLOW_EQUAL) return true + if (result !== AMBIGUOUS) return false - // Properties are only ambiguous if they have symbol keys. These properties - // must be compared in an order-insensitive manner. - return lhs.tag === argumentsObject || lhs.isProperty === true + // Properties are only ambiguous if they have symbol keys. These properties + // must be compared in an order-insensitive manner. + return lhs.tag === argumentsObject || lhs.isProperty === true } diff --git a/lib/symbolProperties.js b/lib/symbolProperties.js index a331ece..f645cbe 100644 --- a/lib/symbolProperties.js +++ b/lib/symbolProperties.js @@ -2,99 +2,99 @@ import { DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL } from './constants.js' import * as recursorUtils from './recursorUtils.js' export class Comparable { - constructor (properties) { - this.properties = properties - this.ordered = properties.slice() - } - - createRecursor () { - const length = this.ordered.length - let index = 0 - return () => { - if (index === length) return null - - return this.ordered[index++] - } - } - - compare (expected) { - if (this.properties.length !== expected.properties.length) return UNEQUAL - - // Compare property keys, reordering the expected properties in the process - // so values can be compared if all keys are equal. - const ordered = [] - const processed = new Set() - for (const property of this.properties) { - let extraneous = true - for (const other of expected.properties) { - if (processed.has(other.key)) continue - - if (property.key.compare(other.key) === DEEP_EQUAL) { - extraneous = false - processed.add(other.key) - ordered.push(other) - break - } - } - - if (extraneous) return UNEQUAL - } - expected.ordered = ordered - - return SHALLOW_EQUAL - } - - prepareDiff (expected) { - // Reorder the expected properties before recursion starts. - const missingProperties = [] - const ordered = [] - const processed = new Set() - for (const other of expected.properties) { - let missing = true - for (const property of this.properties) { - if (processed.has(property.key)) continue - - if (property.key.compare(other.key) === DEEP_EQUAL) { - missing = false - processed.add(property.key) - ordered.push(other) - break - } - } - - if (missing) { - missingProperties.push(other) - } - } - expected.ordered = ordered.concat(missingProperties) - - return { mustRecurse: true } - } - - isSymbolPropertiesComparable = true + constructor (properties) { + this.properties = properties + this.ordered = properties.slice() + } + + createRecursor () { + const length = this.ordered.length + let index = 0 + return () => { + if (index === length) return null + + return this.ordered[index++] + } + } + + compare (expected) { + if (this.properties.length !== expected.properties.length) return UNEQUAL + + // Compare property keys, reordering the expected properties in the process + // so values can be compared if all keys are equal. + const ordered = [] + const processed = new Set() + for (const property of this.properties) { + let extraneous = true + for (const other of expected.properties) { + if (processed.has(other.key)) continue + + if (property.key.compare(other.key) === DEEP_EQUAL) { + extraneous = false + processed.add(other.key) + ordered.push(other) + break + } + } + + if (extraneous) return UNEQUAL + } + expected.ordered = ordered + + return SHALLOW_EQUAL + } + + prepareDiff (expected) { + // Reorder the expected properties before recursion starts. + const missingProperties = [] + const ordered = [] + const processed = new Set() + for (const other of expected.properties) { + let missing = true + for (const property of this.properties) { + if (processed.has(property.key)) continue + + if (property.key.compare(other.key) === DEEP_EQUAL) { + missing = false + processed.add(property.key) + ordered.push(other) + break + } + } + + if (missing) { + missingProperties.push(other) + } + } + expected.ordered = ordered.concat(missingProperties) + + return { mustRecurse: true } + } + + isSymbolPropertiesComparable = true } export class Collector { - constructor (firstProperty, recursor) { - this.properties = [firstProperty] - this.recursor = recursor - this.remainder = null - } - - collectAll () { - do { - const next = this.recursor() - if (next && next.isProperty === true) { // All properties will have symbol keys - this.properties.push(next) - } else { - return next - } - } while (true) - } - - createRecursor () { - return recursorUtils.singleValue(new Comparable(this.properties)) - } - - isSymbolPropertiesCollector = true + constructor (firstProperty, recursor) { + this.properties = [firstProperty] + this.recursor = recursor + this.remainder = null + } + + collectAll () { + do { + const next = this.recursor() + if (next && next.isProperty === true) { // All properties will have symbol keys + this.properties.push(next) + } else { + return next + } + } while (true) + } + + createRecursor () { + return recursorUtils.singleValue(new Comparable(this.properties)) + } + + isSymbolPropertiesCollector = true } diff --git a/lib/themeUtils.js b/lib/themeUtils.js index dc0e648..df1c732 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -2,187 +2,187 @@ import {cloneDeep, merge} from './lodash/index.js' import * as pluginRegistry from './pluginRegistry.js' function freezeTheme (theme) { - const queue = [theme] - while (queue.length > 0) { - const object = queue.shift() - Object.freeze(object) - - for (const key of Object.keys(object)) { - const value = object[key] - if (value !== null && typeof value === 'object') { - queue.push(value) - } - } - } - - return theme + const queue = [theme] + while (queue.length > 0) { + const object = queue.shift() + Object.freeze(object) + + for (const key of Object.keys(object)) { + const value = object[key] + if (value !== null && typeof value === 'object') { + queue.push(value) + } + } + } + + return theme } const defaultTheme = freezeTheme({ - bigInt: { open: '', close: '' }, - boolean: { open: '', close: '' }, - circular: '[Circular]', - date: { - invalid: 'invalid', - value: { open: '', close: '' }, - }, - diffGutters: { - actual: '- ', - expected: '+ ', - padding: ' ', - }, - error: { - ctor: { open: '(', close: ')' }, - name: { open: '', close: '' }, - }, - function: { - name: { open: '', close: '' }, - stringTag: { open: '', close: '' }, - }, - global: { open: '', close: '' }, - item: { - after: ',', - customFormat: null, - increaseValueIndent: false, - }, - list: { openBracket: '[', closeBracket: ']' }, - mapEntry: { - after: ',', - separator: ' => ', - }, - maxDepth: '…', - null: { open: '', close: '' }, - number: { open: '', close: '' }, - object: { - openBracket: '{', - closeBracket: '}', - ctor: { open: '', close: '' }, - stringTag: { open: '@', close: '' }, - secondaryStringTag: { open: '@', close: '' }, - }, - property: { - after: ',', - customFormat: null, - keyBracket: { open: '[', close: ']' }, - separator: ': ', - increaseValueIndent: false, - }, - regexp: { - source: { open: '/', close: '/' }, - flags: { open: '', close: '' }, - separator: '---', - }, - stats: { separator: '---' }, - string: { - open: '', - close: '', - line: { open: "'", close: "'", escapeQuote: "'" }, - multiline: { start: '`', end: '`', escapeQuote: '`' }, - controlPicture: { open: '', close: '' }, - diff: { - insert: { open: '', close: '' }, - delete: { open: '', close: '' }, - equal: { open: '', close: '' }, - insertLine: { open: '', close: '' }, - deleteLine: { open: '', close: '' }, - }, - }, - symbol: { open: '', close: '' }, - typedArray: { - bytes: { open: '', close: '' }, - }, - undefined: { open: '', close: '' }, + bigInt: { open: '', close: '' }, + boolean: { open: '', close: '' }, + circular: '[Circular]', + date: { + invalid: 'invalid', + value: { open: '', close: '' }, + }, + diffGutters: { + actual: '- ', + expected: '+ ', + padding: ' ', + }, + error: { + ctor: { open: '(', close: ')' }, + name: { open: '', close: '' }, + }, + function: { + name: { open: '', close: '' }, + stringTag: { open: '', close: '' }, + }, + global: { open: '', close: '' }, + item: { + after: ',', + customFormat: null, + increaseValueIndent: false, + }, + list: { openBracket: '[', closeBracket: ']' }, + mapEntry: { + after: ',', + separator: ' => ', + }, + maxDepth: '…', + null: { open: '', close: '' }, + number: { open: '', close: '' }, + object: { + openBracket: '{', + closeBracket: '}', + ctor: { open: '', close: '' }, + stringTag: { open: '@', close: '' }, + secondaryStringTag: { open: '@', close: '' }, + }, + property: { + after: ',', + customFormat: null, + keyBracket: { open: '[', close: ']' }, + separator: ': ', + increaseValueIndent: false, + }, + regexp: { + source: { open: '/', close: '/' }, + flags: { open: '', close: '' }, + separator: '---', + }, + stats: { separator: '---' }, + string: { + open: '', + close: '', + line: { open: "'", close: "'", escapeQuote: "'" }, + multiline: { start: '`', end: '`', escapeQuote: '`' }, + controlPicture: { open: '', close: '' }, + diff: { + insert: { open: '', close: '' }, + delete: { open: '', close: '' }, + equal: { open: '', close: '' }, + insertLine: { open: '', close: '' }, + deleteLine: { open: '', close: '' }, + }, + }, + symbol: { open: '', close: '' }, + typedArray: { + bytes: { open: '', close: '' }, + }, + undefined: { open: '', close: '' }, }) const pluginRefs = new Map() pluginRefs.count = 0 const normalizedPluginThemes = new Map() function normalizePlugins (plugins) { - if (!Array.isArray(plugins) || plugins.length === 0) return null - - const refs = [] - const themes = [] - for (const fromPlugin of pluginRegistry.getThemes(plugins)) { - if (!pluginRefs.has(fromPlugin.name)) { - pluginRefs.set(fromPlugin.name, pluginRefs.count++) - } - - refs.push(pluginRefs.get(fromPlugin.name)) - themes.push(fromPlugin.theme) - } - - const ref = refs.join('.') - if (normalizedPluginThemes.has(ref)) { - return { - ref, - theme: normalizedPluginThemes.get(ref), - } - } - - const theme = freezeTheme(themes.reduce((acc, pluginTheme) => { - return merge(acc, pluginTheme) - }, cloneDeep(defaultTheme))) - normalizedPluginThemes.set(ref, theme) - return { ref, theme } + if (!Array.isArray(plugins) || plugins.length === 0) return null + + const refs = [] + const themes = [] + for (const fromPlugin of pluginRegistry.getThemes(plugins)) { + if (!pluginRefs.has(fromPlugin.name)) { + pluginRefs.set(fromPlugin.name, pluginRefs.count++) + } + + refs.push(pluginRefs.get(fromPlugin.name)) + themes.push(fromPlugin.theme) + } + + const ref = refs.join('.') + if (normalizedPluginThemes.has(ref)) { + return { + ref, + theme: normalizedPluginThemes.get(ref), + } + } + + const theme = freezeTheme(themes.reduce((acc, pluginTheme) => { + return merge(acc, pluginTheme) + }, cloneDeep(defaultTheme))) + normalizedPluginThemes.set(ref, theme) + return { ref, theme } } const normalizedCache = new WeakMap() export function normalize (options) { - options = Object.assign({ plugins: [], theme: null }, options) - - const normalizedPlugins = normalizePlugins(options.plugins) - if (!options.theme) { - return normalizedPlugins ? normalizedPlugins.theme : defaultTheme - } - - const entry = normalizedCache.get(options.theme) || { theme: null, withPlugins: new Map() } - if (!normalizedCache.has(options.theme)) normalizedCache.set(options.theme, entry) - - if (normalizedPlugins) { - if (entry.withPlugins.has(normalizedPlugins.ref)) { - return entry.withPlugins.get(normalizedPlugins.ref) - } - - const theme = freezeTheme(merge(cloneDeep(normalizedPlugins.theme), options.theme)) - entry.withPlugins.set(normalizedPlugins.ref, theme) - return theme - } - - if (!entry.theme) { - entry.theme = freezeTheme(merge(cloneDeep(defaultTheme), options.theme)) - } - return entry.theme + options = Object.assign({ plugins: [], theme: null }, options) + + const normalizedPlugins = normalizePlugins(options.plugins) + if (!options.theme) { + return normalizedPlugins ? normalizedPlugins.theme : defaultTheme + } + + const entry = normalizedCache.get(options.theme) || { theme: null, withPlugins: new Map() } + if (!normalizedCache.has(options.theme)) normalizedCache.set(options.theme, entry) + + if (normalizedPlugins) { + if (entry.withPlugins.has(normalizedPlugins.ref)) { + return entry.withPlugins.get(normalizedPlugins.ref) + } + + const theme = freezeTheme(merge(cloneDeep(normalizedPlugins.theme), options.theme)) + entry.withPlugins.set(normalizedPlugins.ref, theme) + return theme + } + + if (!entry.theme) { + entry.theme = freezeTheme(merge(cloneDeep(defaultTheme), options.theme)) + } + return entry.theme } const modifiers = new WeakMap() export function addModifier (descriptor, modifier) { - if (modifiers.has(descriptor)) { - modifiers.get(descriptor).add(modifier) - } else { - modifiers.set(descriptor, new Set([modifier])) - } + if (modifiers.has(descriptor)) { + modifiers.get(descriptor).add(modifier) + } else { + modifiers.set(descriptor, new Set([modifier])) + } } const modifierCache = new WeakMap() const originalCache = new WeakMap() export function applyModifiers (descriptor, theme) { - if (!modifiers.has(descriptor)) return theme + if (!modifiers.has(descriptor)) return theme - return Array.from(modifiers.get(descriptor)).reduce((prev, modifier) => { - const cache = modifierCache.get(modifier) || new WeakMap() - if (!modifierCache.has(modifier)) modifierCache.set(modifier, cache) + return Array.from(modifiers.get(descriptor)).reduce((prev, modifier) => { + const cache = modifierCache.get(modifier) || new WeakMap() + if (!modifierCache.has(modifier)) modifierCache.set(modifier, cache) - if (cache.has(prev)) return cache.get(prev) + if (cache.has(prev)) return cache.get(prev) - const modifiedTheme = cloneDeep(prev) - modifier(modifiedTheme) - freezeTheme(modifiedTheme) - cache.set(prev, modifiedTheme) - originalCache.set(modifiedTheme, theme) - return modifiedTheme - }, theme) + const modifiedTheme = cloneDeep(prev) + modifier(modifiedTheme) + freezeTheme(modifiedTheme) + cache.set(prev, modifiedTheme) + originalCache.set(modifiedTheme, theme) + return modifiedTheme + }, theme) } export function applyModifiersToOriginal (descriptor, theme) { - return applyModifiers(descriptor, originalCache.get(theme) || theme) + return applyModifiers(descriptor, originalCache.get(theme) || theme) } diff --git a/test/_instrumentedTheme.js b/test/_instrumentedTheme.js index 2badf35..548724d 100644 --- a/test/_instrumentedTheme.js +++ b/test/_instrumentedTheme.js @@ -4,22 +4,22 @@ const unused = new Set() const freeze = Object.freeze const createAccessors = (object, path = '') => { - for (const key of Object.keys(object)) { - const value = object[key] - const keyPath = path ? `${path}.${key}` : key - if (value && typeof value === 'object') { - createAccessors(value, keyPath) - } else if (typeof value === 'string') { - unused.add(keyPath) - Object.defineProperty(object, key, { - get () { - unused.delete(keyPath) - return `%${keyPath}${value ? '#' + value : ''}%` - }, - }) - } - } - freeze.call(Object, object) + for (const key of Object.keys(object)) { + const value = object[key] + const keyPath = path ? `${path}.${key}` : key + if (value && typeof value === 'object') { + createAccessors(value, keyPath) + } else if (typeof value === 'string') { + unused.add(keyPath) + Object.defineProperty(object, key, { + get () { + unused.delete(keyPath) + return `%${keyPath}${value ? '#' + value : ''}%` + }, + }) + } + } + freeze.call(Object, object) } export const theme = {} // normalize() caches the result, so this is just a cache key @@ -32,5 +32,5 @@ Object.freeze = freeze export const normalizedTheme = normalized export const checkThemeUsage = t => { - t.deepEqual(unused, new Set(), 'All theme properties should be accessed at least once') + t.deepEqual(unused, new Set(), 'All theme properties should be accessed at least once') } diff --git a/test/compare.js b/test/compare.js index 1bb76a1..b608ab4 100644 --- a/test/compare.js +++ b/test/compare.js @@ -2,66 +2,66 @@ import test from 'ava' import {compare} from '../lib/compare.js' test('compare functions by reference', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - const a_ = (() => { - return function a () { return 1 + 2 } // eslint-disable-line no-shadow - })() + function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + const a_ = (() => { + return function a () { return 1 + 2 } // eslint-disable-line no-shadow + })() - t.false(compare(a, a_).pass) + t.false(compare(a, a_).pass) }) test('compare function by names', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - t.false(compare(a, b).pass) + t.false(compare(a, b).pass) }) test('objects compare even if symbol properties are out of order', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const o1 = { [s1]: 1, [s2]: 2 } - const o2 = { [s2]: 2, [s1]: 1 } + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const o1 = { [s1]: 1, [s2]: 2 } + const o2 = { [s2]: 2, [s1]: 1 } - t.true(compare(o1, o2).pass) + t.true(compare(o1, o2).pass) - const a1 = new Set([1, 2]) - a1[s1] = 1 - a1[s2] = 2 - const a2 = new Set([1, 2]) - a2[s2] = 2 - a2[s1] = 1 + const a1 = new Set([1, 2]) + a1[s1] = 1 + a1[s2] = 2 + const a2 = new Set([1, 2]) + a2[s2] = 2 + a2[s1] = 1 - t.true(compare(a1, a2).pass) + t.true(compare(a1, a2).pass) }) test('-0 is not equal to +0', t => { - t.false(compare(-0, +0).pass) - t.false(compare({ zero: -0 }, { zero: +0 }).pass) + t.false(compare(-0, +0).pass) + t.false(compare({ zero: -0 }, { zero: +0 }).pass) }) test('NaN is equal to NaN', t => { - t.true(compare(NaN, NaN).pass) - t.true(compare({ notANumber: NaN }, { notANumber: NaN }).pass) + t.true(compare(NaN, NaN).pass) + t.true(compare({ notANumber: NaN }, { notANumber: NaN }).pass) }) test('survives odd circular references', t => { - const foo = { foo: {} } - foo.foo.foo = foo - const foo2 = {} - foo2.foo = foo - t.false(compare(foo, foo2).pass) + const foo = { foo: {} } + foo.foo.foo = foo + const foo2 = {} + foo2.foo = foo + t.false(compare(foo, foo2).pass) }) test('arrays are also compared by property', t => { - const a1 = [1, 2, 3] - a1.p = 'a1' - const a2 = [1, 2, 3] - a2.p = 'a2' - t.false(compare(a1, a2).pass) + const a1 = [1, 2, 3] + a1.p = 'a1' + const a2 = [1, 2, 3] + a2.p = 'a2' + t.false(compare(a1, a2).pass) - const a3 = [1, 2, 3] - const a4 = [1, 2, 3] - a4[-1] = -1 - t.false(compare(a3, a4).pass) + const a3 = [1, 2, 3] + const a4 = [1, 2, 3] + a4[-1] = -1 + t.false(compare(a3, a4).pass) }) diff --git a/test/diff.js b/test/diff.js index 343b2c9..dc52653 100644 --- a/test/diff.js +++ b/test/diff.js @@ -9,93 +9,93 @@ const diff = (actual, expected, { invert } = {}) => _diff(actual, expected, { in test.after(checkThemeUsage) void ( - // Tested separately - normalizedTheme.maxDepth + // Tested separately + normalizedTheme.maxDepth ) if (typeof BigInt === 'undefined') { - void ( - normalizedTheme.bigInt.open, - normalizedTheme.bigInt.close - ) + void ( + normalizedTheme.bigInt.open, + normalizedTheme.bigInt.close + ) } { - const diffsPrimitives = (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)) - diffsPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { - return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` - } - for (const [lhs, rhs] of [ - [null, undefined], - [null, false], - [null, true], - [null, ''], - [null, 42], - [null, Symbol()], // eslint-disable-line symbol-description - [Symbol(), Symbol()], // eslint-disable-line symbol-description - [null, {}], - ]) { - test(diffsPrimitives, lhs, rhs) - } - - if (typeof BigInt === 'function') { - test(diffsPrimitives, null, BigInt(42), 'null', '42n') // eslint-disable-line no-undef - } + const diffsPrimitives = (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)) + diffsPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { + return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` + } + for (const [lhs, rhs] of [ + [null, undefined], + [null, false], + [null, true], + [null, ''], + [null, 42], + [null, Symbol()], // eslint-disable-line symbol-description + [Symbol(), Symbol()], // eslint-disable-line symbol-description + [null, {}], + ]) { + test(diffsPrimitives, lhs, rhs) + } + + if (typeof BigInt === 'function') { + test(diffsPrimitives, null, BigInt(42), 'null', '42n') // eslint-disable-line no-undef + } } { - const diffsBoxedPrimitives = (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))) - diffsBoxedPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { - return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` - } - for (const [lhs, rhs] of [ - [true, false], - [-42, 42], - ['foo', 'bar'], - ]) { - test(diffsBoxedPrimitives, lhs, rhs) - } - - if (typeof BigInt === 'function') { - test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n') // eslint-disable-line no-undef - } + const diffsBoxedPrimitives = (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))) + diffsBoxedPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { + return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` + } + for (const [lhs, rhs] of [ + [true, false], + [-42, 42], + ['foo', 'bar'], + ]) { + test(diffsBoxedPrimitives, lhs, rhs) + } + + if (typeof BigInt === 'function') { + test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n') // eslint-disable-line no-undef + } } test('diffs boxed primitives with extra properties', t => { - t.snapshot(diff(new Object('foo'), Object.assign(new Object('foo'), { bar: 'baz' }))) + t.snapshot(diff(new Object('foo'), Object.assign(new Object('foo'), { bar: 'baz' }))) }) test('diffs single line strings', t => { - const actual1 = diff('foo', 'bar') - t.snapshot(actual1) + const actual1 = diff('foo', 'bar') + t.snapshot(actual1) - const actual2 = diff('bar', 'baz') - t.snapshot(actual2) + const actual2 = diff('bar', 'baz') + t.snapshot(actual2) }) test('diffs multiline strings', t => { - const actual1 = diff('foo\nbar', 'baz\nbar') - t.snapshot(actual1) + const actual1 = diff('foo\nbar', 'baz\nbar') + t.snapshot(actual1) - const actual2 = diff('foo\nbar', 'foo\nbaz') - t.snapshot(actual2) + const actual2 = diff('foo\nbar', 'foo\nbaz') + t.snapshot(actual2) - const actual3 = diff('foo\nbar\nbaz', 'foo\nbaz') - t.snapshot(actual3) + const actual3 = diff('foo\nbar\nbaz', 'foo\nbaz') + t.snapshot(actual3) - const actual4 = diff('foo\nbaz', 'foo\nbar\nbaz') - t.snapshot(actual4) + const actual4 = diff('foo\nbaz', 'foo\nbar\nbaz') + t.snapshot(actual4) - const actual5 = diff('foo\n', 'foo\nbaz') - t.snapshot(actual5) + const actual5 = diff('foo\n', 'foo\nbaz') + t.snapshot(actual5) - const actual6 = diff('foo\nbaz', 'foo\n') - t.snapshot(actual6) + const actual6 = diff('foo\nbaz', 'foo\n') + t.snapshot(actual6) - const actual7 = diff('foo\nbar\nbaz', 'foo\n') - t.snapshot(actual7) + const actual7 = diff('foo\nbar\nbaz', 'foo\n') + t.snapshot(actual7) - const actual8 = diff(`foo + const actual8 = diff(`foo bar baz qux @@ -104,465 +104,465 @@ grault baz garply quux`) - t.snapshot(actual8) + t.snapshot(actual8) - const actual9 = diff('foo\nbar\ncorge\nbaz\nqux\nquux\n', 'foo\nbar\nbaz\ngrault\nqux\nquux') - t.snapshot(actual9) + const actual9 = diff('foo\nbar\ncorge\nbaz\nqux\nquux\n', 'foo\nbar\nbaz\ngrault\nqux\nquux') + t.snapshot(actual9) }) test('diffs diverging complex types', t => { - const actual = diff({ foo: 'bar' }, ['baz']) - t.snapshot(actual) + const actual = diff({ foo: 'bar' }, ['baz']) + t.snapshot(actual) }) { - const mapArray = arr => arr - const mapArguments = arr => { let args; (function () { args = arguments })(...arr); return args } - const mapSet = arr => new Set(arr) - - const equalLength = (t, map) => { - const actual1 = diff(map([1, 2, 4]), map([1, 3, 4])) - t.snapshot(actual1) - - const actual2 = diff( - map([1, { foo: 'bar' }, 2]), - map([1, { baz: 'qux' }, 2])) - t.snapshot(actual2) - - class Foo { - constructor () { - this.foo = 'foo' - } - } - class Bar { - constructor () { - this.bar = 'bar' - } - } - const actual3 = diff( - map([new Foo()]), - map([new Bar()])) - t.snapshot(actual3) - - const actual4 = diff( - map([Buffer.alloc(0)]), - map([new Uint8Array()])) - t.snapshot(actual4) - - const actual5 = diff(map([1, 2]), map([1])) - t.snapshot(actual5) - } - test('diffs arrays', equalLength, mapArray) - test('diffs arguments', equalLength, mapArguments) - test('diffs sets', equalLength, mapSet) - - const extraneous = (t, map) => { - const actual1 = diff(map([1, 3, 2]), map([1, 2])) - t.snapshot(actual1) - - const actual2 = diff(map([1, {}, 2]), map([1, 2])) - t.snapshot(actual2) - - const actual3 = diff( - map([1, { foo: 'bar' }, { baz: 'qux' }, 2]), - map([1, { baz: 'qux' }, 2])) - t.snapshot(actual3) - - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const actual4 = diff( - map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2]), - map([1, { [s2]: 'qux' }, 2])) - t.snapshot(actual4) - } - test('detects extraneous array items', extraneous, mapArray) - test('detects extraneous arguments items', extraneous, mapArguments) - test('detects extraneous set items', extraneous, mapSet) - - const missing = (t, map) => { - const actual1 = diff(map([1, 2]), map([1, 3, 2])) - t.snapshot(actual1) - - const actual2 = diff(map([1, 2]), map([1, {}, 2])) - t.snapshot(actual2) - - const actual3 = diff( - map([1, { baz: 'qux' }, 2]), - map([1, { foo: 'bar' }, { baz: 'qux' }, 2])) - t.snapshot(actual3) - - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const actual4 = diff( - map([1, { [s2]: 'qux' }, 2]), - map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2])) - t.snapshot(actual4) - } - test('detects missing array items', missing, mapArray) - test('detects missing arguments items', missing, mapArguments) - test('detects missing set items', missing, mapSet) + const mapArray = arr => arr + const mapArguments = arr => { let args; (function () { args = arguments })(...arr); return args } + const mapSet = arr => new Set(arr) + + const equalLength = (t, map) => { + const actual1 = diff(map([1, 2, 4]), map([1, 3, 4])) + t.snapshot(actual1) + + const actual2 = diff( + map([1, { foo: 'bar' }, 2]), + map([1, { baz: 'qux' }, 2])) + t.snapshot(actual2) + + class Foo { + constructor () { + this.foo = 'foo' + } + } + class Bar { + constructor () { + this.bar = 'bar' + } + } + const actual3 = diff( + map([new Foo()]), + map([new Bar()])) + t.snapshot(actual3) + + const actual4 = diff( + map([Buffer.alloc(0)]), + map([new Uint8Array()])) + t.snapshot(actual4) + + const actual5 = diff(map([1, 2]), map([1])) + t.snapshot(actual5) + } + test('diffs arrays', equalLength, mapArray) + test('diffs arguments', equalLength, mapArguments) + test('diffs sets', equalLength, mapSet) + + const extraneous = (t, map) => { + const actual1 = diff(map([1, 3, 2]), map([1, 2])) + t.snapshot(actual1) + + const actual2 = diff(map([1, {}, 2]), map([1, 2])) + t.snapshot(actual2) + + const actual3 = diff( + map([1, { foo: 'bar' }, { baz: 'qux' }, 2]), + map([1, { baz: 'qux' }, 2])) + t.snapshot(actual3) + + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const actual4 = diff( + map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2]), + map([1, { [s2]: 'qux' }, 2])) + t.snapshot(actual4) + } + test('detects extraneous array items', extraneous, mapArray) + test('detects extraneous arguments items', extraneous, mapArguments) + test('detects extraneous set items', extraneous, mapSet) + + const missing = (t, map) => { + const actual1 = diff(map([1, 2]), map([1, 3, 2])) + t.snapshot(actual1) + + const actual2 = diff(map([1, 2]), map([1, {}, 2])) + t.snapshot(actual2) + + const actual3 = diff( + map([1, { baz: 'qux' }, 2]), + map([1, { foo: 'bar' }, { baz: 'qux' }, 2])) + t.snapshot(actual3) + + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const actual4 = diff( + map([1, { [s2]: 'qux' }, 2]), + map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2])) + t.snapshot(actual4) + } + test('detects missing array items', missing, mapArray) + test('detects missing arguments items', missing, mapArguments) + test('detects missing set items', missing, mapSet) } test('detects extraneous name properties', t => { - const actual1 = diff( - { a: 1, b: 2, c: 3 }, - { a: 1, c: 3 }) - t.snapshot(actual1) + const actual1 = diff( + { a: 1, b: 2, c: 3 }, + { a: 1, c: 3 }) + t.snapshot(actual1) - const actual2 = diff( - { a: 1, b: {}, c: 3 }, - { a: 1, c: 3 }) - t.snapshot(actual2) + const actual2 = diff( + { a: 1, b: {}, c: 3 }, + { a: 1, c: 3 }) + t.snapshot(actual2) }) test('detects missing name properties', t => { - const actual1 = diff( - { a: 1, c: 3 }, - { a: 1, b: 2, c: 3 }) - t.snapshot(actual1) + const actual1 = diff( + { a: 1, c: 3 }, + { a: 1, b: 2, c: 3 }) + t.snapshot(actual1) - const actual2 = diff( - { a: 1, c: 3 }, - { a: 1, b: {}, c: 3 }) - t.snapshot(actual2) + const actual2 = diff( + { a: 1, c: 3 }, + { a: 1, b: {}, c: 3 }) + t.snapshot(actual2) }) test('detects extraneous symbol properties', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const s3 = Symbol('s3') - const actual1 = diff( - { [s1]: 1, [s2]: 2, [s3]: 3 }, - { [s1]: 1, [s3]: 3 }) - t.snapshot(actual1) + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const s3 = Symbol('s3') + const actual1 = diff( + { [s1]: 1, [s2]: 2, [s3]: 3 }, + { [s1]: 1, [s3]: 3 }) + t.snapshot(actual1) - const actual2 = diff( - { [s1]: 1, [s2]: {}, [s3]: 3 }, - { [s1]: 1, [s3]: 3 }) - t.snapshot(actual2) + const actual2 = diff( + { [s1]: 1, [s2]: {}, [s3]: 3 }, + { [s1]: 1, [s3]: 3 }) + t.snapshot(actual2) }) test('detects missing symbol properties', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const s3 = Symbol('s3') - const actual1 = diff( - { [s1]: 1, [s3]: 3 }, - { [s1]: 1, [s2]: 2, [s3]: 3 }) - // Note that when symbol properties are sorted, they're sorted according to - // their order in the actual value. Missing properties will end up at the - // bottom. - t.snapshot(actual1) - - const actual2 = diff( - { [s1]: 1, [s3]: 3 }, - { [s1]: 1, [s2]: {}, [s3]: 3 }) - t.snapshot(actual2) + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const s3 = Symbol('s3') + const actual1 = diff( + { [s1]: 1, [s3]: 3 }, + { [s1]: 1, [s2]: 2, [s3]: 3 }) + // Note that when symbol properties are sorted, they're sorted according to + // their order in the actual value. Missing properties will end up at the + // bottom. + t.snapshot(actual1) + + const actual2 = diff( + { [s1]: 1, [s3]: 3 }, + { [s1]: 1, [s2]: {}, [s3]: 3 }) + t.snapshot(actual2) }) test('diffs maps', t => { - const actual1 = diff( - new Map([[1, 1], [2, 2], [4, 4]]), - new Map([[1, 1], [3, 3], [4, 4]])) - t.snapshot(actual1) + const actual1 = diff( + new Map([[1, 1], [2, 2], [4, 4]]), + new Map([[1, 1], [3, 3], [4, 4]])) + t.snapshot(actual1) - const actual2 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), - new Map([[1, 1], [{ baz: 'qux' }, 2], [4, 4]])) - t.snapshot(actual2) + const actual2 = diff( + new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), + new Map([[1, 1], [{ baz: 'qux' }, 2], [4, 4]])) + t.snapshot(actual2) - const actual3 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), - new Map([[1, 1], [{ baz: 'qux' }, 3], [4, 4]])) - t.snapshot(actual3) + const actual3 = diff( + new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), + new Map([[1, 1], [{ baz: 'qux' }, 3], [4, 4]])) + t.snapshot(actual3) }) test('detects extraneous map entries', t => { - const actual1 = diff( - new Map([[1, 1], [3, 3], [2, 2]]), - new Map([[1, 1], [2, 2]])) - t.snapshot(actual1) + const actual1 = diff( + new Map([[1, 1], [3, 3], [2, 2]]), + new Map([[1, 1], [2, 2]])) + t.snapshot(actual1) - const actual2 = diff( - new Map([[1, 1], [{}, 3], [2, 2]]), - new Map([[1, 1], [2, 2]])) - t.snapshot(actual2) + const actual2 = diff( + new Map([[1, 1], [{}, 3], [2, 2]]), + new Map([[1, 1], [2, 2]])) + t.snapshot(actual2) - const actual3 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]])) - t.snapshot(actual3) + const actual3 = diff( + new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]]), + new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]])) + t.snapshot(actual3) - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const actual4 = diff( - new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]])) - t.snapshot(actual4) + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const actual4 = diff( + new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]]), + new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]])) + t.snapshot(actual4) }) test('detects missing map entries', t => { - const actual1 = diff( - new Map([[1, 1], [2, 2]]), - new Map([[1, 1], [3, 3], [2, 2]])) - t.snapshot(actual1) + const actual1 = diff( + new Map([[1, 1], [2, 2]]), + new Map([[1, 1], [3, 3], [2, 2]])) + t.snapshot(actual1) - const actual2 = diff( - new Map([[1, 1], [2, 2]]), - new Map([[1, 1], [{}, 3], [2, 2]])) - t.snapshot(actual2) + const actual2 = diff( + new Map([[1, 1], [2, 2]]), + new Map([[1, 1], [{}, 3], [2, 2]])) + t.snapshot(actual2) - const actual3 = diff( - new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]])) - t.snapshot(actual3) + const actual3 = diff( + new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]]), + new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]])) + t.snapshot(actual3) - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const actual4 = diff( - new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]])) - t.snapshot(actual4) + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const actual4 = diff( + new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]]), + new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]])) + t.snapshot(actual4) }) test('diffs maps with extra properties', t => { - const actual1 = diff(new Map([['foo', 'bar']]), Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' })) - t.snapshot(actual1) + const actual1 = diff(new Map([['foo', 'bar']]), Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' })) + t.snapshot(actual1) - const actual2 = diff(Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' }), new Map([['foo', 'bar']])) - t.snapshot(actual2) + const actual2 = diff(Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' }), new Map([['foo', 'bar']])) + t.snapshot(actual2) }) test('diffs multiline string values in objects', t => { - const actual1 = diff({ foo: 'bar\nbaz' }, { foo: 'qux\nbaz' }) - t.snapshot(actual1) + const actual1 = diff({ foo: 'bar\nbaz' }, { foo: 'qux\nbaz' }) + t.snapshot(actual1) - const actual2 = diff({ foo: 'bar\nbaz\nqux' }, { foo: 'bar\nqux\nbaz' }) - t.snapshot(actual2) + const actual2 = diff({ foo: 'bar\nbaz\nqux' }, { foo: 'bar\nqux\nbaz' }) + t.snapshot(actual2) - const s1 = Symbol('s1') - const actual3 = diff({ [s1]: 'bar\nbaz' }, { [s1]: 'qux\nbaz' }) - t.snapshot(actual3) + const s1 = Symbol('s1') + const actual3 = diff({ [s1]: 'bar\nbaz' }, { [s1]: 'qux\nbaz' }) + t.snapshot(actual3) }) test('diffs multiline string values in arrays', t => { - const actual = diff(['foo\nbar'], ['baz\nbar']) - t.snapshot(actual) + const actual = diff(['foo\nbar'], ['baz\nbar']) + t.snapshot(actual) }) test('diffs multiline string values in sets', t => { - const actual = diff(new Set(['foo\nbar']), new Set(['baz\nbar'])) - t.snapshot(actual) + const actual = diff(new Set(['foo\nbar']), new Set(['baz\nbar'])) + t.snapshot(actual) }) test('diffs multiline string values in maps when key is primitive', t => { - const actual1 = diff(new Map([[1, 'foo\nbar']]), new Map([[1, 'baz\nbar']])) - t.snapshot(actual1) + const actual1 = diff(new Map([[1, 'foo\nbar']]), new Map([[1, 'baz\nbar']])) + t.snapshot(actual1) - const actual2 = diff(new Map([['foo\nbar', 'foo\nbar']]), new Map([['foo\nbar', 'baz\nbar']])) - t.snapshot(actual2) + const actual2 = diff(new Map([['foo\nbar', 'foo\nbar']]), new Map([['foo\nbar', 'baz\nbar']])) + t.snapshot(actual2) - const actual3 = diff(new Map([['foo', 'bar\nbaz\nqux']]), new Map([['foo', 'bar\nqux\nbaz']])) - t.snapshot(actual3) + const actual3 = diff(new Map([['foo', 'bar\nbaz\nqux']]), new Map([['foo', 'bar\nqux\nbaz']])) + t.snapshot(actual3) }) test('does not diff multiline string values in maps when key is complex', t => { - const actual = diff(new Map([[{}, 'foo\nbar']]), new Map([[{}, 'baz\nbar']])) - t.snapshot(actual) + const actual = diff(new Map([[{}, 'foo\nbar']]), new Map([[{}, 'baz\nbar']])) + t.snapshot(actual) }) test('diffs properties with different values', t => { - class Foo { constructor () { this.value = 42 } } - class Bar { constructor () { this.value = 42 } } - const actual1 = diff({ value: new Foo() }, { value: new Bar() }) - t.snapshot(actual1) + class Foo { constructor () { this.value = 42 } } + class Bar { constructor () { this.value = 42 } } + const actual1 = diff({ value: new Foo() }, { value: new Bar() }) + t.snapshot(actual1) - const actual2 = diff({ value: new Foo() }, { value: 42 }) - t.snapshot(actual2) + const actual2 = diff({ value: new Foo() }, { value: 42 }) + t.snapshot(actual2) - const actual3 = diff({ value: new Foo() }, { value: 'foo\nbar' }) - t.snapshot(actual3) + const actual3 = diff({ value: new Foo() }, { value: 'foo\nbar' }) + t.snapshot(actual3) - const actual4 = diff({ foo: 'bar' }, { foo: 'not bar' }) - t.snapshot(actual4) + const actual4 = diff({ foo: 'bar' }, { foo: 'not bar' }) + t.snapshot(actual4) }) test('diffs map keys with different values', t => { - class Foo { constructor () { this.value = 42 } } - class Bar { constructor () { this.value = 42 } } - const actual1 = diff(new Map([['key', new Foo()]]), new Map([['key', new Bar()]])) - t.snapshot(actual1) + class Foo { constructor () { this.value = 42 } } + class Bar { constructor () { this.value = 42 } } + const actual1 = diff(new Map([['key', new Foo()]]), new Map([['key', new Bar()]])) + t.snapshot(actual1) - const actual2 = diff(new Map([['key', new Foo()]]), new Map([['key', 42]])) - t.snapshot(actual2) + const actual2 = diff(new Map([['key', new Foo()]]), new Map([['key', 42]])) + t.snapshot(actual2) - const actual3 = diff(new Map([['key', new Foo()]]), new Map([['key', 'foo\nbar']])) - t.snapshot(actual3) + const actual3 = diff(new Map([['key', new Foo()]]), new Map([['key', 'foo\nbar']])) + t.snapshot(actual3) - const actual4 = diff(new Map([['key\nline', new Foo()]]), new Map([['key\nline', new Bar()]])) - t.snapshot(actual4) + const actual4 = diff(new Map([['key\nline', new Foo()]]), new Map([['key\nline', new Bar()]])) + t.snapshot(actual4) }) test('diffs circular references', t => { - const obj1 = { obj: {} } - obj1.obj.obj = obj1 - const obj2 = {} - obj2.obj = obj2 - t.snapshot(diff(obj1, obj2)) - - obj2.obj = obj1 - t.snapshot(diff(obj1, obj2)) - - const arr1 = [[]] - arr1[0][0] = arr1 - const arr2 = [] - arr2[0] = arr1 - t.snapshot(diff(arr1, arr2)) - - const map1 = new Map([['map', new Map()]]) - map1.get('map').set('map', map1) - const map2 = new Map() - map2.set('map', map1) - t.snapshot(diff(map1, map2)) - - const key = { key: true } - const map3 = new Map([[key, new Map()]]) - map3.get(key).set(key, map3) - const map4 = new Map() - map4.set(key, map3) - t.snapshot(diff(map3, map4)) + const obj1 = { obj: {} } + obj1.obj.obj = obj1 + const obj2 = {} + obj2.obj = obj2 + t.snapshot(diff(obj1, obj2)) + + obj2.obj = obj1 + t.snapshot(diff(obj1, obj2)) + + const arr1 = [[]] + arr1[0][0] = arr1 + const arr2 = [] + arr2[0] = arr1 + t.snapshot(diff(arr1, arr2)) + + const map1 = new Map([['map', new Map()]]) + map1.get('map').set('map', map1) + const map2 = new Map() + map2.set('map', map1) + t.snapshot(diff(map1, map2)) + + const key = { key: true } + const map3 = new Map([[key, new Map()]]) + map3.get(key).set(key, map3) + const map4 = new Map() + map4.set(key, map3) + t.snapshot(diff(map3, map4)) }) test('diff invalid dates', t => { - t.snapshot(diff(new Date('🚀🌔🛬'), new Date('🚀💥💧'))) + t.snapshot(diff(new Date('🚀🌔🛬'), new Date('🚀💥💧'))) }) test('diff dates with extra properties', t => { - const actual = diff(new Date('1969-07-20T20:17:40.000Z'), Object.assign(new Date('1969-07-21T20:17:40.000Z'), { - foo: 'bar', - })) - t.snapshot(actual) + const actual = diff(new Date('1969-07-20T20:17:40.000Z'), Object.assign(new Date('1969-07-21T20:17:40.000Z'), { + foo: 'bar', + })) + t.snapshot(actual) }) test('diffs errors', t => { - class Custom extends Error {} // eslint-disable-line unicorn/custom-error-definition - t.snapshot(diff(new Custom(), new Error())) + class Custom extends Error {} // eslint-disable-line unicorn/custom-error-definition + t.snapshot(diff(new Custom(), new Error())) }) test('diffs functions', t => { - t.snapshot(diff(function foo () {}, function bar () {})) + t.snapshot(diff(function foo () {}, function bar () {})) }) test('diffs globals', t => { - t.snapshot(diff(global, global)) + t.snapshot(diff(global, global)) }) test('diffs objects without constructor', t => { - const obj = {} - Object.defineProperty(obj, 'constructor', {}) - t.snapshot(diff(obj, {})) + const obj = {} + Object.defineProperty(obj, 'constructor', {}) + t.snapshot(diff(obj, {})) }) test('diffs builtin subclasses', t => { - class Foo extends Array {} - t.snapshot(diff(new Foo(), [])) + class Foo extends Array {} + t.snapshot(diff(new Foo(), [])) }) test('diffs regexps', t => { - t.snapshot(diff(/foo/, /foo/g)) - t.snapshot(diff(/foo/, Object.assign(/foo/, { bar: 'baz' }))) + t.snapshot(diff(/foo/, /foo/g)) + t.snapshot(diff(/foo/, Object.assign(/foo/, { bar: 'baz' }))) }) test('diffs buffers', t => { - t.snapshot(diff(Buffer.from('decafbad', 'hex'), Buffer.from('flat white', 'utf8'))) + t.snapshot(diff(Buffer.from('decafbad', 'hex'), Buffer.from('flat white', 'utf8'))) }) test('inverted diffs', t => { - t.snapshot(diff({ - foo: 'bar', - baz: 'qux\nquux\ncorge', - }, { - foo: 'BAR', - baz: 'qux\ncorge\nquux', - }, { invert: true })) + t.snapshot(diff({ + foo: 'bar', + baz: 'qux\nquux\ncorge', + }, { + foo: 'BAR', + baz: 'qux\ncorge\nquux', + }, { invert: true })) }) test('inverts string diffs', t => { - t.snapshot(diff('foo', 'bar', { invert: true })) - t.snapshot(diff('foo bar baz', 'foo baz quux', { invert: true })) - t.snapshot(diff('foo\nbar\nbaz', 'foobarbaz', { invert: true })) + t.snapshot(diff('foo', 'bar', { invert: true })) + t.snapshot(diff('foo bar baz', 'foo baz quux', { invert: true })) + t.snapshot(diff('foo\nbar\nbaz', 'foobarbaz', { invert: true })) }) test('inverts string diffs in containers', t => { - const actual = 'foo\nbar\nbaz' - const expected = 'foo\nbaz\nquux' + const actual = 'foo\nbar\nbaz' + const expected = 'foo\nbaz\nquux' - t.snapshot(diff({ a: actual }, { a: expected }, { invert: true })) - t.snapshot(diff([actual], [expected], { invert: true })) - t.snapshot(diff(new Map().set('a', actual), new Map().set('a', expected), { invert: true })) - t.snapshot(diff(new Set().add(actual), new Set().add(expected), { invert: true })) - t.snapshot(diff(new String(actual), new String(expected), { invert: true })) // eslint-disable-line unicorn/new-for-builtins, no-new-wrappers + t.snapshot(diff({ a: actual }, { a: expected }, { invert: true })) + t.snapshot(diff([actual], [expected], { invert: true })) + t.snapshot(diff(new Map().set('a', actual), new Map().set('a', expected), { invert: true })) + t.snapshot(diff(new Set().add(actual), new Set().add(expected), { invert: true })) + t.snapshot(diff(new String(actual), new String(expected), { invert: true })) // eslint-disable-line unicorn/new-for-builtins, no-new-wrappers - t.snapshot(diff({ a: { b: actual } }, { a: { b: expected } }, { invert: true })) + t.snapshot(diff({ a: { b: actual } }, { a: { b: expected } }, { invert: true })) }) test('lists: effectively resets depth when formatting differences', t => { - const l1 = [ - { - b: 'b', - }, - { - d: 'bar', - e: { - f: 'f', - }, - }, - ] - const l2 = [ - { - b: 'b', - }, - ] - t.snapshot(_diff(l1, l2, { maxDepth: 1, theme })) + const l1 = [ + { + b: 'b', + }, + { + d: 'bar', + e: { + f: 'f', + }, + }, + ] + const l2 = [ + { + b: 'b', + }, + ] + t.snapshot(_diff(l1, l2, { maxDepth: 1, theme })) }) test('objects: effectively resets depth when formatting differences', t => { - const o1 = { - a: { - b: 'b', - }, - c: { - d: 'bar', - e: { - f: 'f', - }, - }, - } - const o2 = { - a: { - b: 'b', - }, - } - t.snapshot(_diff(o1, o2, { maxDepth: 1, theme })) + const o1 = { + a: { + b: 'b', + }, + c: { + d: 'bar', + e: { + f: 'f', + }, + }, + } + const o2 = { + a: { + b: 'b', + }, + } + t.snapshot(_diff(o1, o2, { maxDepth: 1, theme })) }) // See . test('diff pointers hidden behind maxDepth', t => { - const value = {} - const descriptor = concordance.describe({ - // `value` is encoded in the serialization of `a.b`. `c` is encoded as a - // pointer to the encoded `value`. - a: { - b: value, - }, - c: value, - }) - const serialized = concordance.serialize(descriptor) - - t.notThrows(() => { - // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the - // `c` pointer cannot be resolved, unless the resolution logic first - // deserializes the descriptor in its entirety. - concordance.diffDescriptors(concordance.deserialize(serialized), concordance.describe(undefined), { maxDepth: 1 }) - }) + const value = {} + const descriptor = concordance.describe({ + // `value` is encoded in the serialization of `a.b`. `c` is encoded as a + // pointer to the encoded `value`. + a: { + b: value, + }, + c: value, + }) + const serialized = concordance.serialize(descriptor) + + t.notThrows(() => { + // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the + // `c` pointer cannot be resolved, unless the resolution logic first + // deserializes the descriptor in its entirety. + concordance.diffDescriptors(concordance.deserialize(serialized), concordance.describe(undefined), { maxDepth: 1 }) + }) }) diff --git a/test/fixtures/customErrorPlugin.js b/test/fixtures/customErrorPlugin.js index 9f6deb1..2c38e02 100644 --- a/test/fixtures/customErrorPlugin.js +++ b/test/fixtures/customErrorPlugin.js @@ -1,42 +1,42 @@ export class CustomError extends Error { - constructor (message, code) { - super(message) - this.code = code - this.name = 'CustomError' - } + constructor (message, code) { + super(message) + this.code = code + this.name = 'CustomError' + } } export const factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) { - const tag = Symbol.for('customError') + const tag = Symbol.for('customError') - class DescribedErrorValue extends DescribedMixin(ObjectValue) { - createPropertyRecursor () { - let i = 0 - return { - size: 1, - next: () => { - if (i === 1) { - return null - } - i++ - return this.describeProperty('code', this.describeAny(this.value.code)) - }, - } - } + class DescribedErrorValue extends DescribedMixin(ObjectValue) { + createPropertyRecursor () { + let i = 0 + return { + size: 1, + next: () => { + if (i === 1) { + return null + } + i++ + return this.describeProperty('code', this.describeAny(this.value.code)) + }, + } + } - tag = tag - } + tag = tag + } - const DeserializedErrorValue = DeserializedMixin(ObjectValue) - Object.defineProperty(DeserializedErrorValue.prototype, 'tag', { value: tag }) + const DeserializedErrorValue = DeserializedMixin(ObjectValue) + Object.defineProperty(DeserializedErrorValue.prototype, 'tag', { value: tag }) - return { - describe (props) { - return new DescribedErrorValue(props) - }, - deserialize (state, recursor) { - return new DeserializedErrorValue(state, recursor) - }, - tag, - } + return { + describe (props) { + return new DescribedErrorValue(props) + }, + deserialize (state, recursor) { + return new DeserializedErrorValue(state, recursor) + }, + tag, + } } diff --git a/test/fixtures/pointerSerialization.js b/test/fixtures/pointerSerialization.js index 0139c53..1ec1dd6 100644 --- a/test/fixtures/pointerSerialization.js +++ b/test/fixtures/pointerSerialization.js @@ -3,8 +3,8 @@ import concordance from '../../index.js' const foo = {} export const tree = { - foo, - bar: { foo }, + foo, + bar: { foo }, } const binFile = new URL('./pointerSerialization.bin', import.meta.url) diff --git a/test/format.js b/test/format.js index d935293..d3295c1 100644 --- a/test/format.js +++ b/test/format.js @@ -9,460 +9,460 @@ const format = value => _format(value, { theme }) // "Use" diff themes void ( - normalizedTheme.diffGutters.actual, - normalizedTheme.diffGutters.expected, - normalizedTheme.diffGutters.padding, - normalizedTheme.string.diff.insert.open, - normalizedTheme.string.diff.insert.close, - normalizedTheme.string.diff.delete.open, - normalizedTheme.string.diff.delete.close, - normalizedTheme.string.diff.equal.open, - normalizedTheme.string.diff.equal.close, - normalizedTheme.string.diff.insertLine.open, - normalizedTheme.string.diff.insertLine.close, - normalizedTheme.string.diff.deleteLine.open, - normalizedTheme.string.diff.deleteLine.close, - // Tested separately - normalizedTheme.maxDepth + normalizedTheme.diffGutters.actual, + normalizedTheme.diffGutters.expected, + normalizedTheme.diffGutters.padding, + normalizedTheme.string.diff.insert.open, + normalizedTheme.string.diff.insert.close, + normalizedTheme.string.diff.delete.open, + normalizedTheme.string.diff.delete.close, + normalizedTheme.string.diff.equal.open, + normalizedTheme.string.diff.equal.close, + normalizedTheme.string.diff.insertLine.open, + normalizedTheme.string.diff.insertLine.close, + normalizedTheme.string.diff.deleteLine.open, + normalizedTheme.string.diff.deleteLine.close, + // Tested separately + normalizedTheme.maxDepth ) if (typeof BigInt === 'undefined') { - void ( - normalizedTheme.bigInt.open, - normalizedTheme.bigInt.close - ) + void ( + normalizedTheme.bigInt.open, + normalizedTheme.bigInt.close + ) } { - const formatsPrimitive = (t, value) => t.snapshot(format(value)) - formatsPrimitive.title = (valueRepresentation, value) => { - const str = Object.is(value, -0) - ? '-0' - : String(value).replace(/\r/g, '\\r').replace(/\n/g, '\\n') - return `formats primitive: ${valueRepresentation || str}` - } - for (const value of [ - null, - undefined, - false, - true, - '', - 'foo', - '\\ -- \' -- "', - 'foo\nbar\\baz\'"', - 'qux\r\nquux', - 'qux\rquux', - 42, - -42, - -0, - +0, - Infinity, - -Infinity, - NaN, - Symbol(), // eslint-disable-line symbol-description - Symbol('foo'), - Symbol('foo\nbar'), - Symbol.for('bar'), - Symbol.for('bar\nbaz'), - Symbol.iterator, - ]) { - test(formatsPrimitive, value) - } - - if (typeof BigInt === 'function') { - test('42n', formatsPrimitive, BigInt(42)) // eslint-disable-line no-undef - test('-42n', formatsPrimitive, BigInt(-42)) // eslint-disable-line no-undef - } + const formatsPrimitive = (t, value) => t.snapshot(format(value)) + formatsPrimitive.title = (valueRepresentation, value) => { + const str = Object.is(value, -0) + ? '-0' + : String(value).replace(/\r/g, '\\r').replace(/\n/g, '\\n') + return `formats primitive: ${valueRepresentation || str}` + } + for (const value of [ + null, + undefined, + false, + true, + '', + 'foo', + '\\ -- \' -- "', + 'foo\nbar\\baz\'"', + 'qux\r\nquux', + 'qux\rquux', + 42, + -42, + -0, + +0, + Infinity, + -Infinity, + NaN, + Symbol(), // eslint-disable-line symbol-description + Symbol('foo'), + Symbol('foo\nbar'), + Symbol.for('bar'), + Symbol.for('bar\nbaz'), + Symbol.iterator, + ]) { + test(formatsPrimitive, value) + } + + if (typeof BigInt === 'function') { + test('42n', formatsPrimitive, BigInt(42)) // eslint-disable-line no-undef + test('-42n', formatsPrimitive, BigInt(-42)) // eslint-disable-line no-undef + } } { - const escapesQuote = (t, escapeQuote) => { - const testTheme = { - string: { - line: { open: '<', close: '>', escapeQuote }, - multiline: { start: '<', end: '>', escapeQuote }, - }, - } - t.snapshot(_format(escapeQuote, { theme: testTheme })) - t.snapshot(_format(escapeQuote + '\n', { theme: testTheme })) - } - escapesQuote.title = (_, quote) => `escapes ${quote} according to theme` - test(escapesQuote, "'") - test(escapesQuote, '"') - test(escapesQuote, '`') + const escapesQuote = (t, escapeQuote) => { + const testTheme = { + string: { + line: { open: '<', close: '>', escapeQuote }, + multiline: { start: '<', end: '>', escapeQuote }, + }, + } + t.snapshot(_format(escapeQuote, { theme: testTheme })) + t.snapshot(_format(escapeQuote + '\n', { theme: testTheme })) + } + escapesQuote.title = (_, quote) => `escapes ${quote} according to theme` + test(escapesQuote, "'") + test(escapesQuote, '"') + test(escapesQuote, '`') } test('escapes singlequotes in one-line strings with the default theme', t => { - t.snapshot(_format("'"), 'should be escaped') - t.snapshot(_format("'\n"), 'should not be escaped') + t.snapshot(_format("'"), 'should be escaped') + t.snapshot(_format("'\n"), 'should not be escaped') }) // Regression test for #36 test('escapes backticks in multi-line strings with the default theme', t => { - t.snapshot(_format('`'), 'should not be escaped') - t.snapshot(_format('`\n'), 'should be escaped') + t.snapshot(_format('`'), 'should not be escaped') + t.snapshot(_format('`\n'), 'should be escaped') }) test('formats a simple object', t => { - const obj = { foo: 'bar', baz: 'qux' } - const actual = format(obj) - t.snapshot(actual) + const obj = { foo: 'bar', baz: 'qux' } + const actual = format(obj) + t.snapshot(actual) }) test('formats a simple, nested object', t => { - const obj = { foo: { baz: 'qux' } } - const actual = format(obj) - t.snapshot(actual) + const obj = { foo: { baz: 'qux' } } + const actual = format(obj) + t.snapshot(actual) }) test('formats multiline strings inside an object', t => { - const actual = format({ 'foo\nbar': 'baz\nqux' }) - t.snapshot(actual) + const actual = format({ 'foo\nbar': 'baz\nqux' }) + t.snapshot(actual) }) test('formats symbol keys', t => { - t.snapshot(format({ [Symbol('')]: 'bar' })) + t.snapshot(format({ [Symbol('')]: 'bar' })) }) test('formats registered symbols differently from normal symbols with same description', t => { - t.true(format(Symbol('foo')) !== format(Symbol.for('foo'))) + t.true(format(Symbol('foo')) !== format(Symbol.for('foo'))) }) { - const formatsBoxedPrimitive = (t, value) => t.snapshot(format(new Object(value))) - formatsBoxedPrimitive.title = (valueRepresentation, value) => { - return `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}` - } - for (const value of [ - false, - true, - 42, - -42, - -0, - +0, - Infinity, - -Infinity, - NaN, - 'foo', - ]) { - test(formatsBoxedPrimitive, value) - } - - if (typeof BigInt === 'function') { - test('42n', formatsBoxedPrimitive, BigInt(42)) // eslint-disable-line no-undef - test('-42n', formatsBoxedPrimitive, BigInt(-42)) // eslint-disable-line no-undef - } + const formatsBoxedPrimitive = (t, value) => t.snapshot(format(new Object(value))) + formatsBoxedPrimitive.title = (valueRepresentation, value) => { + return `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}` + } + for (const value of [ + false, + true, + 42, + -42, + -0, + +0, + Infinity, + -Infinity, + NaN, + 'foo', + ]) { + test(formatsBoxedPrimitive, value) + } + + if (typeof BigInt === 'function') { + test('42n', formatsBoxedPrimitive, BigInt(42)) // eslint-disable-line no-undef + test('-42n', formatsBoxedPrimitive, BigInt(-42)) // eslint-disable-line no-undef + } } test('formats boxed primitives with extra properties', t => { - t.snapshot(format(Object.assign(new Object('foo'), { bar: 'baz' }))) + t.snapshot(format(Object.assign(new Object('foo'), { bar: 'baz' }))) }) test('formats a simple array', t => { - const arr = ['foo', 'bar'] - const actual = format(arr) - t.snapshot(actual) + const arr = ['foo', 'bar'] + const actual = format(arr) + t.snapshot(actual) }) test('formats a simple, nested array', t => { - const arr = [['foo', 'bar']] - const actual = format(arr) - t.snapshot(actual) + const arr = [['foo', 'bar']] + const actual = format(arr) + t.snapshot(actual) }) test('formats an array with additional properties', t => { - const arr1 = ['foo', 'bar'] - arr1.baz = 'qux' - t.snapshot(format(arr1)) + const arr1 = ['foo', 'bar'] + arr1.baz = 'qux' + t.snapshot(format(arr1)) - const arr2 = [1, 2, 3] - arr2[-1] = -1 - t.snapshot(format(arr2)) + const arr2 = [1, 2, 3] + arr2[-1] = -1 + t.snapshot(format(arr2)) }) test('formats a multiline string inside an array', t => { - const actual = format(['bar\nbaz']) - t.snapshot(actual) + const actual = format(['bar\nbaz']) + t.snapshot(actual) }) test('formats maps', t => { - const map = new Map() - map.set('foo', 'bar') - map.set({ baz: 'qux' }, 'quux') - map.set('corge', { grault: 'garply' }) - const actual = format(map) - t.snapshot(actual) + const map = new Map() + map.set('foo', 'bar') + map.set({ baz: 'qux' }, 'quux') + map.set('corge', { grault: 'garply' }) + const actual = format(map) + t.snapshot(actual) }) test('formats multiline strings inside a map', t => { - const actual = format(new Map([['foo\nbar', 'baz\nqux']])) - t.snapshot(actual) + const actual = format(new Map([['foo\nbar', 'baz\nqux']])) + t.snapshot(actual) }) test('formats maps with additional properties', t => { - const map = new Map() - map.set('foo', 'bar') - map.baz = 'qux' - const actual = format(map) - t.snapshot(actual) + const map = new Map() + map.set('foo', 'bar') + map.baz = 'qux' + const actual = format(map) + t.snapshot(actual) }) test('formats sets', t => { - const set = new Set() - set.add('foo') - set.add({ bar: 'baz' }) - const actual = format(set) - t.snapshot(actual) + const set = new Set() + set.add('foo') + set.add({ bar: 'baz' }) + const actual = format(set) + t.snapshot(actual) }) test('formats a multiline string inside sets', t => { - const actual = format(new Set(['bar\nbaz'])) - t.snapshot(actual) + const actual = format(new Set(['bar\nbaz'])) + t.snapshot(actual) }) test('formats sets with additional properties', t => { - const set = new Set() - set.add('foo') - set.bar = 'baz' - const actual = format(set) - t.snapshot(actual) + const set = new Set() + set.add('foo') + set.bar = 'baz' + const actual = format(set) + t.snapshot(actual) }) test('formats funky objects that are lists and have an iterator', t => { - const funky = { - 0: 'first', - 1: 'second', - foo: 'bar', - } - Object.defineProperty(funky, 'length', { value: 2 }) - Object.defineProperty(funky, Symbol.iterator, { * value () { yield 'baz' } }) + const funky = { + 0: 'first', + 1: 'second', + foo: 'bar', + } + Object.defineProperty(funky, 'length', { value: 2 }) + Object.defineProperty(funky, Symbol.iterator, { * value () { yield 'baz' } }) - const actual = format(funky) - t.snapshot(actual) + const actual = format(funky) + t.snapshot(actual) }) test('formats regular expressions', t => { - const actual = format(/foo/gim) - t.snapshot(actual) + const actual = format(/foo/gim) + t.snapshot(actual) }) test('formats regular expressions with additional properties', t => { - const actual = format(Object.assign(/foo/gim, { bar: 'baz' })) - t.snapshot(actual) + const actual = format(Object.assign(/foo/gim, { bar: 'baz' })) + t.snapshot(actual) }) test('formats anonymous functions', t => { - const actual = format(() => {}) - t.snapshot(actual) + const actual = format(() => {}) + t.snapshot(actual) }) test('formats named functions', t => { - const actual = format(function foo () {}) - t.snapshot(actual) + const actual = format(function foo () {}) + t.snapshot(actual) }) test('formats functions with additional properties', t => { - const actual = format(Object.assign(function foo () {}, { bar: 'baz' })) - t.snapshot(actual) + const actual = format(Object.assign(function foo () {}, { bar: 'baz' })) + t.snapshot(actual) }) test('formats anonymous generator functions', t => { - const actual = format(function * () {}) - // eslint-disable-next-line max-len - t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %object.openBracket#{%%object.closeBracket#}%') + const actual = format(function * () {}) + // eslint-disable-next-line max-len + t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %object.openBracket#{%%object.closeBracket#}%') }) test('formats named generator functions', t => { - const actual = format(function * foo () {}) - // eslint-disable-next-line max-len - t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{%%object.closeBracket#}%') + const actual = format(function * foo () {}) + // eslint-disable-next-line max-len + t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{%%object.closeBracket#}%') }) test('formats generator functions with additional properties', t => { - const actual = format(Object.assign(function * foo () {}, { bar: 'baz' })) - // eslint-disable-next-line max-len - t.is(actual, `%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{% + const actual = format(Object.assign(function * foo () {}, { bar: 'baz' })) + // eslint-disable-next-line max-len + t.is(actual, `%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{% bar%property.separator#: %%string.line.open#'%%string.open%baz%string.close%%string.line.close#'%%property.after#,% %object.closeBracket#}%`) }) test('formats arguments', t => { - (function (a, b, c) { - const actual = format(arguments) - t.snapshot(actual) - })('foo', 'bar', 'baz') + (function (a, b, c) { + const actual = format(arguments) + t.snapshot(actual) + })('foo', 'bar', 'baz') }) test('formats simple errors', t => { - const actual = format(new TypeError('Test message')) - t.snapshot(actual) + const actual = format(new TypeError('Test message')) + t.snapshot(actual) }) test('formats simple errors with a modified name', t => { - const err = new TypeError('Test message') - err.name = 'FooError' - const actual = format(err) - t.snapshot(actual) + const err = new TypeError('Test message') + err.name = 'FooError' + const actual = format(err) + t.snapshot(actual) }) test('formats errors with a name that does not include Error and does not match the constructor', t => { - class Foo extends Error { // eslint-disable-line unicorn/custom-error-definition - constructor (message) { - super(message) - this.name = 'Bar' // eslint-disable-line unicorn/custom-error-definition - } - } - const actual = format(new Foo('Test message')) - t.snapshot(actual) + class Foo extends Error { // eslint-disable-line unicorn/custom-error-definition + constructor (message) { + super(message) + this.name = 'Bar' // eslint-disable-line unicorn/custom-error-definition + } + } + const actual = format(new Foo('Test message')) + t.snapshot(actual) }) test('formats errors with additional properties', t => { - const actual = format(Object.assign(new TypeError('Test message'), { foo: 'bar' })) - t.snapshot(actual) + const actual = format(Object.assign(new TypeError('Test message'), { foo: 'bar' })) + t.snapshot(actual) }) test('formats promises', t => { - const actual = format(Promise.resolve()) - t.snapshot(actual) + const actual = format(Promise.resolve()) + t.snapshot(actual) }) test('formats promises with additional properties', t => { - const actual = format(Object.assign(Promise.resolve(), { foo: 'bar' })) - t.snapshot(actual) + const actual = format(Object.assign(Promise.resolve(), { foo: 'bar' })) + t.snapshot(actual) }) test('formats pointers', t => { - const obj = { foo: 'bar' } - const actual = format({ baz: obj, qux: { quux: obj } }) - t.snapshot(actual) + const obj = { foo: 'bar' } + const actual = format({ baz: obj, qux: { quux: obj } }) + t.snapshot(actual) }) test('formats circular references', t => { - const obj = {} - obj.circular = obj - const actual = format(obj) - t.snapshot(actual) + const obj = {} + obj.circular = obj + const actual = format(obj) + t.snapshot(actual) }) { - const plain = (t, value, tag) => { - const actual = format(value) - t.snapshot(actual) - } - plain.title = (_, __, tag) => `formats ${tag}` - - const withProperties = (t, value, tag) => { - const actual = format(Object.assign(value, { foo: 'bar' })) - t.snapshot(actual) - } - withProperties.title = (_, __, tag) => `formats ${tag} with additional properties` - - const buffer = Buffer.from('decafbad'.repeat(12), 'hex') - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) - - for (const [tag, value, valueForProps] of [ - ['ArrayBuffer', arrayBuffer], - ['Buffer @Uint8Array', buffer], - ['DataView', new DataView(arrayBuffer), new DataView(arrayBuffer)], - ['Float32Array', new Float32Array(arrayBuffer)], - ['Float64Array', new Float64Array(arrayBuffer)], - ['Int16Array', new Int16Array(arrayBuffer)], - ['Int32Array', new Int32Array(arrayBuffer)], - ['Int8Array', new Int8Array(arrayBuffer)], - ['Uint16Array', new Uint16Array(arrayBuffer)], - ['Uint32Array', new Uint32Array(arrayBuffer)], - ['Uint8Array', new Uint8Array(arrayBuffer)], - ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], - ]) { - test(plain, value, tag) - test(withProperties, valueForProps || value.slice(), tag) - } + const plain = (t, value, tag) => { + const actual = format(value) + t.snapshot(actual) + } + plain.title = (_, __, tag) => `formats ${tag}` + + const withProperties = (t, value, tag) => { + const actual = format(Object.assign(value, { foo: 'bar' })) + t.snapshot(actual) + } + withProperties.title = (_, __, tag) => `formats ${tag} with additional properties` + + const buffer = Buffer.from('decafbad'.repeat(12), 'hex') + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) + + for (const [tag, value, valueForProps] of [ + ['ArrayBuffer', arrayBuffer], + ['Buffer @Uint8Array', buffer], + ['DataView', new DataView(arrayBuffer), new DataView(arrayBuffer)], + ['Float32Array', new Float32Array(arrayBuffer)], + ['Float64Array', new Float64Array(arrayBuffer)], + ['Int16Array', new Int16Array(arrayBuffer)], + ['Int32Array', new Int32Array(arrayBuffer)], + ['Int8Array', new Int8Array(arrayBuffer)], + ['Uint16Array', new Uint16Array(arrayBuffer)], + ['Uint32Array', new Uint32Array(arrayBuffer)], + ['Uint8Array', new Uint8Array(arrayBuffer)], + ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], + ]) { + test(plain, value, tag) + test(withProperties, valueForProps || value.slice(), tag) + } } test('formats dates', t => { - const actual1 = format(new Date('1969-07-20T20:17:40.012Z')) - t.snapshot(actual1) + const actual1 = format(new Date('1969-07-20T20:17:40.012Z')) + t.snapshot(actual1) - const actual2 = format(new Date('🚀🌔🛬')) - t.snapshot(actual2) + const actual2 = format(new Date('🚀🌔🛬')) + t.snapshot(actual2) }) test('formats dates with additional properties', t => { - const actual = format(Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' })) - t.snapshot(actual) + const actual = format(Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' })) + t.snapshot(actual) }) test('shows non-Object tag if constructor name is different', t => { - class Foo {} - const actual1 = format(new Foo()) - t.snapshot(actual1) + class Foo {} + const actual1 = format(new Foo()) + t.snapshot(actual1) - class Bar extends Array {} - const actual2 = format(new Bar()) - t.snapshot(actual2) + class Bar extends Array {} + const actual2 = format(new Bar()) + t.snapshot(actual2) - class Baz extends Date {} - const actual3 = format(new Baz('1969-07-20T20:17:40Z')) - t.snapshot(actual3) + class Baz extends Date {} + const actual3 = format(new Baz('1969-07-20T20:17:40Z')) + t.snapshot(actual3) - class Qux extends RegExp {} - const actual4 = format(new Qux('foo')) - t.snapshot(actual4) + class Qux extends RegExp {} + const actual4 = format(new Qux('foo')) + t.snapshot(actual4) - class Quux extends Int16Array {} - const actual5 = format(new Quux()) - t.snapshot(actual5) + class Quux extends Int16Array {} + const actual5 = format(new Quux()) + t.snapshot(actual5) }) test('shows string tag if object has no constructor', t => { - const obj = {} - Object.defineProperty(obj, 'constructor', {}) - t.snapshot(format(obj)) + const obj = {} + Object.defineProperty(obj, 'constructor', {}) + t.snapshot(format(obj)) }) test('formats global', t => { - t.snapshot(format(global)) + t.snapshot(format(global)) }) test('format with given plugin', t => { - const plugins = [ - { - name: 'CustomError', - apiVersion: 1, - register: props => { - const { describe } = customErrorPlugin.factory(props) - return function (value) { - if (value.name === 'CustomError') { - return describe - } - } - }, - }, - ] - - const actual1 = _format(new customErrorPlugin.CustomError('plugin formatter', 'PLUGIN'), { plugins, theme }) - t.snapshot(actual1) - const actual2 = _format(new Error('error'), { plugins, theme }) - t.snapshot(actual2) + const plugins = [ + { + name: 'CustomError', + apiVersion: 1, + register: props => { + const { describe } = customErrorPlugin.factory(props) + return function (value) { + if (value.name === 'CustomError') { + return describe + } + } + }, + }, + ] + + const actual1 = _format(new customErrorPlugin.CustomError('plugin formatter', 'PLUGIN'), { plugins, theme }) + t.snapshot(actual1) + const actual2 = _format(new Error('error'), { plugins, theme }) + t.snapshot(actual2) }) // See . test('format pointers hidden behind maxDepth', t => { - const value = {} - const descriptor = concordance.describe({ - // `value` is encoded in the serialization of `a.b`. `c` is encoded as a - // pointer to the encoded `value`. - a: { - b: value, - }, - c: value, - }) - const serialized = concordance.serialize(descriptor) - - t.notThrows(() => { - // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the - // `c` pointer cannot be resolved, unless the resolution logic first - // deserializes the descriptor in its entirety. - concordance.formatDescriptor(concordance.deserialize(serialized), { maxDepth: 1 }) - }) + const value = {} + const descriptor = concordance.describe({ + // `value` is encoded in the serialization of `a.b`. `c` is encoded as a + // pointer to the encoded `value`. + a: { + b: value, + }, + c: value, + }) + const serialized = concordance.serialize(descriptor) + + t.notThrows(() => { + // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the + // `c` pointer cannot be resolved, unless the resolution logic first + // deserializes the descriptor in its entirety. + concordance.formatDescriptor(concordance.deserialize(serialized), { maxDepth: 1 }) + }) }) diff --git a/test/lodash-isequal-comparison.js b/test/lodash-isequal-comparison.js index 9b5efe4..e03ade9 100644 --- a/test/lodash-isequal-comparison.js +++ b/test/lodash-isequal-comparison.js @@ -47,581 +47,581 @@ const symbol1 = Symbol ? Symbol('a') : true const symbol2 = Symbol ? Symbol('b') : false test('compare primitives', t => { - const pairs = [ - [1, 1, true], [1, new Object(1), false], [1, '1', false], [1, 2, false], - [-0, -0, true], [0, 0, true], [0, new Object(0), false], [new Object(0), new Object(0), true], [-0, 0, false], [0, '0', false], [0, null, false], // eslint-disable-line max-len - [NaN, NaN, true], [NaN, new Object(NaN), false], [new Object(NaN), new Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], // eslint-disable-line max-len - ['a', 'a', true], ['a', new Object('a'), false], [new Object('a'), new Object('a'), true], ['a', 'b', false], ['a', ['a'], false], // eslint-disable-line max-len - [true, true, true], [true, new Object(true), false], [new Object(true), new Object(true), true], [true, 1, false], [true, 'a', false], // eslint-disable-line max-len - [false, false, true], [false, new Object(false), false], [new Object(false), new Object(false), true], [false, 0, false], [false, '', false], // eslint-disable-line max-len - [symbol1, symbol1, true], [symbol1, new Object(symbol1), false], [new Object(symbol1), new Object(symbol1), true], [symbol1, symbol2, false], // eslint-disable-line max-len - [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], - [undefined, undefined, true], [undefined, null, false], [undefined, '', false], - ] - - for (const [lhs, rhs, result] of pairs) { - t.is(isEqual(lhs, rhs), result) - } + const pairs = [ + [1, 1, true], [1, new Object(1), false], [1, '1', false], [1, 2, false], + [-0, -0, true], [0, 0, true], [0, new Object(0), false], [new Object(0), new Object(0), true], [-0, 0, false], [0, '0', false], [0, null, false], // eslint-disable-line max-len + [NaN, NaN, true], [NaN, new Object(NaN), false], [new Object(NaN), new Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], // eslint-disable-line max-len + ['a', 'a', true], ['a', new Object('a'), false], [new Object('a'), new Object('a'), true], ['a', 'b', false], ['a', ['a'], false], // eslint-disable-line max-len + [true, true, true], [true, new Object(true), false], [new Object(true), new Object(true), true], [true, 1, false], [true, 'a', false], // eslint-disable-line max-len + [false, false, true], [false, new Object(false), false], [new Object(false), new Object(false), true], [false, 0, false], [false, '', false], // eslint-disable-line max-len + [symbol1, symbol1, true], [symbol1, new Object(symbol1), false], [new Object(symbol1), new Object(symbol1), true], [symbol1, symbol2, false], // eslint-disable-line max-len + [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], + [undefined, undefined, true], [undefined, null, false], [undefined, '', false], + ] + + for (const [lhs, rhs, result] of pairs) { + t.is(isEqual(lhs, rhs), result) + } }) test('compare arrays', t => { - let array1 = [true, null, 1, 'a', undefined] - let array2 = [true, null, 1, 'a', undefined] + let array1 = [true, null, 1, 'a', undefined] + let array2 = [true, null, 1, 'a', undefined] - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] - array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] + array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] + array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1 = [1] - array1[2] = 3 + array1 = [1] + array1[2] = 3 - array2 = [1] - array2[1] = undefined - array2[2] = 3 + array2 = [1] + array2[1] = undefined + array2[2] = 3 - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1 = [new Object(1), false, new Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [new Object('c')]], { a: 1 }] - array2 = [1, new Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', new Object('b'), ['c']], { a: 1 }] + array1 = [new Object(1), false, new Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [new Object('c')]], { a: 1 }] + array2 = [1, new Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', new Object('b'), ['c']], { a: 1 }] - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) - array1 = [1, 2, 3] - array2 = [3, 2, 1] + array1 = [1, 2, 3] + array2 = [3, 2, 1] - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) - array1 = [1, 2] - array2 = [1, 2, 3] + array1 = [1, 2] + array2 = [1, 2, 3] - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) }) test('treat arrays with identical values but different non-index properties as unequal', t => { - let array1 = [1, 2, 3] - let array2 = [1, 2, 3] + let array1 = [1, 2, 3] + let array2 = [1, 2, 3] - array1.every = array1.filter = array1.forEach = - array1.indexOf = array1.lastIndexOf = array1.map = - array1.some = array1.reduce = array1.reduceRight = null + array1.every = array1.filter = array1.forEach = + array1.indexOf = array1.lastIndexOf = array1.map = + array1.some = array1.reduce = array1.reduceRight = null - array2.concat = array2.join = array2.pop = - array2.reverse = array2.shift = array2.slice = - array2.sort = array2.splice = array2.unshift = null + array2.concat = array2.join = array2.pop = + array2.reverse = array2.shift = array2.slice = + array2.sort = array2.splice = array2.unshift = null - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) - array1 = [1, 2, 3] - array1.a = 1 + array1 = [1, 2, 3] + array1.a = 1 - array2 = [1, 2, 3] - array2.b = 1 + array2 = [1, 2, 3] + array2.b = 1 - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) - array1 = /c/.exec('abcde') - array2 = ['c'] + array1 = /c/.exec('abcde') + array2 = ['c'] - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) }) test('compare sparse arrays', t => { - const array = new Array(1) + const array = new Array(1) - t.true(isEqual(array, new Array(1))) - t.true(isEqual(array, [undefined])) - t.false(isEqual(array, new Array(2))) + t.true(isEqual(array, new Array(1))) + t.true(isEqual(array, [undefined])) + t.false(isEqual(array, new Array(2))) }) test('compare plain objects', t => { - let object1 = { a: true, b: null, c: 1, d: 'a', e: undefined } - let object2 = { a: true, b: null, c: 1, d: 'a', e: undefined } + let object1 = { a: true, b: null, c: 1, d: 'a', e: undefined } + let object2 = { a: true, b: null, c: 1, d: 'a', e: undefined } - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) - object1 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } - object2 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } + object1 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } + object2 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) - object1 = { a: 1, b: 2, c: 3 } - object2 = { a: 3, b: 2, c: 1 } + object1 = { a: 1, b: 2, c: 3 } + object2 = { a: 3, b: 2, c: 1 } - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)) - object1 = { a: 1, b: 2, c: 3 } - object2 = { d: 1, e: 2, f: 3 } + object1 = { a: 1, b: 2, c: 3 } + object2 = { d: 1, e: 2, f: 3 } - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)) - object1 = { a: 1, b: 2 } - object2 = { a: 1, b: 2, c: 3 } + object1 = { a: 1, b: 2 } + object2 = { a: 1, b: 2, c: 3 } - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)) }) test('compare objects regardless of key order', t => { - const object1 = { a: 1, b: 2, c: 3 } - const object2 = { c: 3, a: 1, b: 2 } + const object1 = { a: 1, b: 2, c: 3 } + const object2 = { c: 3, a: 1, b: 2 } - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) }) test('compare nested objects', t => { - const noop = () => {} - - const object1 = { - a: [1, 2, 3], - b: true, - c: 1, - d: 'a', - e: { - f: ['a', 'b', 'c'], - g: false, - h: new Date(2012, 4, 23), - i: noop, - j: 'a', - }, - } - - const object2 = { - a: [1, 2, 3], - b: true, - c: 1, - d: 'a', - e: { - f: ['a', 'b', 'c'], - g: false, - h: new Date(2012, 4, 23), - i: noop, - j: 'a', - }, - } - - t.true(isEqual(object1, object2)) + const noop = () => {} + + const object1 = { + a: [1, 2, 3], + b: true, + c: 1, + d: 'a', + e: { + f: ['a', 'b', 'c'], + g: false, + h: new Date(2012, 4, 23), + i: noop, + j: 'a', + }, + } + + const object2 = { + a: [1, 2, 3], + b: true, + c: 1, + d: 'a', + e: { + f: ['a', 'b', 'c'], + g: false, + h: new Date(2012, 4, 23), + i: noop, + j: 'a', + }, + } + + t.true(isEqual(object1, object2)) }) test('compare object instances', t => { - function Foo () { - this.a = 1 - } - Foo.prototype.a = 1 + function Foo () { + this.a = 1 + } + Foo.prototype.a = 1 - function Bar () { - this.a = 1 - } - Bar.prototype.a = 2 + function Bar () { + this.a = 1 + } + Bar.prototype.a = 2 - t.true(isEqual(new Foo(), new Foo())) - t.false(isEqual(new Foo(), new Bar())) - t.false(isEqual({ a: 1 }, new Foo())) - t.false(isEqual({ a: 2 }, new Bar())) + t.true(isEqual(new Foo(), new Foo())) + t.false(isEqual(new Foo(), new Bar())) + t.false(isEqual({ a: 1 }, new Foo())) + t.false(isEqual({ a: 2 }, new Bar())) }) test('compare objects with constructor properties', t => { - t.true(isEqual({ constructor: 1 }, { constructor: 1 })) - t.false(isEqual({ constructor: 1 }, { constructor: '1' })) - t.true(isEqual({ constructor: [1] }, { constructor: [1] })) - t.false(isEqual({ constructor: [1] }, { constructor: ['1'] })) - t.false(isEqual({ constructor: Object }, {})) + t.true(isEqual({ constructor: 1 }, { constructor: 1 })) + t.false(isEqual({ constructor: 1 }, { constructor: '1' })) + t.true(isEqual({ constructor: [1] }, { constructor: [1] })) + t.false(isEqual({ constructor: [1] }, { constructor: ['1'] })) + t.false(isEqual({ constructor: Object }, {})) }) test('compare arrays with circular references', t => { - let array1 = [] - let array2 = [] + let array1 = [] + let array2 = [] - array1.push(array1) - array2.push(array2) + array1.push(array1) + array2.push(array2) - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1.push('b') - array2.push('b') + array1.push('b') + array2.push('b') - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1.push('c') - array2.push('d') + array1.push('c') + array2.push('d') - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) - array1 = ['a', 'b', 'c'] - array1[1] = array1 - array2 = ['a', ['a', 'b', 'c'], 'c'] + array1 = ['a', 'b', 'c'] + array1[1] = array1 + array2 = ['a', ['a', 'b', 'c'], 'c'] - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) }) test('have transitive equivalence for circular references of arrays', t => { - const array1 = [] - const array2 = [array1] - const array3 = [array2] + const array1 = [] + const array2 = [array1] + const array3 = [array2] - array1[0] = array1 + array1[0] = array1 - t.true(isEqual(array1, array2)) - t.true(isEqual(array2, array3)) - // Concordance detects a different circular reference in array1 before it does - // in array3, making them unequal. - t.false(isEqual(array1, array3)) + t.true(isEqual(array1, array2)) + t.true(isEqual(array2, array3)) + // Concordance detects a different circular reference in array1 before it does + // in array3, making them unequal. + t.false(isEqual(array1, array3)) }) test('compare objects with circular references', t => { - let object1 = {} - let object2 = {} + let object1 = {} + let object2 = {} - object1.a = object1 - object2.a = object2 + object1.a = object1 + object2.a = object2 - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) - object1.b = 0 - object2.b = 0 + object1.b = 0 + object2.b = 0 - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) - object1.c = new Object(1) - object2.c = new Object(2) + object1.c = new Object(1) + object2.c = new Object(2) - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)) - object1 = { a: 1, b: 2, c: 3 } - object1.b = object1 - object2 = { a: 1, b: { a: 1, b: 2, c: 3 }, c: 3 } + object1 = { a: 1, b: 2, c: 3 } + object1.b = object1 + object2 = { a: 1, b: { a: 1, b: 2, c: 3 }, c: 3 } - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)) }) test('have transitive equivalence for circular references of objects', t => { - const object1 = {} - const object2 = { a: object1 } - const object3 = { a: object2 } + const object1 = {} + const object2 = { a: object1 } + const object3 = { a: object2 } - object1.a = object1 + object1.a = object1 - t.true(isEqual(object1, object2)) - t.true(isEqual(object2, object3)) - // Concordance detects a different circular reference in object1 before it - // does in object3, making them unequal. - t.false(isEqual(object1, object3)) + t.true(isEqual(object1, object2)) + t.true(isEqual(object2, object3)) + // Concordance detects a different circular reference in object1 before it + // does in object3, making them unequal. + t.false(isEqual(object1, object3)) }) test('compare objects with multiple circular references', t => { - const array1 = [{}] - const array2 = [{}]; + const array1 = [{}] + const array2 = [{}]; - (array1[0].a = array1).push(array1); - (array2[0].a = array2).push(array2) + (array1[0].a = array1).push(array1); + (array2[0].a = array2).push(array2) - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1[0].b = 0 - array2[0].b = 0 + array1[0].b = 0 + array2[0].b = 0 - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)) - array1[0].c = new Object(1) - array2[0].c = new Object(2) + array1[0].c = new Object(1) + array2[0].c = new Object(2) - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)) }) test('compare objects with complex circular references', t => { - const object1 = { - foo: { b: { c: { d: {} } } }, - bar: { a: 2 }, - } + const object1 = { + foo: { b: { c: { d: {} } } }, + bar: { a: 2 }, + } - const object2 = { - foo: { b: { c: { d: {} } } }, - bar: { a: 2 }, - } + const object2 = { + foo: { b: { c: { d: {} } } }, + bar: { a: 2 }, + } - object1.foo.b.c.d = object1 - object1.bar.b = object1.foo.b + object1.foo.b.c.d = object1 + object1.bar.b = object1.foo.b - object2.foo.b.c.d = object2 - object2.bar.b = object2.foo.b + object2.foo.b.c.d = object2 + object2.bar.b = object2.foo.b - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) }) test('compare objects with shared property values', t => { - const object1 = { - a: [1, 2], - } + const object1 = { + a: [1, 2], + } - const object2 = { - a: [1, 2], - b: [1, 2], - } + const object2 = { + a: [1, 2], + b: [1, 2], + } - object1.b = object1.a + object1.b = object1.a - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) }) test('treat objects created by `Object.create(null)` like plain objects', t => { - function Foo () { - this.a = 1 - } - Foo.prototype.constructor = null + function Foo () { + this.a = 1 + } + Foo.prototype.constructor = null - const object1 = Object.create(null) - object1.a = 1 + const object1 = Object.create(null) + object1.a = 1 - const object2 = { a: 1 } + const object2 = { a: 1 } - t.true(isEqual(object1, object2)) - t.false(isEqual(new Foo(), object2)) + t.true(isEqual(object1, object2)) + t.false(isEqual(new Foo(), object2)) }) test('avoid common type coercions', t => { - t.false(isEqual(true, new Object(false))) - t.false(isEqual(new Object(false), new Object(0))) - t.false(isEqual(false, new Object(''))) - t.false(isEqual(new Object(36), new Object('36'))) - t.false(isEqual(0, '')) - t.false(isEqual(1, true)) - t.false(isEqual(1337756400000, new Date(2012, 4, 23))) - t.false(isEqual('36', 36)) - t.false(isEqual(36, '36')) + t.false(isEqual(true, new Object(false))) + t.false(isEqual(new Object(false), new Object(0))) + t.false(isEqual(false, new Object(''))) + t.false(isEqual(new Object(36), new Object('36'))) + t.false(isEqual(0, '')) + t.false(isEqual(1, true)) + t.false(isEqual(1337756400000, new Date(2012, 4, 23))) + t.false(isEqual('36', 36)) + t.false(isEqual(36, '36')) }) test('compare `arguments` objects', t => { - const args1 = (function () { return arguments }()) - const args2 = (function () { return arguments }()) - const args3 = (function () { return arguments }(1, 2)) + const args1 = (function () { return arguments }()) + const args2 = (function () { return arguments }()) + const args3 = (function () { return arguments }(1, 2)) - t.true(isEqual(args1, args2)) - t.false(isEqual(args1, args3)) + t.true(isEqual(args1, args2)) + t.false(isEqual(args1, args3)) }) test('actual `arguments` objects may be compared to expected arrays', t => { - const array = [1, 2, 3] + const array = [1, 2, 3] - const args = (function () { return arguments })(1, 2, 3) - t.true(isEqual(args, array)) - t.false(isEqual(array, args)) + const args = (function () { return arguments })(1, 2, 3) + t.true(isEqual(args, array)) + t.false(isEqual(array, args)) }) test('compare array buffers', t => { - const buffer = new Int8Array([-1]).buffer + const buffer = new Int8Array([-1]).buffer - t.true(isEqual(buffer, new Uint8Array([255]).buffer)) - t.false(isEqual(buffer, new ArrayBuffer(1))) + t.true(isEqual(buffer, new Uint8Array([255]).buffer)) + t.false(isEqual(buffer, new ArrayBuffer(1))) }) test('compare array views', t => { - const arrayViews = [ - 'Float32Array', - 'Float64Array', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Uint16Array', - 'Uint32Array', - 'DataView', - ] - - const namespaces = [global, realm] - for (const ns of namespaces) { - arrayViews.forEach((type, viewIndex) => { - const otherType = arrayViews[(viewIndex + 1) % arrayViews.length] - const CtorA = ns[type] - const CtorB = ns[otherType] - const bufferA = new ns.ArrayBuffer(8) - const bufferB = new ns.ArrayBuffer(8) - const bufferC = new ns.ArrayBuffer(16) - - t.true(isEqual(new CtorA(bufferA), new CtorA(bufferA))) - t.false(isEqual(new CtorA(bufferA), new CtorB(bufferB))) - t.false(isEqual(new CtorB(bufferB), new CtorB(bufferC))) - }) - } + const arrayViews = [ + 'Float32Array', + 'Float64Array', + 'Int8Array', + 'Int16Array', + 'Int32Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Uint16Array', + 'Uint32Array', + 'DataView', + ] + + const namespaces = [global, realm] + for (const ns of namespaces) { + arrayViews.forEach((type, viewIndex) => { + const otherType = arrayViews[(viewIndex + 1) % arrayViews.length] + const CtorA = ns[type] + const CtorB = ns[otherType] + const bufferA = new ns.ArrayBuffer(8) + const bufferB = new ns.ArrayBuffer(8) + const bufferC = new ns.ArrayBuffer(16) + + t.true(isEqual(new CtorA(bufferA), new CtorA(bufferA))) + t.false(isEqual(new CtorA(bufferA), new CtorB(bufferB))) + t.false(isEqual(new CtorB(bufferB), new CtorB(bufferC))) + }) + } }) test('compare buffers', t => { - const buffer = Buffer.from([1]) + const buffer = Buffer.from([1]) - t.true(isEqual(buffer, Buffer.from([1]))) - t.false(isEqual(buffer, Buffer.from([2]))) - t.false(isEqual(buffer, new Uint8Array([1]))) + t.true(isEqual(buffer, Buffer.from([1]))) + t.false(isEqual(buffer, Buffer.from([2]))) + t.false(isEqual(buffer, new Uint8Array([1]))) }) test('compare date objects', t => { - const date = new Date(2012, 4, 23) + const date = new Date(2012, 4, 23) - t.true(isEqual(date, new Date(2012, 4, 23))) - t.true(isEqual(new Date('a'), new Date('b'))) - t.false(isEqual(date, new Date(2013, 3, 25))) - t.false(isEqual(date, { getTime () { return +date } })) + t.true(isEqual(date, new Date(2012, 4, 23))) + t.true(isEqual(new Date('a'), new Date('b'))) + t.false(isEqual(date, new Date(2013, 3, 25))) + t.false(isEqual(date, { getTime () { return +date } })) }) test('compare error objects', t => { - const errorTypes = [ - 'Error', - 'EvalError', - 'RangeError', - 'ReferenceError', - 'SyntaxError', - 'TypeError', - 'URIError', - ] - - errorTypes.forEach((type, index) => { - const otherType = errorTypes[++index % errorTypes.length] - const CtorA = global[type] - const CtorB = global[otherType] - - t.true(isEqual(new CtorA('a'), new CtorA('a'))) - t.false(isEqual(new CtorA('a'), new CtorB('a'))) - t.false(isEqual(new CtorB('a'), new CtorB('b'))) - }) + const errorTypes = [ + 'Error', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + ] + + errorTypes.forEach((type, index) => { + const otherType = errorTypes[++index % errorTypes.length] + const CtorA = global[type] + const CtorB = global[otherType] + + t.true(isEqual(new CtorA('a'), new CtorA('a'))) + t.false(isEqual(new CtorA('a'), new CtorB('a'))) + t.false(isEqual(new CtorB('a'), new CtorB('b'))) + }) }) test('compare functions', t => { - function a () { return 1 + 2 } - function b () { return 1 + 2 } + function a () { return 1 + 2 } + function b () { return 1 + 2 } - t.true(isEqual(a, a)) - t.false(isEqual(a, b)) + t.true(isEqual(a, a)) + t.false(isEqual(a, b)) }) test('compare maps', t => { - const map1 = new Map() - for (const map2 of [new Map(), new realm.Map()]) { - map1.set('a', 1) - map2.set('b', 2) - t.false(isEqual(map1, map2)) + const map1 = new Map() + for (const map2 of [new Map(), new realm.Map()]) { + map1.set('a', 1) + map2.set('b', 2) + t.false(isEqual(map1, map2)) - map1.set('b', 2) - map2.set('a', 1) - t.false(isEqual(map1, map2)) + map1.set('b', 2) + map2.set('a', 1) + t.false(isEqual(map1, map2)) - map1.delete('a') - map1.set('a', 1) - t.true(isEqual(map1, map2)) + map1.delete('a') + map1.set('a', 1) + t.true(isEqual(map1, map2)) - map2.delete('a') - t.false(isEqual(map1, map2)) + map2.delete('a') + t.false(isEqual(map1, map2)) - map1.clear() - map2.clear() - } + map1.clear() + map2.clear() + } }) test('compare maps with circular references', t => { - const map1 = new Map() - const map2 = new Map() + const map1 = new Map() + const map2 = new Map() - map1.set('a', map1) - map2.set('a', map2) - t.true(isEqual(map1, map2)) + map1.set('a', map1) + map2.set('a', map2) + t.true(isEqual(map1, map2)) - map1.set('b', 1) - map2.set('b', 2) - t.false(isEqual(map1, map2)) + map1.set('b', 1) + map2.set('b', 2) + t.false(isEqual(map1, map2)) }) test('compare promises by reference', t => { - const promise1 = Promise.resolve(1) - for (const promise2 of [Promise.resolve(1), realm.Promise.resolve(1)]) { - t.false(isEqual(promise1, promise2)) - t.true(isEqual(promise1, promise1)) - } + const promise1 = Promise.resolve(1) + for (const promise2 of [Promise.resolve(1), realm.Promise.resolve(1)]) { + t.false(isEqual(promise1, promise2)) + t.true(isEqual(promise1, promise1)) + } }) test('compare regexes', t => { - t.true(isEqual(/x/gim, /x/gim)) - t.true(isEqual(/x/gim, /x/gim)) - t.false(isEqual(/x/gi, /x/g)) - t.false(isEqual(/x/, /y/)) - t.false(isEqual(/x/g, { global: true, ignoreCase: false, multiline: false, source: 'x' })) + t.true(isEqual(/x/gim, /x/gim)) + t.true(isEqual(/x/gim, /x/gim)) + t.false(isEqual(/x/gi, /x/g)) + t.false(isEqual(/x/, /y/)) + t.false(isEqual(/x/g, { global: true, ignoreCase: false, multiline: false, source: 'x' })) }) test('compare sets', t => { - const set1 = new Set() - for (const set2 of [new Set(), new realm.Set()]) { - set1.add(1) - set2.add(2) - t.false(isEqual(set1, set2)) + const set1 = new Set() + for (const set2 of [new Set(), new realm.Set()]) { + set1.add(1) + set2.add(2) + t.false(isEqual(set1, set2)) - set1.add(2) - set2.add(1) - t.false(isEqual(set1, set2)) + set1.add(2) + set2.add(1) + t.false(isEqual(set1, set2)) - set1.delete(1) - set1.add(1) - t.true(isEqual(set1, set2)) + set1.delete(1) + set1.add(1) + t.true(isEqual(set1, set2)) - set2.delete(1) - t.false(isEqual(set1, set2)) + set2.delete(1) + t.false(isEqual(set1, set2)) - set1.clear() - set2.clear() - } + set1.clear() + set2.clear() + } }) test('compare sets with circular references', t => { - const set1 = new Set() - const set2 = new Set() + const set1 = new Set() + const set2 = new Set() - set1.add(set1) - set2.add(set2) - t.true(isEqual(set1, set2)) + set1.add(set1) + set2.add(set2) + t.true(isEqual(set1, set2)) - set1.add(1) - set2.add(2) - t.false(isEqual(set1, set2)) + set1.add(1) + set2.add(2) + t.false(isEqual(set1, set2)) }) test('compare symbol properties', t => { - const object1 = { a: 1 } - const object2 = { a: 1 } + const object1 = { a: 1 } + const object2 = { a: 1 } - object1[symbol1] = { a: { b: 2 } } - object2[symbol1] = { a: { b: 2 } } + object1[symbol1] = { a: { b: 2 } } + object2[symbol1] = { a: { b: 2 } } - Object.defineProperty(object2, symbol2, { - configurable: true, - enumerable: false, - writable: true, - value: 2, - }) + Object.defineProperty(object2, symbol2, { + configurable: true, + enumerable: false, + writable: true, + value: 2, + }) - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)) - object2[symbol1] = { a: 1 } - t.false(isEqual(object1, object2)) + object2[symbol1] = { a: 1 } + t.false(isEqual(object1, object2)) - delete object2[symbol1] - object2[Symbol('a')] = { a: { b: 2 } } - t.false(isEqual(object1, object2)) + delete object2[symbol1] + object2[Symbol('a')] = { a: { b: 2 } } + t.false(isEqual(object1, object2)) }) test('return `true` for like-objects from different realms', t => { - const array = new realm.Array() - array.push(1) - t.true(isEqual([1], array)) - t.false(isEqual([2], array)) + const array = new realm.Array() + array.push(1) + t.true(isEqual([1], array)) + t.false(isEqual([2], array)) - const object = new realm.Object() - object.a = 1 - t.true(isEqual({ a: 1 }, object)) - t.false(isEqual({ a: 2 }, object)) + const object = new realm.Object() + object.a = 1 + t.true(isEqual({ a: 1 }, object)) + t.false(isEqual({ a: 2 }, object)) }) test('return `false` for objects with custom `toString` methods', t => { - let primitive - const object = { 'toString' () { return primitive } } - for (const value of [true, null, 1, 'a', undefined]) { - primitive = value - t.false(isEqual(object, value)) - } + let primitive + const object = { 'toString' () { return primitive } } + for (const value of [true, null, 1, 'a', undefined]) { + primitive = value + t.false(isEqual(object, value)) + } }) diff --git a/test/max-depth.js b/test/max-depth.js index fa0f657..2258765 100644 --- a/test/max-depth.js +++ b/test/max-depth.js @@ -2,54 +2,54 @@ import test from 'ava' import { format, diff } from '../index.js' const deep = { - one: { - two: { - three: { - four: { - five: 'fin', - }, - }, - arr: [], - arr2: [[]], - date: new Date('1969-07-20T20:17:40Z'), - date2: Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' }), - error: new Error(), - fn () {}, - fn2: Object.assign(() => {}, { foo: 'bar' }), - map: new Map(), - map2: new Map([['foo', 'bar']]), - obj: {}, - regexp: /foo/, - regexp2: Object.assign(/foo/, { foo: 'bar' }), - set: new Set(), - set2: new Set(['foo']), - }, - arr: [{ three: { four: {} } }], - map: new Map([[{ three: { four: {} } }, { three: { four: {} } }]]), - set: new Set([{ three: { four: {} } }]), - }, + one: { + two: { + three: { + four: { + five: 'fin', + }, + }, + arr: [], + arr2: [[]], + date: new Date('1969-07-20T20:17:40Z'), + date2: Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' }), + error: new Error(), + fn () {}, + fn2: Object.assign(() => {}, { foo: 'bar' }), + map: new Map(), + map2: new Map([['foo', 'bar']]), + obj: {}, + regexp: /foo/, + regexp2: Object.assign(/foo/, { foo: 'bar' }), + set: new Set(), + set2: new Set(['foo']), + }, + arr: [{ three: { four: {} } }], + map: new Map([[{ three: { four: {} } }, { three: { four: {} } }]]), + set: new Set([{ three: { four: {} } }]), + }, } test('format() respects maxDepth option', t => { - t.snapshot(format(deep, { maxDepth: 3 })) + t.snapshot(format(deep, { maxDepth: 3 })) }) test('diff() respects maxDepth option for equal parts', t => { - t.snapshot(diff(Object.assign({ unequal: 1 }, deep), Object.assign({ unequal: 2 }, deep), { maxDepth: 3 })) - t.snapshot(diff({ one: { two: { three: 'baz', three2: ['quux'] } } }, { one: { two: { three: 'qux', three2: ['quux'] } } }, { maxDepth: 1 })) // eslint-disable-line max-len + t.snapshot(diff(Object.assign({ unequal: 1 }, deep), Object.assign({ unequal: 2 }, deep), { maxDepth: 3 })) + t.snapshot(diff({ one: { two: { three: 'baz', three2: ['quux'] } } }, { one: { two: { three: 'qux', three2: ['quux'] } } }, { maxDepth: 1 })) // eslint-disable-line max-len }) test('properties with increased indentation respect the maxDepth when formatted', t => { - t.snapshot(format({ - foo: { - bar: {}, - }, - }, { - maxDepth: 1, - theme: { - property: { - increaseValueIndent: true, - }, - }, - })) + t.snapshot(format({ + foo: { + bar: {}, + }, + }, { + maxDepth: 1, + theme: { + property: { + increaseValueIndent: true, + }, + }, + })) }) diff --git a/test/odd-properties.js b/test/odd-properties.js index 6018f7b..bab952d 100644 --- a/test/odd-properties.js +++ b/test/odd-properties.js @@ -2,8 +2,8 @@ import test from 'ava' import { compare } from '../index.js' test('ignores undescribed own properties', t => { - const a = new Proxy({ a: 1 }, { - getOwnPropertyDescriptor (target, prop) {}, - }) - t.true(compare(a, {}).pass) + const a = new Proxy({ a: 1 }, { + getOwnPropertyDescriptor (target, prop) {}, + }) + t.true(compare(a, {}).pass) }) diff --git a/test/pluginRegistry.js b/test/pluginRegistry.js index 22655be..9daa098 100644 --- a/test/pluginRegistry.js +++ b/test/pluginRegistry.js @@ -2,60 +2,60 @@ import test from 'ava' import esmock from 'esmock' const pluginRegistry = await esmock('../lib/pluginRegistry', { - import: { JSON: { parse: () => ({ version: '1.0.0' }) } }, + import: { JSON: { parse: () => ({ version: '1.0.0' }) } }, }) test('registration should fail when plugin name invalid', t => { - t.throws(() => pluginRegistry.add({ name: { for: 'complex' } }), { name: 'PluginTypeError' }) + t.throws(() => pluginRegistry.add({ name: { for: 'complex' } }), { name: 'PluginTypeError' }) }) test('registration should fail when api version unsupported', t => { - t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 2 }), { name: 'UnsupportedApiError' }) + t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 2 }), { name: 'UnsupportedApiError' }) }) test('registration should fail when installed concordance version below minimal version required by plugin', t => { - t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 1, minimalConcordanceVersion: '2.0.0' }), - { name: 'UnsupportedError' }) + t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 1, minimalConcordanceVersion: '2.0.0' }), + { name: 'UnsupportedError' }) }) test('registration should fail when descriptor id used twice', t => { - const plugin = { - name: 'complex', - apiVersion: 1, - register: concordance => { - concordance.addDescriptor(1, 'complexCustomValue') - concordance.addDescriptor(1, 'complexCustomValue') - }, - } - t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorIdError' }) + const plugin = { + name: 'complex', + apiVersion: 1, + register: concordance => { + concordance.addDescriptor(1, 'complexCustomValue') + concordance.addDescriptor(1, 'complexCustomValue') + }, + } + t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorIdError' }) }) test('registration should fail when descriptor tag used twice', t => { - const plugin = { - name: 'complex', - apiVersion: 1, - register: concordance => { - concordance.addDescriptor(1, 'complexCustomValue') - concordance.addDescriptor(2, 'complexCustomValue') - }, - } - t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorTagError' }) + const plugin = { + name: 'complex', + apiVersion: 1, + register: concordance => { + concordance.addDescriptor(1, 'complexCustomValue') + concordance.addDescriptor(2, 'complexCustomValue') + }, + } + t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorTagError' }) }) test('registration should be successful', t => { - t.plan(2) - const tryDescribeValue = () => { } // eslint-disable-line unicorn/consistent-function-scoping - const plugin = { - name: 'complex', - apiVersion: 1, - serializerVersion: 1, - register: concordance => { - t.pass() - concordance.addDescriptor(1, 'complexCustomObject', 'objectDeserializer') - concordance.addDescriptor(2, 'complexCustomArray', 'arrayDeserializer') - return tryDescribeValue - }, - } - - t.snapshot(pluginRegistry.add(plugin)) + t.plan(2) + const tryDescribeValue = () => { } // eslint-disable-line unicorn/consistent-function-scoping + const plugin = { + name: 'complex', + apiVersion: 1, + serializerVersion: 1, + register: concordance => { + t.pass() + concordance.addDescriptor(1, 'complexCustomObject', 'objectDeserializer') + concordance.addDescriptor(2, 'complexCustomArray', 'arrayDeserializer') + return tryDescribeValue + }, + } + + t.snapshot(pluginRegistry.add(plugin)) }) diff --git a/test/serialization-fixtures.js b/test/serialization-fixtures.js index 5791839..7fbc5c8 100644 --- a/test/serialization-fixtures.js +++ b/test/serialization-fixtures.js @@ -4,5 +4,5 @@ import { compareDescriptors, deserialize, describe } from '../index.js' import { serialization, tree } from './fixtures/pointerSerialization.js' test('pointer serialization equals the same tree', t => { - t.true(compareDescriptors(deserialize(serialization), describe(tree))) + t.true(compareDescriptors(deserialize(serialization), describe(tree))) }) diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index 44a53dc..fdfc410 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -5,52 +5,52 @@ import { deserialize, serialize } from '../lib/serialize.js' import * as customErrorPlugin from './fixtures/customErrorPlugin.js' test('serializes a descriptor into a buffer', t => { - const result = serialize(describe({ foo: 'bar' })) - t.true(Buffer.isBuffer(result)) + const result = serialize(describe({ foo: 'bar' })) + t.true(Buffer.isBuffer(result)) }) const plugins = [ - { - name: 'CustomError', - apiVersion: 1, - serializerVersion: 1, - register: props => { - const custom = customErrorPlugin.factory(props) - props.addDescriptor(1, custom.tag, custom.deserialize) - return function (value) { - if (value.name === 'CustomError') { - return custom.describe - } - } - }, - }, + { + name: 'CustomError', + apiVersion: 1, + serializerVersion: 1, + register: props => { + const custom = customErrorPlugin.factory(props) + props.addDescriptor(1, custom.tag, custom.deserialize) + return function (value) { + if (value.name === 'CustomError') { + return custom.describe + } + } + }, + }, ] const useDeserialized = (t, value, options) => { - const original = describe(value, options) - - const buffer = serialize(original) - const deserialized = deserialize(buffer, options) - t.true( - compareDescriptors(deserialized, original), - 'the deserialized descriptor equals the original') - t.is( - formatDescriptor(deserialized), - formatDescriptor(original), - 'the deserialized descriptor is formatted like the original') - - const redeserialized = deserialize(serialize(deserialized), options) - t.true( - compareDescriptors(redeserialized, original), - 'after serializing and deserializing it again, the deserialized descriptor equals the original') - t.is( - formatDescriptor(redeserialized), - formatDescriptor(original), - 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original') - - t.true( - compareDescriptors(redeserialized, deserialized), - 'deserialized descriptors equal each other') + const original = describe(value, options) + + const buffer = serialize(original) + const deserialized = deserialize(buffer, options) + t.true( + compareDescriptors(deserialized, original), + 'the deserialized descriptor equals the original') + t.is( + formatDescriptor(deserialized), + formatDescriptor(original), + 'the deserialized descriptor is formatted like the original') + + const redeserialized = deserialize(serialize(deserialized), options) + t.true( + compareDescriptors(redeserialized, original), + 'after serializing and deserializing it again, the deserialized descriptor equals the original') + t.is( + formatDescriptor(redeserialized), + formatDescriptor(original), + 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original') + + t.true( + compareDescriptors(redeserialized, deserialized), + 'deserialized descriptors equal each other') } useDeserialized.title = (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original` @@ -88,7 +88,7 @@ test('Symbol(\'foo\')', useDeserialized, Symbol('foo')) test(useDeserialized, undefined) if (typeof BigInt === 'function') { - test('42n', useDeserialized, BigInt(42)) // eslint-disable-line no-undef + test('42n', useDeserialized, BigInt(42)) // eslint-disable-line no-undef } // Objects @@ -104,16 +104,16 @@ test('object with infinite length property', useDeserialized, { length: Infinity test('object with fractional length property', useDeserialized, { length: 1.5 }) test('symbol properties are reordered despite serialization', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const original = describe({ [s1]: 1, [s2]: 2 }) - const expected = describe({ [s2]: 2, [s1]: 1 }) + const s1 = Symbol('s1') + const s2 = Symbol('s2') + const original = describe({ [s1]: 1, [s2]: 2 }) + const expected = describe({ [s2]: 2, [s1]: 1 }) - t.true(compareDescriptors(deserialize(serialize(original)), expected)) - t.snapshot(diffDescriptors(deserialize(serialize(original)), expected)) + t.true(compareDescriptors(deserialize(serialize(original)), expected)) + t.snapshot(diffDescriptors(deserialize(serialize(original)), expected)) - t.true(compareDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) - t.snapshot(diffDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) + t.true(compareDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) + t.snapshot(diffDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) }) // Arrays @@ -122,19 +122,19 @@ test('array with complex item', useDeserialized, [{}]) // Iterators test('iterator with primitive item', useDeserialized, - Object.create({}, { - [Symbol.iterator]: { - enumerable: false, - * value () { return 'bar' }, - }, - })) + Object.create({}, { + [Symbol.iterator]: { + enumerable: false, + * value () { return 'bar' }, + }, + })) test('iterator with complex item', useDeserialized, - Object.create({}, { - [Symbol.iterator]: { - enumerable: false, - * value () { return {} }, - }, - })) + Object.create({}, { + [Symbol.iterator]: { + enumerable: false, + * value () { return {} }, + }, + })) // Maps test('map with primitive key and value', useDeserialized, new Map([['foo', 'bar']])) @@ -148,54 +148,54 @@ test('set with complex value', useDeserialized, new Set([{}])) // Pointers { - const obj = {} - obj.self = obj - test('object with pointer to itself', useDeserialized, obj) + const obj = {} + obj.self = obj + test('object with pointer to itself', useDeserialized, obj) } // Other complex values test('arguments', useDeserialized, (function () { return arguments })('foo', {})) { - const buffer = Buffer.from('decafbad'.repeat(12), 'hex') - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) - - for (const [tag, value] of [ - ['ArrayBuffer', arrayBuffer], - ['Buffer @Uint8Array', buffer], - ['DataView', new DataView(arrayBuffer)], - ['Float32Array', new Float32Array(arrayBuffer)], - ['Float64Array', new Float64Array(arrayBuffer)], - ['Int16Array', new Int16Array(arrayBuffer)], - ['Int32Array', new Int32Array(arrayBuffer)], - ['Int8Array', new Int8Array(arrayBuffer)], - ['Uint16Array', new Uint16Array(arrayBuffer)], - ['Uint32Array', new Uint32Array(arrayBuffer)], - ['Uint8Array', new Uint8Array(arrayBuffer)], - ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], - ]) { - test(tag, useDeserialized, value) - } + const buffer = Buffer.from('decafbad'.repeat(12), 'hex') + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) + + for (const [tag, value] of [ + ['ArrayBuffer', arrayBuffer], + ['Buffer @Uint8Array', buffer], + ['DataView', new DataView(arrayBuffer)], + ['Float32Array', new Float32Array(arrayBuffer)], + ['Float64Array', new Float64Array(arrayBuffer)], + ['Int16Array', new Int16Array(arrayBuffer)], + ['Int32Array', new Int32Array(arrayBuffer)], + ['Int8Array', new Int8Array(arrayBuffer)], + ['Uint16Array', new Uint16Array(arrayBuffer)], + ['Uint32Array', new Uint32Array(arrayBuffer)], + ['Uint8Array', new Uint8Array(arrayBuffer)], + ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], + ]) { + test(tag, useDeserialized, value) + } } test('date', useDeserialized, new Date('1969-07-20T20:17:40Z')) test('error', useDeserialized, new Error('foo')) test('function', useDeserialized, function foo () {}) test('compare functions with different names', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - const original = describe(a) - const deserialized = deserialize(serialize(original)) - t.false(compareDescriptors(deserialized, describe(b))) - t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) + const original = describe(a) + const deserialized = deserialize(serialize(original)) + t.false(compareDescriptors(deserialized, describe(b))) + t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) }) test('compare deserialized function with object', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - const b = { bar: 'b' } + function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + const b = { bar: 'b' } - const original = describe(a) - const deserialized = deserialize(serialize(original)) - t.false(compareDescriptors(deserialized, describe(b))) - t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) + const original = describe(a) + const deserialized = deserialize(serialize(original)) + t.false(compareDescriptors(deserialized, describe(b))) + t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) }) test('generator function', useDeserialized, function * foo () {}) test('global', useDeserialized, global) @@ -204,25 +204,25 @@ test('regexp', useDeserialized, /foo/gi) test('plugin', useDeserialized, new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins }) test('should fail when plugin for deserialization missing', t => { - const deserializationPlugins = [ - { - name: 'CustomError_v2', - apiVersion: 1, - serializerVersion: 2, - register: props => { - const custom = customErrorPlugin.factory(props) - props.addDescriptor(1, Symbol('CustomError_v2'), custom.deserialize) - return function (value) { - if (value.name === 'CustomError') { - return custom.describe - } - } - }, - }, - ] - - t.throws(() => { - const serialized = serialize(describe(new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins })) - deserialize(serialized, { plugins: deserializationPlugins }) - }, { name: 'MissingPluginError' }) + const deserializationPlugins = [ + { + name: 'CustomError_v2', + apiVersion: 1, + serializerVersion: 2, + register: props => { + const custom = customErrorPlugin.factory(props) + props.addDescriptor(1, Symbol('CustomError_v2'), custom.deserialize) + return function (value) { + if (value.name === 'CustomError') { + return custom.describe + } + } + }, + }, + ] + + t.throws(() => { + const serialized = serialize(describe(new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins })) + deserialize(serialized, { plugins: deserializationPlugins }) + }, { name: 'MissingPluginError' }) }) From b5e1f2716868f2c81319b49fdcde30033c44e4a1 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Mon, 21 Aug 2023 10:21:34 -0500 Subject: [PATCH 04/13] convert to `xo` --- .c8rc.json | 4 +- .editorconfig | 12 + .eslintrc.js | 14 - .gitattributes | 2 + index.js | 22 +- lib/Circular.js | 35 +- lib/Indenter.js | 20 +- lib/Registry.js | 24 +- lib/compare.js | 123 +++-- lib/complexValues/arguments.js | 40 +- lib/complexValues/arrayBuffer.js | 24 +- lib/complexValues/boxed.js | 47 +- lib/complexValues/dataView.js | 21 +- lib/complexValues/date.js | 86 +-- lib/complexValues/error.js | 134 ++--- lib/complexValues/function.js | 145 ++--- lib/complexValues/global.js | 27 +- lib/complexValues/map.js | 79 +-- lib/complexValues/object.js | 300 ++++++----- lib/complexValues/promise.js | 25 +- lib/complexValues/regexp.js | 96 ++-- lib/complexValues/set.js | 79 +-- lib/complexValues/typedArray.js | 171 +++--- lib/constants.js | 8 +- lib/describe.js | 206 +++---- lib/diff.js | 394 ++++++++------ lib/encoder.js | 384 +++++++------ lib/format.js | 101 ++-- lib/formatUtils.js | 119 +++-- lib/getCtor.js | 19 +- lib/getObjectKeys.js | 26 +- lib/getStringTag.js | 28 +- lib/hasLength.js | 14 +- lib/isEnumerable.js | 6 +- lib/lineBuilder.js | 323 ++++++----- lib/metaDescriptors/item.js | 216 ++++---- lib/metaDescriptors/mapEntry.js | 227 ++++---- lib/metaDescriptors/pointer.js | 26 +- lib/metaDescriptors/property.js | 188 ++++--- lib/metaDescriptors/stats.js | 100 ++-- lib/pluginRegistry.js | 169 +++--- lib/primitiveValues/bigInt.js | 34 +- lib/primitiveValues/boolean.js | 34 +- lib/primitiveValues/null.js | 26 +- lib/primitiveValues/number.js | 36 +- lib/primitiveValues/string.js | 359 +++++++------ lib/primitiveValues/symbol.js | 95 ++-- lib/primitiveValues/undefined.js | 26 +- lib/recursorUtils.js | 138 ++--- lib/serialize.js | 354 ++++++------ lib/shouldCompareDeep.js | 17 +- lib/symbolProperties.js | 112 ++-- lib/themeUtils.js | 195 +++---- package.json | 128 +++-- test/_instrumentedTheme.js | 43 +- test/compare.js | 107 ++-- test/diff.js | 638 +++++++++++----------- test/fixtures/customErrorPlugin.js | 43 +- test/fixtures/pointerSerialization.js | 17 +- test/format.js | 489 ++++++++--------- test/lodash-isequal-comparison.js | 739 ++++++++++++++------------ test/max-depth.js | 36 +- test/odd-properties.js | 15 +- test/pluginRegistry.js | 66 +-- test/serialization-fixtures.js | 11 +- test/serialize-and-encode.js | 278 +++++----- 66 files changed, 4385 insertions(+), 3735 deletions(-) create mode 100644 .editorconfig delete mode 100644 .eslintrc.js create mode 100644 .gitattributes diff --git a/.c8rc.json b/.c8rc.json index 39f2a65..4711308 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -2,8 +2,8 @@ "all": true, "exclude": [ "{coverage,test}/**", - ".eslintrc.js", - "index.d.ts" + ".xo-config.cjs", + "lib/lodash" ], "reporter": [ "html", diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fd6b3a1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = false + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 2abd045..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -export default { - sourceType: 'module', - plugins: ['@novemberborn/as-i-preach'], - extends: ['plugin:@novemberborn/as-i-preach/nodejs'], - overrides: [ - { - files: ['test/**/*.js'], - rules: { - 'no-new-object': 'off', - strict: 'off', - }, - }, - ], -} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..79203a2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto eol=lf +*.snap binary diff --git a/index.js b/index.js index 4409247..e7c0b38 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,14 @@ -import {compare, compareDescriptors} from './lib/compare.js' -import describe from './lib/describe.js' -import {diff, diffDescriptors} from './lib/diff.js' -import {format, formatDescriptor} from './lib/format.js' -import {serialize, deserialize} from './lib/serialize.js' +import {compare, compareDescriptors} from './lib/compare.js'; +import describe from './lib/describe.js'; +import {diff, diffDescriptors} from './lib/diff.js'; +import {format, formatDescriptor} from './lib/format.js'; +import {serialize, deserialize} from './lib/serialize.js'; -export {compare, compareDescriptors} from './lib/compare.js' -export {default as describe} from './lib/describe.js' -export {diff, diffDescriptors} from './lib/diff.js' -export {format, formatDescriptor} from './lib/format.js' -export {serialize, deserialize} from './lib/serialize.js' +export {compare, compareDescriptors} from './lib/compare.js'; +export {default as describe} from './lib/describe.js'; +export {diff, diffDescriptors} from './lib/diff.js'; +export {format, formatDescriptor} from './lib/format.js'; +export {serialize, deserialize} from './lib/serialize.js'; export default { compare, @@ -20,4 +20,4 @@ export default { formatDescriptor, serialize, deserialize, -} +}; diff --git a/lib/Circular.js b/lib/Circular.js index 56035e6..efc984c 100644 --- a/lib/Circular.js +++ b/lib/Circular.js @@ -1,32 +1,39 @@ export default class Circular { - constructor () { - this.stack = new Map() + constructor() { + this.stack = new Map(); } - add (descriptor) { - if (this.stack.has(descriptor)) throw new Error('Already in stack') + add(descriptor) { + if (this.stack.has(descriptor)) { + throw new Error('Already in stack'); + } if (descriptor.isItem !== true && descriptor.isMapEntry !== true && descriptor.isProperty !== true) { - this.stack.set(descriptor, this.stack.size + 1) + this.stack.set(descriptor, this.stack.size + 1); } - return this + + return this; } - delete (descriptor) { + delete(descriptor) { if (this.stack.has(descriptor)) { - if (this.stack.get(descriptor) !== this.stack.size) throw new Error('Not on top of stack') - this.stack.delete(descriptor) + if (this.stack.get(descriptor) !== this.stack.size) { + throw new Error('Not on top of stack'); + } + + this.stack.delete(descriptor); } - return this + + return this; } - has (descriptor) { - return this.stack.has(descriptor) + has(descriptor) { + return this.stack.has(descriptor); } - get (descriptor) { + get(descriptor) { return this.stack.has(descriptor) ? this.stack.get(descriptor) - : 0 + : 0; } } diff --git a/lib/Indenter.js b/lib/Indenter.js index 3be4f91..1882fc0 100644 --- a/lib/Indenter.js +++ b/lib/Indenter.js @@ -1,19 +1,19 @@ export default class Indenter { - constructor (level, step) { - this.level = level - this.step = step - this.value = step.repeat(level) + constructor(level, step) { + this.level = level; + this.step = step; + this.value = step.repeat(level); } - increase () { - return new Indenter(this.level + 1, this.step) + increase() { + return new Indenter(this.level + 1, this.step); } - decrease () { - return new Indenter(this.level - 1, this.step) + decrease() { + return new Indenter(this.level - 1, this.step); } - toString () { - return this.value + toString() { + return this.value; } } diff --git a/lib/Registry.js b/lib/Registry.js index 569d4a5..a776b3d 100644 --- a/lib/Registry.js +++ b/lib/Registry.js @@ -1,21 +1,21 @@ export default class Registry { - constructor () { - this.counter = 0 - this.map = new WeakMap() + constructor() { + this.counter = 0; + this.map = new WeakMap(); } - has (value) { - return this.map.has(value) + has(value) { + return this.map.has(value); } - get (value) { - return this.map.get(value).descriptor + get(value) { + return this.map.get(value).descriptor; } - alloc (value) { - const index = ++this.counter - const pointer = { descriptor: null, index } - this.map.set(value, pointer) - return pointer + alloc(value) { + const index = ++this.counter; + const pointer = {descriptor: null, index}; + this.map.set(value, pointer); + return pointer; } } diff --git a/lib/compare.js b/lib/compare.js index ca0a9a2..41555fd 100644 --- a/lib/compare.js +++ b/lib/compare.js @@ -1,95 +1,112 @@ -import Circular from './Circular.js' -import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from './constants.js' -import describe from './describe.js' -import * as recursorUtils from './recursorUtils.js' -import shouldCompareDeep from './shouldCompareDeep.js' -import * as symbolProperties from './symbolProperties.js' - -function shortcircuitPrimitive (value) { - if (value === null || value === undefined || value === true || value === false) return true - - const type = typeof value - if (type === 'string' || type === 'symbol') return true +import Circular from './Circular.js'; +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from './constants.js'; +import describe from './describe.js'; +import * as recursorUtils from './recursorUtils.js'; +import shouldCompareDeep from './shouldCompareDeep.js'; +import * as symbolProperties from './symbolProperties.js'; + +function shortcircuitPrimitive(value) { + if (value === null || value === undefined || value === true || value === false) { + return true; + } + + const type = typeof value; + if (type === 'string' || type === 'symbol') { + return true; + } + // Don't shortcircuit NaN values - if (type === 'number') return !isNaN(value) + if (type === 'number') { + return !Number.isNaN(value); + } - return false + return false; } -export function compareDescriptors (lhs, rhs) { - const lhsCircular = new Circular() - const rhsCircular = new Circular() +export function compareDescriptors(lhs, rhs) { + const lhsCircular = new Circular(); + const rhsCircular = new Circular(); - const lhsStack = [] - const rhsStack = [] - let topIndex = -1 + const lhsStack = []; + const rhsStack = []; + let topIndex = -1; do { - let result + let result; if (lhsCircular.has(lhs)) { result = lhsCircular.get(lhs) === rhsCircular.get(rhs) ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } else if (rhsCircular.has(rhs)) { - result = UNEQUAL + result = UNEQUAL; } else { - result = lhs.compare(rhs) + result = lhs.compare(rhs); + } + + if (result === UNEQUAL) { + return false; } - if (result === UNEQUAL) return false if (result !== DEEP_EQUAL) { - if (!shouldCompareDeep(result, lhs, rhs)) return false + if (!shouldCompareDeep(result, lhs, rhs)) { + return false; + } if (result === AMBIGUOUS && lhs.isProperty === true) { // Replace both sides by a pseudo-descriptor which collects symbol // properties instead. - lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) - rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) + lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor); + rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor); // Replace the current recursors so they can continue correctly after // the collectors have been "compared". This is necessary since the // collectors eat the first value after the last symbol property. - lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) - rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) + lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()); + rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()); } - lhsCircular.add(lhs) - rhsCircular.add(rhs) + lhsCircular.add(lhs); + rhsCircular.add(rhs); - lhsStack.push({ subject: lhs, recursor: lhs.createRecursor() }) - rhsStack.push({ subject: rhs, recursor: rhs.createRecursor() }) - topIndex++ + lhsStack.push({subject: lhs, recursor: lhs.createRecursor()}); + rhsStack.push({subject: rhs, recursor: rhs.createRecursor()}); + topIndex++; } while (topIndex >= 0) { - lhs = lhsStack[topIndex].recursor() - rhs = rhsStack[topIndex].recursor() + lhs = lhsStack[topIndex].recursor(); + rhs = rhsStack[topIndex].recursor(); if (lhs !== null && rhs !== null) { - break + break; } if (lhs === null && rhs === null) { - const lhsRecord = lhsStack.pop() - const rhsRecord = rhsStack.pop() - lhsCircular.delete(lhsRecord.subject) - rhsCircular.delete(rhsRecord.subject) - topIndex-- + const lhsRecord = lhsStack.pop(); + const rhsRecord = rhsStack.pop(); + lhsCircular.delete(lhsRecord.subject); + rhsCircular.delete(rhsRecord.subject); + topIndex--; } else { - return false + return false; } } - } while (topIndex >= 0) + } while (topIndex >= 0); - return true + return true; } -export function compare (actual, expected, options) { - if (Object.is(actual, expected)) return { pass: true } +export function compare(actual, expected, options) { + if (Object.is(actual, expected)) { + return {pass: true}; + } + // Primitive values should be the same, so if actual or expected is primitive // then the values will never compare. - if (shortcircuitPrimitive(actual) || shortcircuitPrimitive(expected)) return { pass: false } + if (shortcircuitPrimitive(actual) || shortcircuitPrimitive(expected)) { + return {pass: false}; + } - actual = describe(actual, options) - expected = describe(expected, options) - const pass = compareDescriptors(actual, expected) - return { actual, expected, pass } + actual = describe(actual, options); + expected = describe(expected, options); + const pass = compareDescriptors(actual, expected); + return {actual, expected, pass}; } diff --git a/lib/complexValues/arguments.js b/lib/complexValues/arguments.js index ec1a128..0421a7b 100644 --- a/lib/complexValues/arguments.js +++ b/lib/complexValues/arguments.js @@ -1,41 +1,47 @@ -import { AMBIGUOUS, UNEQUAL } from '../constants.js' -import * as object from './object.js' +import {AMBIGUOUS, UNEQUAL} from '../constants.js'; -export function describe (props) { - return new DescribedArgumentsValue(Object.assign({ - // Treat as an array, to allow comparisons with arrays +import * as object from './object.js'; + +export function describe(props) { + return new DescribedArgumentsValue({// Treat as an array, to allow comparisons with arrays isArray: true, isList: true, - }, props, { ctor: 'Arguments' })) + ...props, + ctor: 'Arguments', + }); } -export function deserialize (state, recursor) { - return new DeserializedArgumentsValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedArgumentsValue(state, recursor); } -export const tag = Symbol('ArgumentsValue') +export const tag = Symbol('ArgumentsValue'); class ArgumentsValue extends object.ObjectValue { - compare (expected) { - if (expected.isComplex !== true) return UNEQUAL + compare(expected) { + if (expected.isComplex !== true) { + return UNEQUAL; + } // When used on the left-hand side of a comparison, argument values may be // compared to arrays. - if (expected.stringTag === 'Array') return AMBIGUOUS + if (expected.stringTag === 'Array') { + return AMBIGUOUS; + } - return super.compare(expected) + return super.compare(expected); } - tag = tag + tag = tag; } -const DescribedArgumentsValue = object.DescribedMixin(ArgumentsValue) +const DescribedArgumentsValue = object.DescribedMixin(ArgumentsValue); class DeserializedArgumentsValue extends object.DeserializedMixin(ArgumentsValue) { - compare (expected) { + compare(expected) { // Deserialized argument values may only be compared to argument values. return expected.isComplex === true && expected.stringTag === 'Array' ? UNEQUAL - : super.compare(expected) + : super.compare(expected); } } diff --git a/lib/complexValues/arrayBuffer.js b/lib/complexValues/arrayBuffer.js index ab13c12..9dd9797 100644 --- a/lib/complexValues/arrayBuffer.js +++ b/lib/complexValues/arrayBuffer.js @@ -1,25 +1,25 @@ -import * as typedArray from './typedArray.js' +import {Buffer} from 'node:buffer'; -export function describe (props) { - return new DescribedArrayBufferValue(Object.assign({ - buffer: Buffer.from(props.value), +import * as typedArray from './typedArray.js'; + +export function describe(props) { + return new DescribedArrayBufferValue({buffer: Buffer.from(props.value), // Set isArray and isList so the property recursor excludes the byte accessors isArray: true, - isList: true, - }, props)) + isList: true, ...props}); } -export function deserialize (state, recursor) { - return new DeserializedArrayBufferValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedArrayBufferValue(state, recursor); } -export const tag = Symbol('ArrayBufferValue') +export const tag = Symbol('ArrayBufferValue'); // ArrayBuffers can be represented as regular Buffers, allowing them to be // treated as TypedArrays for the purposes of this package. class ArrayBufferValue extends typedArray.TypedArrayValue { - tag = tag + tag = tag; } -const DescribedArrayBufferValue = typedArray.DescribedMixin(ArrayBufferValue) -const DeserializedArrayBufferValue = typedArray.DeserializedMixin(ArrayBufferValue) +const DescribedArrayBufferValue = typedArray.DescribedMixin(ArrayBufferValue); +const DeserializedArrayBufferValue = typedArray.DeserializedMixin(ArrayBufferValue); diff --git a/lib/complexValues/boxed.js b/lib/complexValues/boxed.js index eb28aa7..0d27591 100644 --- a/lib/complexValues/boxed.js +++ b/lib/complexValues/boxed.js @@ -1,47 +1,50 @@ -import {tag as stringPrimitive} from '../primitiveValues/string.js' -import * as recursorUtils from '../recursorUtils.js' -import * as object from './object.js' +import {tag as stringPrimitive} from '../primitiveValues/string.js'; +import * as recursorUtils from '../recursorUtils.js'; -export function describe (props) { - return new DescribedBoxedValue(props) +import * as object from './object.js'; + +export function describe(props) { + return new DescribedBoxedValue(props); } -export function deserialize (state, recursor) { - return new DeserializedBoxedValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedBoxedValue(state, recursor); } -export const tag = Symbol('BoxedValue') +export const tag = Symbol('BoxedValue'); class BoxedValue extends object.ObjectValue { - tag = tag + tag = tag; } class DescribedBoxedValue extends object.DescribedMixin(BoxedValue) { - constructor (props) { - super(props) - this.unboxed = props.unboxed + constructor(props) { + super(props); + this.unboxed = props.unboxed; } - createListRecursor () { - return recursorUtils.NOOP_RECURSOR + createListRecursor() { + return recursorUtils.NOOP_RECURSOR; } - createPropertyRecursor () { - if (this.unboxed.tag !== stringPrimitive) return super.createPropertyRecursor() + createPropertyRecursor() { + if (this.unboxed.tag !== stringPrimitive) { + return super.createPropertyRecursor(); + } // Just so that createPropertyRecursor() skips the index-based character // properties. try { - this.isList = true - return super.createPropertyRecursor() + this.isList = true; + return super.createPropertyRecursor(); } finally { - this.isList = false + this.isList = false; } } - createRecursor () { - return recursorUtils.unshift(super.createRecursor(), this.unboxed) + createRecursor() { + return recursorUtils.unshift(super.createRecursor(), this.unboxed); } } -const DeserializedBoxedValue = object.DeserializedMixin(BoxedValue) +const DeserializedBoxedValue = object.DeserializedMixin(BoxedValue); diff --git a/lib/complexValues/dataView.js b/lib/complexValues/dataView.js index 595193e..0a1399c 100644 --- a/lib/complexValues/dataView.js +++ b/lib/complexValues/dataView.js @@ -1,25 +1,26 @@ -import * as typedArray from './typedArray.js' +import * as typedArray from './typedArray.js'; -export function describe (props) { - return new DescribedDataViewValue(Object.assign({ +export function describe(props) { + return new DescribedDataViewValue({ buffer: typedArray.getBuffer(props.value), // Set isArray and isList so the property recursor excludes the byte accessors isArray: true, isList: true, - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedDataViewValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedDataViewValue(state, recursor); } -export const tag = Symbol('DataViewValue') +export const tag = Symbol('DataViewValue'); // DataViews can be represented as regular Buffers, allowing them to be treated // as TypedArrays for the purposes of this package. class DataViewValue extends typedArray.TypedArrayValue { - tag = tag + tag = tag; } -const DescribedDataViewValue = typedArray.DescribedMixin(DataViewValue) -const DeserializedDataViewValue = typedArray.DeserializedMixin(DataViewValue) +const DescribedDataViewValue = typedArray.DescribedMixin(DataViewValue); +const DeserializedDataViewValue = typedArray.DeserializedMixin(DataViewValue); diff --git a/lib/complexValues/date.js b/lib/complexValues/date.js index dd60adb..fd1f797 100644 --- a/lib/complexValues/date.js +++ b/lib/complexValues/date.js @@ -1,22 +1,24 @@ -import dateTime from 'date-time' -import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' -import * as object from './object.js' - -export function describe (props) { - const date = props.value - const invalid = isNaN(date.valueOf()) - return new DescribedDateValue(Object.assign({}, props, { invalid })) +import dateTime from 'date-time'; + +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; + +import * as object from './object.js'; + +export function describe(props) { + const date = props.value; + const invalid = Number.isNaN(date.valueOf()); + return new DescribedDateValue({...props, invalid}); } -export function deserialize (state, recursor) { - return new DeserializedDateValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedDateValue(state, recursor); } -export const tag = Symbol('DateValue') +export const tag = Symbol('DateValue'); -function formatDate (date) { +function formatDate(date) { // Always format in UTC. The local timezone shouldn't be used since it's most // likely different from that of CI servers. return dateTime({ @@ -24,58 +26,60 @@ function formatDate (date) { local: false, showTimeZone: true, showMilliseconds: true, - }) + }); } class DateValue extends object.ObjectValue { - constructor (props) { - super(props) - this.invalid = props.invalid + constructor(props) { + super(props); + this.invalid = props.invalid; } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare(expected) { + const result = super.compare(expected); + if (result !== SHALLOW_EQUAL) { + return result; + } return (this.invalid && expected.invalid) || Object.is(this.value.getTime(), expected.value.getTime()) ? SHALLOW_EQUAL - : UNEQUAL + : UNEQUAL; } - formatShallow (theme, indent) { - const string = formatUtils.formatCtorAndStringTag(theme, this) + ' ' + - (this.invalid ? theme.date.invalid : formatUtils.wrap(theme.date.value, formatDate(this.value))) + ' ' + - theme.object.openBracket + formatShallow(theme, indent) { + const string = formatUtils.formatCtorAndStringTag(theme, this) + ' ' + + (this.invalid ? theme.date.invalid : formatUtils.wrap(theme.date.value, formatDate(this.value))) + ' ' + + theme.object.openBracket; return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { + finalize(innerLines) { return innerLines.isEmpty ? lineBuilder.single(string + theme.object.closeBracket) : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) // eslint-disable-line unicorn/prefer-spread + .append(lineBuilder.last(indent + theme.object.closeBracket)); }, - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + maxDepth() { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket); }, - }) + }); } - serialize () { - const iso = this.invalid ? null : this.value.toISOString() - return [this.invalid, iso, super.serialize()] + serialize() { + const iso = this.invalid ? null : this.value.toISOString(); + return [this.invalid, iso, super.serialize()]; } - tag = tag + tag = tag; } -const DescribedDateValue = object.DescribedMixin(DateValue) +const DescribedDateValue = object.DescribedMixin(DateValue); class DeserializedDateValue extends object.DeserializedMixin(DateValue) { - constructor (state, recursor) { - super(state[2], recursor) - this.invalid = state[0] - this.value = new Date(this.invalid ? NaN : state[1]) + constructor(state, recursor) { + super(state[2], recursor); + this.invalid = state[0]; + this.value = new Date(this.invalid ? Number.NaN : state[1]); } } diff --git a/lib/complexValues/error.js b/lib/complexValues/error.js index ccc5513..45ce6f9 100644 --- a/lib/complexValues/error.js +++ b/lib/complexValues/error.js @@ -1,127 +1,137 @@ -import { UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import isEnumerable from '../isEnumerable.js' -import lineBuilder from '../lineBuilder.js' -import { NOOP_RECURSOR } from '../recursorUtils.js' -import * as object from './object.js' - -export function describe (props) { - const error = props.value - return new DescribedErrorValue(Object.assign({ +import {UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import isEnumerable from '../isEnumerable.js'; +import lineBuilder from '../lineBuilder.js'; +import {NOOP_RECURSOR} from '../recursorUtils.js'; + +import * as object from './object.js'; + +export function describe(props) { + const error = props.value; + return new DescribedErrorValue({ nameIsEnumerable: isEnumerable(error, 'name'), name: error.name, messageIsEnumerable: isEnumerable(error, 'message'), message: error.message, - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedErrorValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedErrorValue(state, recursor); } -export const tag = Symbol('ErrorValue') +export const tag = Symbol('ErrorValue'); class ErrorValue extends object.ObjectValue { - constructor (props) { - super(props) - this.name = props.name + constructor(props) { + super(props); + this.name = props.name; } - compare (expected) { + compare(expected) { return this.tag === expected.tag && this.name === expected.name ? super.compare(expected) - : UNEQUAL + : UNEQUAL; } - formatShallow (theme, indent) { - const name = this.name || this.ctor + formatShallow(theme, indent) { + const name = this.name || this.ctor; let string = name ? formatUtils.wrap(theme.error.name, name) - : formatUtils.wrap(theme.object.stringTag, this.stringTag) + : formatUtils.wrap(theme.object.stringTag, this.stringTag); if (this.ctor && this.ctor !== name) { - string += ' ' + formatUtils.wrap(theme.error.ctor, this.ctor) + string += ' ' + formatUtils.wrap(theme.error.ctor, this.ctor); } + if (this.stringTag && this.stringTag !== this.ctor && this.name && !this.name.includes(this.stringTag)) { - string += ' ' + formatUtils.wrap(theme.object.secondaryStringTag, this.stringTag) + string += ' ' + formatUtils.wrap(theme.object.secondaryStringTag, this.stringTag); } - string += ' ' + theme.object.openBracket + + string += ' ' + theme.object.openBracket; return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { + finalize(innerLines) { return innerLines.isEmpty ? lineBuilder.single(string + theme.object.closeBracket) : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) // eslint-disable-line unicorn/prefer-spread + .append(lineBuilder.last(indent + theme.object.closeBracket)); }, - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + maxDepth() { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket); }, - }) + }); } - serialize () { - return [this.name, super.serialize()] + serialize() { + return [this.name, super.serialize()]; } - tag = tag + tag = tag; } class DescribedErrorValue extends object.DescribedMixin(ErrorValue) { - constructor (props) { - super(props) - this.nameIsEnumerable = props.nameIsEnumerable - this.messageIsEnumerable = props.messageIsEnumerable - this.message = props.message + constructor(props) { + super(props); + this.nameIsEnumerable = props.nameIsEnumerable; + this.messageIsEnumerable = props.messageIsEnumerable; + this.message = props.message; } - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() + createPropertyRecursor() { + const recursor = super.createPropertyRecursor(); - let skipName = this.nameIsEnumerable - let emitMessage = !this.messageIsEnumerable + let skipName = this.nameIsEnumerable; + let emitMessage = !this.messageIsEnumerable; - let size = recursor.size + let {size} = recursor; if (skipName && size > 0) { - size -= 1 + size -= 1; } + if (emitMessage) { - size += 1 + size += 1; } - if (size === 0) return NOOP_RECURSOR + if (size === 0) { + return NOOP_RECURSOR; + } - let done = false + let done = false; const next = () => { - if (done) return null + if (done) { + return null; + } - const property = recursor.next() + const property = recursor.next(); if (property) { if (skipName && property.key.value === 'name') { - skipName = false - return next() + skipName = false; + return next(); } - return property + + return property; } if (emitMessage) { - emitMessage = false - return this.describeProperty('message', this.describeAny(this.message)) + emitMessage = false; + return this.describeProperty('message', this.describeAny(this.message)); } - done = true - return null - } + done = true; + return null; + }; - return { size, next } + return {size, next}; } } class DeserializedErrorValue extends object.DeserializedMixin(ErrorValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.name = state[0] + constructor(state, recursor) { + super(state[1], recursor); + this.name = state[0]; } } diff --git a/lib/complexValues/function.js b/lib/complexValues/function.js index 0539fa4..1b92164 100644 --- a/lib/complexValues/function.js +++ b/lib/complexValues/function.js @@ -1,115 +1,138 @@ -import { UNEQUAL, SHALLOW_EQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import isEnumerable from '../isEnumerable.js' -import lineBuilder from '../lineBuilder.js' -import { NOOP_RECURSOR } from '../recursorUtils.js' -import * as object from './object.js' - -export function describe (props) { - const fn = props.value - return new DescribedFunctionValue(Object.assign({ +import {UNEQUAL, SHALLOW_EQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import isEnumerable from '../isEnumerable.js'; +import lineBuilder from '../lineBuilder.js'; +import {NOOP_RECURSOR} from '../recursorUtils.js'; + +import * as object from './object.js'; + +export function describe(props) { + const fn = props.value; + return new DescribedFunctionValue({ nameIsEnumerable: isEnumerable(fn, 'name'), name: typeof fn.name === 'string' ? fn.name : null, - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedFunctionValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedFunctionValue(state, recursor); } -export const tag = Symbol('FunctionValue') +export const tag = Symbol('FunctionValue'); class FunctionValue extends object.ObjectValue { - constructor (props) { - super(props) - this.name = props.name + constructor(props) { + super(props); + this.name = props.name; } - formatShallow (theme, indent) { - const string = formatUtils.wrap(theme.function.stringTag, this.stringTag) + - (this.name ? ' ' + formatUtils.wrap(theme.function.name, this.name) : '') + - ' ' + theme.object.openBracket + formatShallow(theme, indent) { + const string = formatUtils.wrap(theme.function.stringTag, this.stringTag) + + (this.name ? ' ' + formatUtils.wrap(theme.function.name, this.name) : '') + + ' ' + theme.object.openBracket; return super.formatShallow(theme, indent).customize({ - finalize (innerLines) { + finalize(innerLines) { return innerLines.isEmpty ? lineBuilder.single(string + theme.object.closeBracket) : lineBuilder.first(string) - .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) - .append(lineBuilder.last(indent + theme.object.closeBracket)) + .concat(innerLines.withFirstPrefixed(indent.increase()).stripFlags()) // eslint-disable-line unicorn/prefer-spread + .append(lineBuilder.last(indent + theme.object.closeBracket)); }, - maxDepth () { - return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket) + maxDepth() { + return lineBuilder.single(string + ' ' + theme.maxDepth + ' ' + theme.object.closeBracket); }, - }) + }); } - tag = tag + tag = tag; } class DescribedFunctionValue extends object.DescribedMixin(FunctionValue) { - constructor (props) { - super(props) - this.nameIsEnumerable = props.nameIsEnumerable + constructor(props) { + super(props); + this.nameIsEnumerable = props.nameIsEnumerable; } - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.name !== expected.name) return UNEQUAL - if (this.value && expected.value && this.value !== expected.value) return UNEQUAL + compare(expected) { + if (this.tag !== expected.tag) { + return UNEQUAL; + } + + if (this.name !== expected.name) { + return UNEQUAL; + } + + if (this.value && expected.value && this.value !== expected.value) { + return UNEQUAL; + } - return super.compare(expected) + return super.compare(expected); } - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() + createPropertyRecursor() { + const recursor = super.createPropertyRecursor(); - const skipName = this.nameIsEnumerable - if (!skipName) return recursor + const skipName = this.nameIsEnumerable; + if (!skipName) { + return recursor; + } - let size = recursor.size + let {size} = recursor; if (skipName) { - size -= 1 + size -= 1; } - if (size === 0) return NOOP_RECURSOR + if (size === 0) { + return NOOP_RECURSOR; + } const next = () => { - const property = recursor.next() + const property = recursor.next(); if (property) { if (skipName && property.key.value === 'name') { - return next() + return next(); } - return property + + return property; } - return null - } + return null; + }; - return { size, next } + return {size, next}; } - serialize () { - return [this.name, super.serialize()] + serialize() { + return [this.name, super.serialize()]; } } class DeserializedFunctionValue extends object.DeserializedMixin(FunctionValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.name = state[0] + constructor(state, recursor) { + super(state[1], recursor); + this.name = state[0]; } - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.name !== expected.name) return UNEQUAL - if (this.stringTag !== expected.stringTag) return UNEQUAL + compare(expected) { + if (this.tag !== expected.tag) { + return UNEQUAL; + } + + if (this.name !== expected.name) { + return UNEQUAL; + } + + if (this.stringTag !== expected.stringTag) { + return UNEQUAL; + } - return SHALLOW_EQUAL + return SHALLOW_EQUAL; } - serialize () { - return [this.name, super.serialize()] + serialize() { + return [this.name, super.serialize()]; } } diff --git a/lib/complexValues/global.js b/lib/complexValues/global.js index 3a34f4f..3ec93f9 100644 --- a/lib/complexValues/global.js +++ b/lib/complexValues/global.js @@ -1,28 +1,29 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe () { - return new GlobalValue() +export function describe() { + return new GlobalValue(); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('GlobalValue') +export const tag = Symbol('GlobalValue'); class GlobalValue { - compare (expected) { + compare(expected) { return this.tag === expected.tag ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { + formatDeep(theme) { return lineBuilder.single( - formatUtils.wrap(theme.global, 'Global') + ' ' + theme.object.openBracket + theme.object.closeBracket) + formatUtils.wrap(theme.global, 'Global') + ' ' + theme.object.openBracket + theme.object.closeBracket, + ); } - isComplex = true + isComplex = true; - tag = tag + tag = tag; } diff --git a/lib/complexValues/map.js b/lib/complexValues/map.js index a690921..62bd59b 100644 --- a/lib/complexValues/map.js +++ b/lib/complexValues/map.js @@ -1,71 +1,76 @@ -import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' -import * as recursorUtils from '../recursorUtils.js' -import * as object from './object.js' - -export function describe (props) { - return new DescribedMapValue(Object.assign({ - size: props.value.size, - }, props)) +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js'; +import * as recursorUtils from '../recursorUtils.js'; + +import * as object from './object.js'; + +export function describe(props) { + return new DescribedMapValue({size: props.value.size, ...props}); } -export function deserialize (state, recursor) { - return new DeserializedMapValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedMapValue(state, recursor); } -export const tag = Symbol('MapValue') +export const tag = Symbol('MapValue'); class MapValue extends object.ObjectValue { - constructor (props) { - super(props) - this.size = props.size + constructor(props) { + super(props); + this.size = props.size; } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare(expected) { + const result = super.compare(expected); + if (result !== SHALLOW_EQUAL) { + return result; + } return this.size === expected.size ? SHALLOW_EQUAL - : UNEQUAL + : UNEQUAL; } - prepareDiff (expected) { + prepareDiff(expected) { // Maps should be compared, even if they have a different number of entries. - return { compareResult: super.compare(expected) } + return {compareResult: super.compare(expected)}; } - serialize () { - return [this.size, super.serialize()] + serialize() { + return [this.size, super.serialize()]; } - tag = tag + tag = tag; } class DescribedMapValue extends object.DescribedMixin(MapValue) { - createIterableRecursor () { - const size = this.size - if (size === 0) return recursorUtils.NOOP_RECURSOR + createIterableRecursor() { + const {size} = this; + if (size === 0) { + return recursorUtils.NOOP_RECURSOR; + } - let index = 0 - let entries + let index = 0; + let entries; const next = () => { - if (index === size) return null + if (index === size) { + return null; + } if (!entries) { - entries = Array.from(this.value) + entries = [...this.value]; } - const entry = entries[index++] - return this.describeMapEntry(this.describeAny(entry[0]), this.describeAny(entry[1])) - } + const entry = entries[index++]; + return this.describeMapEntry(this.describeAny(entry[0]), this.describeAny(entry[1])); + }; - return { size, next } + return {size, next}; } } class DeserializedMapValue extends object.DeserializedMixin(MapValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.size = state[0] + constructor(state, recursor) { + super(state[1], recursor); + this.size = state[0]; } } diff --git a/lib/complexValues/object.js b/lib/complexValues/object.js index 4521047..240248b 100644 --- a/lib/complexValues/object.js +++ b/lib/complexValues/object.js @@ -1,221 +1,249 @@ -import { DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL } from '../constants.js' -import { ObjectFormatter } from '../formatUtils.js' -import getObjectKeys from '../getObjectKeys.js' -import hasLength from '../hasLength.js' -import * as stats from '../metaDescriptors/stats.js' -import * as recursorUtils from '../recursorUtils.js' - -export function describe (props) { - const isArray = props.stringTag === 'Array' - const object = props.value - return new DescribedObjectValue(Object.assign({ +import {DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL} from '../constants.js'; +import {ObjectFormatter} from '../formatUtils.js'; +import getObjectKeys from '../getObjectKeys.js'; +import hasLength from '../hasLength.js'; +import * as stats from '../metaDescriptors/stats.js'; +import * as recursorUtils from '../recursorUtils.js'; + +export function describe(props) { + const isArray = props.stringTag === 'Array'; + const object = props.value; + return new DescribedObjectValue({ isArray, isIterable: object[Symbol.iterator] !== undefined, isList: isArray || hasLength(object), - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedObjectValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedObjectValue(state, recursor); } -export const tag = Symbol('ObjectValue') +export const tag = Symbol('ObjectValue'); export class ObjectValue { - constructor (props) { - this.ctor = props.ctor - this.pointer = props.pointer - this.stringTag = props.stringTag - - this.isArray = props.isArray === true - this.isIterable = props.isIterable === true - this.isList = props.isList === true + constructor(props) { + this.ctor = props.ctor; + this.pointer = props.pointer; + this.stringTag = props.stringTag; + + this.isArray = props.isArray === true; + this.isIterable = props.isIterable === true; + this.isList = props.isList === true; } - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.stringTag !== expected.stringTag || !this.hasSameCtor(expected)) return UNEQUAL - return SHALLOW_EQUAL + compare(expected) { + if (this.tag !== expected.tag) { + return UNEQUAL; + } + + if (this.stringTag !== expected.stringTag || !this.hasSameCtor(expected)) { + return UNEQUAL; + } + + return SHALLOW_EQUAL; } - hasSameCtor (expected) { - return this.ctor === expected.ctor + hasSameCtor(expected) { + return this.ctor === expected.ctor; } - formatShallow (theme, indent) { - return new ObjectFormatter(this, theme, indent) + formatShallow(theme, indent) { + return new ObjectFormatter(this, theme, indent); } - serialize () { + serialize() { return [ - this.ctor, this.pointer, this.stringTag, - this.isArray, this.isIterable, this.isList, - ] + this.ctor, + this.pointer, + this.stringTag, + this.isArray, + this.isIterable, + this.isList, + ]; } - isComplex = true + isComplex = true; - tag = tag + tag = tag; } -const DescribedObjectValue = DescribedMixin(ObjectValue) -const DeserializedObjectValue = DeserializedMixin(ObjectValue) +const DescribedObjectValue = DescribedMixin(ObjectValue); +const DeserializedObjectValue = DeserializedMixin(ObjectValue); -export function DescribedMixin (base) { +export function DescribedMixin(base) { return class extends base { - constructor (props) { - super(props) - - this.value = props.value - this.describeAny = props.describeAny - this.describeItem = props.describeItem - this.describeMapEntry = props.describeMapEntry - this.describeProperty = props.describeProperty - - this.iterableState = null - this.listState = null - this.propertyState = null + constructor(props) { + super(props); + + this.value = props.value; + this.describeAny = props.describeAny; + this.describeItem = props.describeItem; + this.describeMapEntry = props.describeMapEntry; + this.describeProperty = props.describeProperty; + + this.iterableState = null; + this.listState = null; + this.propertyState = null; } - compare (expected) { + compare(expected) { return this.value === expected.value ? DEEP_EQUAL - : super.compare(expected) + : super.compare(expected); } - createPropertyRecursor () { - const objectKeys = getObjectKeys(this.value, this.isList ? this.value.length : 0) - const size = objectKeys.size - if (size === 0) return recursorUtils.NOOP_RECURSOR + createPropertyRecursor() { + const objectKeys = getObjectKeys(this.value, this.isList ? this.value.length : 0); + const {size} = objectKeys; + if (size === 0) { + return recursorUtils.NOOP_RECURSOR; + } - let index = 0 + let index = 0; const next = () => { - if (index === size) return null + if (index === size) { + return null; + } - const key = objectKeys.keys[index++] - return this.describeProperty(key, this.describeAny(this.value[key])) - } + const key = objectKeys.keys[index++]; + return this.describeProperty(key, this.describeAny(this.value[key])); + }; - return { size, next } + return {size, next}; } - createListRecursor () { - if (!this.isList) return recursorUtils.NOOP_RECURSOR + createListRecursor() { + if (!this.isList) { + return recursorUtils.NOOP_RECURSOR; + } - const size = this.value.length - if (size === 0) return recursorUtils.NOOP_RECURSOR + const size = this.value.length; + if (size === 0) { + return recursorUtils.NOOP_RECURSOR; + } - let index = 0 + let index = 0; const next = () => { - if (index === size) return null + if (index === size) { + return null; + } - const current = index - index++ - return this.describeItem(current, this.describeAny(this.value[current])) - } + const current = index; + index++; + return this.describeItem(current, this.describeAny(this.value[current])); + }; - return { size, next } + return {size, next}; } - createIterableRecursor () { - if (this.isArray || !this.isIterable) return recursorUtils.NOOP_RECURSOR + createIterableRecursor() { + if (this.isArray || !this.isIterable) { + return recursorUtils.NOOP_RECURSOR; + } - const iterator = this.value[Symbol.iterator]() - let first = iterator.next() + const iterator = this.value[Symbol.iterator](); + let first = iterator.next(); - let done = false - let size = -1 + let done = false; + let size = -1; if (first.done) { if (first.value === undefined) { - size = 0 - done = true + size = 0; + done = true; } else { - size = 1 + size = 1; } } - let index = 0 + let index = 0; const next = () => { - if (done) return null + if (done) { + return null; + } while (!done) { - const current = first || iterator.next() + const current = first || iterator.next(); if (current === first) { - first = null + first = null; } + if (current.done) { - done = true + done = true; } - const item = current.value - if (done && item === undefined) return null + const item = current.value; + if (done && item === undefined) { + return null; + } if (this.isList && this.value[index] === item) { - index++ + index++; } else { - return this.describeItem(index++, this.describeAny(item)) + return this.describeItem(index++, this.describeAny(item)); } } - } + }; - return { size, next } + return {size, next}; } - createRecursor () { - let recursedProperty = false - let recursedList = false - let recursedIterable = false + createRecursor() { + let recursedProperty = false; + let recursedList = false; + let recursedIterable = false; - let recursor = null + let recursor = null; return () => { - let retval = null + let retval = null; do { if (recursor !== null) { - retval = recursor.next() + retval = recursor.next(); if (retval === null) { - recursor = null + recursor = null; } } while (recursor === null && (!recursedList || !recursedProperty || !recursedIterable)) { // Prioritize recursing lists if (!recursedList) { - const replay = recursorUtils.replay(this.listState, () => this.createListRecursor()) - this.listState = replay.state - recursor = replay.recursor - recursedList = true + const replay = recursorUtils.replay(this.listState, () => this.createListRecursor()); + this.listState = replay.state; + recursor = replay.recursor; + recursedList = true; if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describeListRecursor(recursor) + retval = stats.describeListRecursor(recursor); } } else if (!recursedProperty) { - const replay = recursorUtils.replay(this.propertyState, () => this.createPropertyRecursor()) - this.propertyState = replay.state - recursor = replay.recursor - recursedProperty = true + const replay = recursorUtils.replay(this.propertyState, () => this.createPropertyRecursor()); + this.propertyState = replay.state; + recursor = replay.recursor; + recursedProperty = true; if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describePropertyRecursor(recursor) + retval = stats.describePropertyRecursor(recursor); } } else if (!recursedIterable) { - const replay = recursorUtils.replay(this.iterableState, () => this.createIterableRecursor()) - this.iterableState = replay.state - recursor = replay.recursor - recursedIterable = true + const replay = recursorUtils.replay(this.iterableState, () => this.createIterableRecursor()); + this.iterableState = replay.state; + recursor = replay.recursor; + recursedIterable = true; if (recursor !== recursorUtils.NOOP_RECURSOR) { - retval = stats.describeIterableRecursor(recursor) + retval = stats.describeIterableRecursor(recursor); } } } - } while (recursor !== null && retval === null) + } while (recursor !== null && retval === null); - return retval - } + return retval; + }; } - } + }; } -export function DeserializedMixin (base) { +export function DeserializedMixin(base) { return class extends base { - constructor (state, recursor) { + constructor(state, recursor) { super({ ctor: state[0], pointer: state[1], @@ -223,22 +251,24 @@ export function DeserializedMixin (base) { isArray: state[3], isIterable: state[4], isList: state[5], - }) + }); - this.deserializedRecursor = recursor - this.replayState = null + this.deserializedRecursor = recursor; + this.replayState = null; } - createRecursor () { - if (!this.deserializedRecursor) return () => null + createRecursor() { + if (!this.deserializedRecursor) { + return () => null; + } - const replay = recursorUtils.replay(this.replayState, () => ({ size: -1, next: this.deserializedRecursor })) - this.replayState = replay.state - return replay.recursor.next + const replay = recursorUtils.replay(this.replayState, () => ({size: -1, next: this.deserializedRecursor})); + this.replayState = replay.state; + return replay.recursor.next; } - hasSameCtor (expected) { - return this.ctor === expected.ctor + hasSameCtor(expected) { + return this.ctor === expected.ctor; } - } + }; } diff --git a/lib/complexValues/promise.js b/lib/complexValues/promise.js index 69bf85e..8dfdcc5 100644 --- a/lib/complexValues/promise.js +++ b/lib/complexValues/promise.js @@ -1,33 +1,34 @@ -import {DEEP_EQUAL, UNEQUAL} from '../constants.js' -import * as object from './object.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; -export function describe (props) { - return new DescribedPromiseValue(props) +import * as object from './object.js'; + +export function describe(props) { + return new DescribedPromiseValue(props); } -export function deserialize (props) { - return new DeserializedPromiseValue(props) +export function deserialize(props) { + return new DeserializedPromiseValue(props); } -export const tag = Symbol('PromiseValue') +export const tag = Symbol('PromiseValue'); class PromiseValue extends object.ObjectValue { - tag = tag + tag = tag; } class DescribedPromiseValue extends object.DescribedMixin(PromiseValue) { - compare (expected) { + compare(expected) { // When comparing described promises, require them to be the exact same // object. return super.compare(expected) === DEEP_EQUAL ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } } class DeserializedPromiseValue extends object.DeserializedMixin(PromiseValue) { - compare (expected) { + compare(expected) { // Deserialized promises can never be compared using object references. - return super.compare(expected) + return super.compare(expected); } } diff --git a/lib/complexValues/regexp.js b/lib/complexValues/regexp.js index 9c8c0b4..60054d6 100644 --- a/lib/complexValues/regexp.js +++ b/lib/complexValues/regexp.js @@ -1,84 +1,86 @@ -import { UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' -import * as object from './object.js' - -export function describe (props) { - const regexp = props.value - return new DescribedRegexpValue(Object.assign({ +import {UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; + +import * as object from './object.js'; + +export function describe(props) { + const regexp = props.value; + return new DescribedRegexpValue({ flags: getSortedFlags(regexp), source: regexp.source, - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedRegexpValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedRegexpValue(state, recursor); } -export const tag = Symbol('RegexpValue') +export const tag = Symbol('RegexpValue'); -function getSortedFlags (regexp) { - const flags = regexp.flags || String(regexp).slice(regexp.source.length + 2) - return flags.split('').sort().join('') +function getSortedFlags(regexp) { + const flags = regexp.flags || String(regexp).slice(regexp.source.length + 2); + return [...flags].sort().join(''); } class RegexpValue extends object.ObjectValue { - constructor (props) { - super(props) - this.flags = props.flags - this.source = props.source + constructor(props) { + super(props); + this.flags = props.flags; + this.source = props.source; } - compare (expected) { + compare(expected) { return this.tag === expected.tag && this.flags === expected.flags && this.source === expected.source ? super.compare(expected) - : UNEQUAL + : UNEQUAL; } - formatShallow (theme, indent) { - const ctor = this.ctor || this.stringTag - const regexp = formatUtils.wrap(theme.regexp.source, this.source) + formatUtils.wrap(theme.regexp.flags, this.flags) + formatShallow(theme, indent) { + const ctor = this.ctor || this.stringTag; + const regexp = formatUtils.wrap(theme.regexp.source, this.source) + formatUtils.wrap(theme.regexp.flags, this.flags); return super.formatShallow(theme, indent).customize({ finalize: innerLines => { - if (ctor === 'RegExp' && innerLines.isEmpty) return lineBuilder.single(regexp) + if (ctor === 'RegExp' && innerLines.isEmpty) { + return lineBuilder.single(regexp); + } - const innerIndentation = indent.increase() + const innerIndentation = indent.increase(); const header = lineBuilder.first(formatUtils.formatCtorAndStringTag(theme, this) + ' ' + theme.object.openBracket) - .concat(lineBuilder.line(innerIndentation + regexp)) + .concat(lineBuilder.line(innerIndentation + regexp)); // eslint-disable-line unicorn/prefer-spread if (!innerLines.isEmpty) { - header.append(lineBuilder.line(innerIndentation + theme.regexp.separator)) - header.append(innerLines.withFirstPrefixed(innerIndentation).stripFlags()) + header.append(lineBuilder.line(innerIndentation + theme.regexp.separator)); + header.append(innerLines.withFirstPrefixed(innerIndentation).stripFlags()); } - return header.append(lineBuilder.last(indent + theme.object.closeBracket)) + return header.append(lineBuilder.last(indent + theme.object.closeBracket)); }, - maxDepth: () => { - return lineBuilder.single( - formatUtils.formatCtorAndStringTag(theme, this) + ' ' + - theme.object.openBracket + ' ' + - regexp + ' ' + - theme.maxDepth + ' ' + - theme.object.closeBracket) - }, - }) + maxDepth: () => lineBuilder.single( + formatUtils.formatCtorAndStringTag(theme, this) + ' ' + + theme.object.openBracket + ' ' + + regexp + ' ' + + theme.maxDepth + ' ' + + theme.object.closeBracket), + }); } - serialize () { - return [this.flags, this.source, super.serialize()] + serialize() { + return [this.flags, this.source, super.serialize()]; } - tag = tag + tag = tag; } -const DescribedRegexpValue = object.DescribedMixin(RegexpValue) +const DescribedRegexpValue = object.DescribedMixin(RegexpValue); class DeserializedRegexpValue extends object.DeserializedMixin(RegexpValue) { - constructor (state, recursor) { - super(state[2], recursor) - this.flags = state[0] - this.source = state[1] + constructor(state, recursor) { + super(state[2], recursor); + this.flags = state[0]; + this.source = state[1]; } } diff --git a/lib/complexValues/set.js b/lib/complexValues/set.js index c78689b..7875d28 100644 --- a/lib/complexValues/set.js +++ b/lib/complexValues/set.js @@ -1,71 +1,76 @@ -import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js' -import * as recursorUtils from '../recursorUtils.js' -import * as object from './object.js' - -export function describe (props) { - return new DescribedSetValue(Object.assign({ - size: props.value.size, - }, props)) +import {SHALLOW_EQUAL, UNEQUAL} from '../constants.js'; +import * as recursorUtils from '../recursorUtils.js'; + +import * as object from './object.js'; + +export function describe(props) { + return new DescribedSetValue({size: props.value.size, ...props}); } -export function deserialize (state, recursor) { - return new DeserializedSetValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedSetValue(state, recursor); } -export const tag = Symbol('SetValue') +export const tag = Symbol('SetValue'); class SetValue extends object.ObjectValue { - constructor (props) { - super(props) - this.size = props.size + constructor(props) { + super(props); + this.size = props.size; } - compare (expected) { - const result = super.compare(expected) - if (result !== SHALLOW_EQUAL) return result + compare(expected) { + const result = super.compare(expected); + if (result !== SHALLOW_EQUAL) { + return result; + } return this.size === expected.size ? SHALLOW_EQUAL - : UNEQUAL + : UNEQUAL; } - prepareDiff (expected) { + prepareDiff(expected) { // Sets should be compared, even if they have a different number of items. - return { compareResult: super.compare(expected) } + return {compareResult: super.compare(expected)}; } - serialize () { - return [this.size, super.serialize()] + serialize() { + return [this.size, super.serialize()]; } - tag = tag + tag = tag; } class DescribedSetValue extends object.DescribedMixin(SetValue) { - createIterableRecursor () { - const size = this.size - if (size === 0) return recursorUtils.NOOP_RECURSOR + createIterableRecursor() { + const {size} = this; + if (size === 0) { + return recursorUtils.NOOP_RECURSOR; + } - let index = 0 - let members + let index = 0; + let members; const next = () => { - if (index === size) return null + if (index === size) { + return null; + } if (!members) { - members = Array.from(this.value) + members = [...this.value]; } - const value = members[index] - return this.describeItem(index++, this.describeAny(value)) - } + const value = members[index]; + return this.describeItem(index++, this.describeAny(value)); + }; - return { size, next } + return {size, next}; } } class DeserializedSetValue extends object.DeserializedMixin(SetValue) { - constructor (state, recursor) { - super(state[1], recursor) - this.size = state[0] + constructor(state, recursor) { + super(state[1], recursor); + this.size = state[0]; } } diff --git a/lib/complexValues/typedArray.js b/lib/complexValues/typedArray.js index ad7a4f7..06ec578 100644 --- a/lib/complexValues/typedArray.js +++ b/lib/complexValues/typedArray.js @@ -1,149 +1,168 @@ -import {DEEP_EQUAL, UNEQUAL} from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' -import {propertyTag as propertyStatsTag} from '../metaDescriptors/stats.js' -import * as recursorUtils from '../recursorUtils.js' -import * as object from './object.js' - -export function getBuffer (value) { - const buffer = Buffer.from(value.buffer) - return value.byteLength !== value.buffer.byteLength - ? buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) - : buffer +import {Buffer} from 'node:buffer'; + +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; +import {propertyTag as propertyStatsTag} from '../metaDescriptors/stats.js'; +import * as recursorUtils from '../recursorUtils.js'; + +import * as object from './object.js'; + +export function getBuffer(value) { + const buffer = Buffer.from(value.buffer); + return value.byteLength === value.buffer.byteLength + ? buffer + : buffer.slice(value.byteOffset, value.byteOffset + value.byteLength); } -export function describe (props) { - return new DescribedTypedArrayValue(Object.assign({ +export function describe(props) { + return new DescribedTypedArrayValue({ buffer: getBuffer(props.value), // Set isArray and isList so the property recursor excludes the byte accessors isArray: true, isList: true, - }, props)) + ...props, + }); } -export function deserialize (state, recursor) { - return new DeserializedTypedArrayValue(state, recursor) +export function deserialize(state, recursor) { + return new DeserializedTypedArrayValue(state, recursor); } -export function deserializeBytes (buffer) { - return new Bytes(buffer) +export function deserializeBytes(buffer) { + return new Bytes(buffer); } -export const bytesTag = Symbol('Bytes') +export const bytesTag = Symbol('Bytes'); -export const tag = Symbol('TypedArrayValue') +export const tag = Symbol('TypedArrayValue'); class Bytes { - constructor (buffer) { - this.buffer = buffer + constructor(buffer) { + this.buffer = buffer; } - compare (expected) { + compare(expected) { return expected.tag === bytesTag && this.buffer.equals(expected.buffer) ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme, indent) { - const indentation = indent - const lines = lineBuilder.buffer() + formatDeep(theme, indent) { + const indentation = indent; + const lines = lineBuilder.buffer(); // Display 4-byte words, 8 per line - let string = '' - let isFirst = true + let string = ''; + let isFirst = true; for (let offset = 0; offset < this.buffer.length; offset += 4) { if (offset > 0) { if (offset % 32 === 0) { if (isFirst) { - lines.append(lineBuilder.first(string)) - isFirst = false + lines.append(lineBuilder.first(string)); + isFirst = false; } else { - lines.append(lineBuilder.line(string)) + lines.append(lineBuilder.line(string)); } - string = String(indentation) + + string = String(indentation); } else { - string += ' ' + string += ' '; } } - string += formatUtils.wrap(theme.typedArray.bytes, this.buffer.toString('hex', offset, offset + 4)) + + string += formatUtils.wrap(theme.typedArray.bytes, this.buffer.toString('hex', offset, offset + 4)); } return isFirst ? lineBuilder.single(string) - : lines.append(lineBuilder.last(string)) + : lines.append(lineBuilder.last(string)); } - serialize () { - return this.buffer + serialize() { + return this.buffer; } - tag = bytesTag + tag = bytesTag; } export class TypedArrayValue extends object.ObjectValue { - constructor (props) { - super(props) - this.buffer = props.buffer + constructor(props) { + super(props); + this.buffer = props.buffer; } - formatShallow (theme, indent) { + formatShallow(theme, indent) { return super.formatShallow(theme, indent).customize({ - shouldFormat (subject) { - if (subject.tag === propertyStatsTag) return subject.size > 1 - if (subject.isProperty === true) return subject.key.value !== 'byteLength' - if (subject.tag === bytesTag) return subject.buffer.byteLength > 0 - return true + shouldFormat(subject) { + if (subject.tag === propertyStatsTag) { + return subject.size > 1; + } + + if (subject.isProperty === true) { + return subject.key.value !== 'byteLength'; + } + + if (subject.tag === bytesTag) { + return subject.buffer.byteLength > 0; + } + + return true; }, - }) + }); } - tag = tag + tag = tag; } -export function DescribedMixin (base) { +export function DescribedMixin(base) { return class extends object.DescribedMixin(base) { // The list isn't recursed. Instead a Bytes instance is returned by the main // recursor. - createListRecursor () { - return recursorUtils.NOOP_RECURSOR + createListRecursor() { + return recursorUtils.NOOP_RECURSOR; } - createPropertyRecursor () { - const recursor = super.createPropertyRecursor() - const size = recursor.size + 1 + createPropertyRecursor() { + const recursor = super.createPropertyRecursor(); + const size = recursor.size + 1; - let done = false + let done = false; const next = () => { - if (done) return null + if (done) { + return null; + } - const property = recursor.next() - if (property) return property + const property = recursor.next(); + if (property) { + return property; + } - done = true - return this.describeProperty('byteLength', this.describeAny(this.buffer.byteLength)) - } + done = true; + return this.describeProperty('byteLength', this.describeAny(this.buffer.byteLength)); + }; - return { size, next } + return {size, next}; } - createRecursor () { - return recursorUtils.unshift(super.createRecursor(), new Bytes(this.buffer)) + createRecursor() { + return recursorUtils.unshift(super.createRecursor(), new Bytes(this.buffer)); } - } + }; } -const DescribedTypedArrayValue = DescribedMixin(TypedArrayValue) +const DescribedTypedArrayValue = DescribedMixin(TypedArrayValue); -export function DeserializedMixin (base) { +export function DeserializedMixin(base) { return class extends object.DeserializedMixin(base) { - constructor (state, recursor) { - super(state, recursor) + constructor(state, recursor) { + super(state, recursor); // Get the Bytes descriptor from the recursor. It contains the buffer. - const bytesDescriptor = this.createRecursor()() - this.buffer = bytesDescriptor.buffer + const bytesDescriptor = this.createRecursor()(); + this.buffer = bytesDescriptor.buffer; } - } + }; } -const DeserializedTypedArrayValue = DeserializedMixin(TypedArrayValue) +const DeserializedTypedArrayValue = DeserializedMixin(TypedArrayValue); diff --git a/lib/constants.js b/lib/constants.js index 2f1a741..8ee7e78 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,4 +1,4 @@ -export const AMBIGUOUS = Symbol('AMBIGUOUS') -export const DEEP_EQUAL = Symbol('DEEP_EQUAL') -export const SHALLOW_EQUAL = Symbol('SHALLOW_EQUAL') -export const UNEQUAL = Symbol('UNEQUAL') +export const AMBIGUOUS = Symbol('AMBIGUOUS'); +export const DEEP_EQUAL = Symbol('DEEP_EQUAL'); +export const SHALLOW_EQUAL = Symbol('SHALLOW_EQUAL'); +export const UNEQUAL = Symbol('UNEQUAL'); diff --git a/lib/describe.js b/lib/describe.js index 25baca4..0d24f96 100644 --- a/lib/describe.js +++ b/lib/describe.js @@ -1,33 +1,31 @@ -import Registry from './Registry.js' -import * as argumentsValue from './complexValues/arguments.js' -import * as arrayBufferValue from './complexValues/arrayBuffer.js' -import * as boxedValue from './complexValues/boxed.js' -import * as dataViewValue from './complexValues/dataView.js' -import * as dateValue from './complexValues/date.js' -import * as errorValue from './complexValues/error.js' -import * as functionValue from './complexValues/function.js' -import * as globalValue from './complexValues/global.js' -import * as mapValue from './complexValues/map.js' -import * as objectValue from './complexValues/object.js' -import * as promiseValue from './complexValues/promise.js' -import * as regexpValue from './complexValues/regexp.js' -import * as setValue from './complexValues/set.js' -import * as typedArrayValue from './complexValues/typedArray.js' - -import getCtor from './getCtor.js' -import getStringTag from './getStringTag.js' -import * as itemDescriptor from './metaDescriptors/item.js' -import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js' -import * as propertyDescriptor from './metaDescriptors/property.js' - -import * as pluginRegistry from './pluginRegistry.js' -import * as bigIntValue from './primitiveValues/bigInt.js' -import * as booleanValue from './primitiveValues/boolean.js' -import * as nullValue from './primitiveValues/null.js' -import * as numberValue from './primitiveValues/number.js' -import * as stringValue from './primitiveValues/string.js' -import * as symbolValue from './primitiveValues/symbol.js' -import * as undefinedValue from './primitiveValues/undefined.js' +import Registry from './Registry.js'; +import * as argumentsValue from './complexValues/arguments.js'; +import * as arrayBufferValue from './complexValues/arrayBuffer.js'; +import * as boxedValue from './complexValues/boxed.js'; +import * as dataViewValue from './complexValues/dataView.js'; +import * as dateValue from './complexValues/date.js'; +import * as errorValue from './complexValues/error.js'; +import * as functionValue from './complexValues/function.js'; +import * as globalValue from './complexValues/global.js'; +import * as mapValue from './complexValues/map.js'; +import * as objectValue from './complexValues/object.js'; +import * as promiseValue from './complexValues/promise.js'; +import * as regexpValue from './complexValues/regexp.js'; +import * as setValue from './complexValues/set.js'; +import * as typedArrayValue from './complexValues/typedArray.js'; +import getCtor from './getCtor.js'; +import getStringTag from './getStringTag.js'; +import * as itemDescriptor from './metaDescriptors/item.js'; +import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js'; +import * as propertyDescriptor from './metaDescriptors/property.js'; +import * as pluginRegistry from './pluginRegistry.js'; +import * as bigIntValue from './primitiveValues/bigInt.js'; +import * as booleanValue from './primitiveValues/boolean.js'; +import * as nullValue from './primitiveValues/null.js'; +import * as numberValue from './primitiveValues/number.js'; +import * as stringValue from './primitiveValues/string.js'; +import * as symbolValue from './primitiveValues/symbol.js'; +import * as undefinedValue from './primitiveValues/undefined.js'; const SpecializedComplexes = new Map([ ['Arguments', argumentsValue.describe], @@ -51,67 +49,91 @@ const SpecializedComplexes = new Map([ ['Uint32Array', typedArrayValue.describe], ['Uint8Array', typedArrayValue.describe], ['Uint8ClampedArray', typedArrayValue.describe], -]) +]); -function describePrimitive (value) { - if (value === null) return nullValue.describe() - if (value === undefined) return undefinedValue.describe() - if (value === true || value === false) return booleanValue.describe(value) +function describePrimitive(value) { + if (value === null) { + return nullValue.describe(); + } + + if (value === undefined) { + return undefinedValue.describe(); + } + + if (value === true || value === false) { + return booleanValue.describe(value); + } + + const type = typeof value; + if (type === 'bigint') { + return bigIntValue.describe(value); + } + + if (type === 'number') { + return numberValue.describe(value); + } - const type = typeof value - if (type === 'bigint') return bigIntValue.describe(value) - if (type === 'number') return numberValue.describe(value) - if (type === 'string') return stringValue.describe(value) - if (type === 'symbol') return symbolValue.describe(value) + if (type === 'string') { + return stringValue.describe(value); + } + + if (type === 'symbol') { + return symbolValue.describe(value); + } - return null + return null; } -function unboxComplex (tag, complex) { +function unboxComplex(tag, complex) { // Try to unbox by calling `valueOf()`. `describePrimitive()` will return // `null` if the resulting value is not a primitive, in which case it's // ignored. if (typeof complex.valueOf === 'function') { - const value = complex.valueOf() - if (value !== complex) return describePrimitive(value) + const value = complex.valueOf(); + if (value !== complex) { + return describePrimitive(value); + } } - return null + return null; } -function registerPlugins (plugins) { - if (!Array.isArray(plugins) || plugins.length === 0) return () => null +function registerPlugins(plugins) { + if (!Array.isArray(plugins) || plugins.length === 0) { + return () => null; + } - const tryFns = pluginRegistry.getTryDescribeValues(plugins) + const tryFns = pluginRegistry.getTryDescribeValues(plugins); return (value, stringTag, ctor) => { for (const tryDescribeValue of tryFns) { - const describeValue = tryDescribeValue(value, stringTag, ctor) - if (describeValue) return describeValue + const describeValue = tryDescribeValue(value, stringTag, ctor); + if (describeValue) { + return describeValue; + } } - return null - } + return null; + }; } -function describeComplex (value, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) { - if (registry.has(value)) return registry.get(value) +// eslint-disable-next-line max-params +function describeComplex(value, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) { + if (registry.has(value)) { + return registry.get(value); + } - const stringTag = getStringTag(value) - const ctor = getCtor(stringTag, value) - const pointer = registry.alloc(value) + const stringTag = getStringTag(value); + const ctor = getCtor(stringTag, value); + const pointer = registry.alloc(value); - let unboxed - let describeValue = tryPlugins(value, stringTag, ctor) + let unboxed; + let describeValue = tryPlugins(value, stringTag, ctor); if (describeValue === null) { if (SpecializedComplexes.has(stringTag)) { - describeValue = SpecializedComplexes.get(stringTag) + describeValue = SpecializedComplexes.get(stringTag); } else { - unboxed = unboxComplex(stringTag, value) - if (unboxed !== null) { - describeValue = boxedValue.describe - } else { - describeValue = objectValue.describe - } + unboxed = unboxComplex(stringTag, value); + describeValue = unboxed === null ? objectValue.describe : boxedValue.describe; } } @@ -125,44 +147,40 @@ function describeComplex (value, registry, tryPlugins, describeAny, describeItem stringTag, unboxed, value, - }) - pointer.descriptor = descriptor - return descriptor + }); + pointer.descriptor = descriptor; + return descriptor; } -const describeItem = (index, valueDescriptor) => { - return valueDescriptor.isPrimitive === true - ? itemDescriptor.describePrimitive(index, valueDescriptor) - : itemDescriptor.describeComplex(index, valueDescriptor) -} - -const describeMapEntry = (keyDescriptor, valueDescriptor) => { - return mapEntryDescriptor.describe(keyDescriptor, valueDescriptor) -} +const describeItem = (index, valueDescriptor) => valueDescriptor.isPrimitive === true + ? itemDescriptor.describePrimitive(index, valueDescriptor) + : itemDescriptor.describeComplex(index, valueDescriptor); -export default function describe (value, options) { - const primitive = describePrimitive(value) - if (primitive !== null) return primitive +const describeMapEntry = (keyDescriptor, valueDescriptor) => mapEntryDescriptor.describe(keyDescriptor, valueDescriptor); - const registry = new Registry() - const tryPlugins = registerPlugins(options && options.plugins) - const curriedComplex = c => { - return describeComplex(c, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty) +export default function describe(value, options) { + const primitive = describePrimitive(value); + if (primitive !== null) { + return primitive; } + const registry = new Registry(); + const tryPlugins = registerPlugins(options && options.plugins); + const curriedComplex = c => describeComplex(c, registry, tryPlugins, describeAny, describeItem, describeMapEntry, describeProperty); + const describeAny = any => { - const descriptor = describePrimitive(any) - return descriptor !== null - ? descriptor - : curriedComplex(any) - } + const descriptor = describePrimitive(any); + return descriptor === null + ? curriedComplex(any) + : descriptor; + }; const describeProperty = (key, valueDescriptor) => { - const keyDescriptor = describePrimitive(key) + const keyDescriptor = describePrimitive(key); return valueDescriptor.isPrimitive === true ? propertyDescriptor.describePrimitive(keyDescriptor, valueDescriptor) - : propertyDescriptor.describeComplex(keyDescriptor, valueDescriptor) - } + : propertyDescriptor.describeComplex(keyDescriptor, valueDescriptor); + }; - return curriedComplex(value) + return curriedComplex(value); } diff --git a/lib/diff.js b/lib/diff.js index d0e2037..9a31a20 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -1,123 +1,143 @@ -import Circular from './Circular.js' -import Indenter from './Indenter.js' -import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL} from './constants.js' -import describe from './describe.js' -import lineBuilder from './lineBuilder.js' -import * as recursorUtils from './recursorUtils.js' -import shouldCompareDeep from './shouldCompareDeep.js' -import * as symbolProperties from './symbolProperties.js' -import * as themeUtils from './themeUtils.js' +import Circular from './Circular.js'; +import Indenter from './Indenter.js'; +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL} from './constants.js'; +import describe from './describe.js'; +import lineBuilder from './lineBuilder.js'; +import * as recursorUtils from './recursorUtils.js'; +import shouldCompareDeep from './shouldCompareDeep.js'; +import * as symbolProperties from './symbolProperties.js'; +import * as themeUtils from './themeUtils.js'; + +const NOOP = Symbol('NOOP'); + +const alwaysFormat = () => true; + +function compareComplexShape(lhs, rhs) { + let result = lhs.compare(rhs); + if (result === DEEP_EQUAL) { + return DEEP_EQUAL; + } -const NOOP = Symbol('NOOP') + if (result === UNEQUAL || !shouldCompareDeep(result, lhs, rhs)) { + return UNEQUAL; + } -const alwaysFormat = () => true + let collectedSymbolProperties = false; + let lhsRecursor = lhs.createRecursor(); + let rhsRecursor = rhs.createRecursor(); -function compareComplexShape (lhs, rhs) { - let result = lhs.compare(rhs) - if (result === DEEP_EQUAL) return DEEP_EQUAL - if (result === UNEQUAL || !shouldCompareDeep(result, lhs, rhs)) return UNEQUAL + do { + lhs = lhsRecursor(); + rhs = rhsRecursor(); - let collectedSymbolProperties = false - let lhsRecursor = lhs.createRecursor() - let rhsRecursor = rhs.createRecursor() + if (lhs === null && rhs === null) { + return SHALLOW_EQUAL; + } - do { - lhs = lhsRecursor() - rhs = rhsRecursor() + if (lhs === null || rhs === null) { + return UNEQUAL; + } - if (lhs === null && rhs === null) return SHALLOW_EQUAL - if (lhs === null || rhs === null) return UNEQUAL + result = lhs.compare(rhs); + if (result === UNEQUAL) { + return UNEQUAL; + } - result = lhs.compare(rhs) - if (result === UNEQUAL) return UNEQUAL if ( - result === AMBIGUOUS && - lhs.isProperty === true && !collectedSymbolProperties && - shouldCompareDeep(result, lhs, rhs) + result === AMBIGUOUS + && lhs.isProperty === true && !collectedSymbolProperties + && shouldCompareDeep(result, lhs, rhs) ) { - collectedSymbolProperties = true - const lhsCollector = new symbolProperties.Collector(lhs, lhsRecursor) - const rhsCollector = new symbolProperties.Collector(rhs, rhsRecursor) + collectedSymbolProperties = true; + const lhsCollector = new symbolProperties.Collector(lhs, lhsRecursor); + const rhsCollector = new symbolProperties.Collector(rhs, rhsRecursor); lhsRecursor = recursorUtils.sequence( lhsCollector.createRecursor(), - recursorUtils.unshift(lhsRecursor, lhsCollector.collectAll())) + recursorUtils.unshift(lhsRecursor, lhsCollector.collectAll())); rhsRecursor = recursorUtils.sequence( rhsCollector.createRecursor(), - recursorUtils.unshift(rhsRecursor, rhsCollector.collectAll())) + recursorUtils.unshift(rhsRecursor, rhsCollector.collectAll())); } - } while (true) + } while (true); // eslint-disable-line no-constant-condition } -export function diffDescriptors (lhs, rhs, options) { - const theme = themeUtils.normalize(options) - const invert = options ? options.invert === true : false +// eslint-disable-next-line complexity +export function diffDescriptors(lhs, rhs, options) { + const theme = themeUtils.normalize(options); + const invert = options ? options.invert === true : false; - const lhsCircular = new Circular() - const rhsCircular = new Circular() - const maxDepth = (options && options.maxDepth) || 0 + const lhsCircular = new Circular(); + const rhsCircular = new Circular(); + const maxDepth = (options && options.maxDepth) || 0; - let indent = new Indenter(0, ' ') + let indent = new Indenter(0, ' '); - const lhsStack = [] - const rhsStack = [] - let topIndex = -1 + const lhsStack = []; + const rhsStack = []; + let topIndex = -1; - const buffer = lineBuilder.buffer() - const diffStack = [] - let diffIndex = -1 + const buffer = lineBuilder.buffer(); + const diffStack = []; + let diffIndex = -1; - const isCircular = descriptor => lhsCircular.has(descriptor) || rhsCircular.has(descriptor) + const isCircular = descriptor => lhsCircular.has(descriptor) || rhsCircular.has(descriptor); + // eslint-disable-next-line complexity const format = (builder, subject, circular, depthOffset = 0) => { - if (diffIndex >= 0 && !diffStack[diffIndex].shouldFormat(subject)) return + if (diffIndex >= 0 && !diffStack[diffIndex].shouldFormat(subject)) { + return; + } if (circular.has(subject)) { - diffStack[diffIndex].formatter.append(builder.single(theme.circular)) - return + diffStack[diffIndex].formatter.append(builder.single(theme.circular)); + return; } - const formatStack = [] - let formatIndex = -1 + const formatStack = []; + let formatIndex = -1; do { if (circular.has(subject)) { - formatStack[formatIndex].formatter.append(builder.single(theme.circular), subject) + formatStack[formatIndex].formatter.append(builder.single(theme.circular), subject); } else { - let didFormat = false + let didFormat = false; if (typeof subject.formatDeep === 'function') { - let formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) + let formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent); if (formatted !== null) { - didFormat = true + didFormat = true; + // eslint-disable-next-line max-depth if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) + formatted = builder.setDefaultGutter(formatted); + // eslint-disable-next-line max-depth if (diffIndex === -1) { - buffer.append(formatted) + buffer.append(formatted); } else { - diffStack[diffIndex].formatter.append(formatted, subject) + diffStack[diffIndex].formatter.append(formatted, subject); } } else { - formatStack[formatIndex].formatter.append(formatted, subject) + formatStack[formatIndex].formatter.append(formatted, subject); } } } if (!didFormat && typeof subject.formatShallow === 'function') { - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const recursor = subject.createRecursor() + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent); + const recursor = subject.createRecursor(); if (formatter.increaseIndent && maxDepth > 0 && indent.level === (maxDepth + depthOffset)) { - const isEmpty = recursor() === null + const isEmpty = recursor() === null; let formatted = !isEmpty && typeof formatter.maxDepth === 'function' ? formatter.maxDepth() - : formatter.finalize() + : formatter.finalize(); + // eslint-disable-next-line max-depth if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) - diffStack[diffIndex].formatter.append(formatted, subject) + formatted = builder.setDefaultGutter(formatted); + diffStack[diffIndex].formatter.append(formatted, subject); } else { - formatStack[formatIndex].formatter.append(formatted, subject) + formatStack[formatIndex].formatter.append(formatted, subject); } } else { formatStack.push({ @@ -126,115 +146,129 @@ export function diffDescriptors (lhs, rhs, options) { decreaseIndent: formatter.increaseIndent, shouldFormat: formatter.shouldFormat || alwaysFormat, subject, - }) - formatIndex++ + }); + formatIndex++; + + // eslint-disable-next-line max-depth + if (formatter.increaseIndent) { + indent = indent.increase(); + } - if (formatter.increaseIndent) indent = indent.increase() - circular.add(subject) + circular.add(subject); } } } while (formatIndex >= 0) { do { - subject = formatStack[formatIndex].recursor() - } while (subject && !formatStack[formatIndex].shouldFormat(subject)) + subject = formatStack[formatIndex].recursor(); + } while (subject && !formatStack[formatIndex].shouldFormat(subject)); if (subject) { - break + break; + } + + const record = formatStack.pop(); + formatIndex--; + if (record.decreaseIndent) { + indent = indent.decrease(); } - const record = formatStack.pop() - formatIndex-- - if (record.decreaseIndent) indent = indent.decrease() - circular.delete(record.subject) + circular.delete(record.subject); - let formatted = record.formatter.finalize() + let formatted = record.formatter.finalize(); if (formatIndex === -1) { - formatted = builder.setDefaultGutter(formatted) + formatted = builder.setDefaultGutter(formatted); if (diffIndex === -1) { - buffer.append(formatted) + buffer.append(formatted); } else { - diffStack[diffIndex].formatter.append(formatted, record.subject) + diffStack[diffIndex].formatter.append(formatted, record.subject); } } else { - formatStack[formatIndex].formatter.append(formatted, record.subject) + formatStack[formatIndex].formatter.append(formatted, record.subject); } } - } while (formatIndex >= 0) - } + } while (formatIndex >= 0); + }; do { - let compareResult = NOOP + let compareResult = NOOP; if (lhsCircular.has(lhs)) { compareResult = lhsCircular.get(lhs) === rhsCircular.get(rhs) ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } else if (rhsCircular.has(rhs)) { - compareResult = UNEQUAL + compareResult = UNEQUAL; } - let firstPassSymbolProperty = false + let firstPassSymbolProperty = false; if (lhs.isProperty === true) { - compareResult = lhs.compare(rhs) + compareResult = lhs.compare(rhs); if (compareResult === AMBIGUOUS) { - const parent = lhsStack[topIndex].subject - firstPassSymbolProperty = parent.isSymbolPropertiesCollector !== true && parent.isSymbolPropertiesComparable !== true + const parent = lhsStack[topIndex].subject; + firstPassSymbolProperty = parent.isSymbolPropertiesCollector !== true && parent.isSymbolPropertiesComparable !== true; } } - let didFormat = false - let mustRecurse = false + let didFormat = false; + let mustRecurse = false; if (compareResult !== DEEP_EQUAL && !firstPassSymbolProperty && typeof lhs.prepareDiff === 'function') { - const lhsRecursor = topIndex === -1 ? null : lhsStack[topIndex].recursor - const rhsRecursor = topIndex === -1 ? null : rhsStack[topIndex].recursor + const lhsRecursor = topIndex === -1 ? null : lhsStack[topIndex].recursor; + const rhsRecursor = topIndex === -1 ? null : rhsStack[topIndex].recursor; const instructions = lhs.prepareDiff( rhs, lhsRecursor, rhsRecursor, compareComplexShape, - isCircular) + isCircular); if (instructions !== null) { if (topIndex >= 0) { if (typeof instructions.lhsRecursor === 'function') { - lhsStack[topIndex].recursor = instructions.lhsRecursor + lhsStack[topIndex].recursor = instructions.lhsRecursor; } + if (typeof instructions.rhsRecursor === 'function') { - rhsStack[topIndex].recursor = instructions.rhsRecursor + rhsStack[topIndex].recursor = instructions.rhsRecursor; } } if (instructions.compareResult) { - compareResult = instructions.compareResult + compareResult = instructions.compareResult; } + if (instructions.mustRecurse === true) { - mustRecurse = true + mustRecurse = true; } else { + // eslint-disable-next-line no-lonely-if, unicorn/prefer-switch if (instructions.actualIsExtraneous === true) { - format(lineBuilder.actual, lhs, lhsCircular) - didFormat = true + format(lineBuilder.actual, lhs, lhsCircular); + didFormat = true; } else if (instructions.multipleAreExtraneous === true) { + // eslint-disable-next-line max-depth for (const extraneous of instructions.descriptors) { - format(lineBuilder.actual, extraneous, lhsCircular) + format(lineBuilder.actual, extraneous, lhsCircular); } - didFormat = true + + didFormat = true; } else if (instructions.expectedIsMissing === true) { - format(lineBuilder.expected, rhs, rhsCircular) - didFormat = true + format(lineBuilder.expected, rhs, rhsCircular); + didFormat = true; } else if (instructions.multipleAreMissing === true) { + // eslint-disable-next-line max-depth for (const missing of instructions.descriptors) { - format(lineBuilder.expected, missing, rhsCircular) + format(lineBuilder.expected, missing, rhsCircular); } - didFormat = true + + didFormat = true; } else if (instructions.isUnequal === true) { - format(lineBuilder.actual, lhs, lhsCircular) - format(lineBuilder.expected, rhs, rhsCircular) - didFormat = true + format(lineBuilder.actual, lhs, lhsCircular); + format(lineBuilder.expected, rhs, rhsCircular); + didFormat = true; } else if (!instructions.compareResult) { // TODO: Throw a useful, custom error - throw new Error('Illegal result of prepareDiff()') + throw new Error('Illegal result of prepareDiff()'); } } } @@ -242,142 +276,150 @@ export function diffDescriptors (lhs, rhs, options) { if (!didFormat) { if (compareResult === NOOP) { - compareResult = lhs.compare(rhs) + compareResult = lhs.compare(rhs); } if (!mustRecurse) { - mustRecurse = shouldCompareDeep(compareResult, lhs, rhs) + mustRecurse = shouldCompareDeep(compareResult, lhs, rhs); } if (compareResult === DEEP_EQUAL) { - format(lineBuilder, lhs, lhsCircular) + format(lineBuilder, lhs, lhsCircular); } else if (mustRecurse) { if (compareResult === AMBIGUOUS && lhs.isProperty === true) { // Replace both sides by a pseudo-descriptor which collects symbol // properties instead. - lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor) - rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor) + lhs = new symbolProperties.Collector(lhs, lhsStack[topIndex].recursor); + rhs = new symbolProperties.Collector(rhs, rhsStack[topIndex].recursor); // Replace the current recursors so they can continue correctly after // the collectors have been "compared". This is necessary since the // collectors eat the first value after the last symbol property. - lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()) - rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()) + lhsStack[topIndex].recursor = recursorUtils.unshift(lhsStack[topIndex].recursor, lhs.collectAll()); + rhsStack[topIndex].recursor = recursorUtils.unshift(rhsStack[topIndex].recursor, rhs.collectAll()); } if (typeof lhs.diffShallow === 'function') { - const formatter = lhs.diffShallow(rhs, themeUtils.applyModifiers(lhs, theme), indent) + const formatter = lhs.diffShallow(rhs, themeUtils.applyModifiers(lhs, theme), indent); diffStack.push({ formatter, origin: lhs, decreaseIndent: formatter.increaseIndent, exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, shouldFormat: formatter.shouldFormat || alwaysFormat, - }) - diffIndex++ + }); + diffIndex++; - if (formatter.increaseIndent) indent = indent.increase() + if (formatter.increaseIndent) { + indent = indent.increase(); + } } else if (typeof lhs.formatShallow === 'function') { - const formatter = lhs.formatShallow(themeUtils.applyModifiers(lhs, theme), indent) + const formatter = lhs.formatShallow(themeUtils.applyModifiers(lhs, theme), indent); diffStack.push({ formatter, decreaseIndent: formatter.increaseIndent, exceedsMaxDepth: formatter.increaseIndent && maxDepth > 0 && indent.level >= maxDepth, shouldFormat: formatter.shouldFormat || alwaysFormat, subject: lhs, - }) - diffIndex++ + }); + diffIndex++; - if (formatter.increaseIndent) indent = indent.increase() + if (formatter.increaseIndent) { + indent = indent.increase(); + } } - lhsCircular.add(lhs) - rhsCircular.add(rhs) + lhsCircular.add(lhs); + rhsCircular.add(rhs); - lhsStack.push({ diffIndex, subject: lhs, recursor: lhs.createRecursor() }) - rhsStack.push({ diffIndex, subject: rhs, recursor: rhs.createRecursor() }) - topIndex++ + lhsStack.push({diffIndex, subject: lhs, recursor: lhs.createRecursor()}); + rhsStack.push({diffIndex, subject: rhs, recursor: rhs.createRecursor()}); + topIndex++; } else { const diffed = typeof lhs.diffDeep === 'function' ? lhs.diffDeep(rhs, themeUtils.applyModifiers(lhs, theme), indent, invert) - : null + : null; if (diffed === null) { - format(lineBuilder.actual, lhs, lhsCircular) - format(lineBuilder.expected, rhs, rhsCircular) + format(lineBuilder.actual, lhs, lhsCircular); + format(lineBuilder.expected, rhs, rhsCircular); + } else if (diffIndex === -1) { + buffer.append(diffed); } else { - if (diffIndex === -1) { - buffer.append(diffed) - } else { - diffStack[diffIndex].formatter.append(diffed, lhs) - } + diffStack[diffIndex].formatter.append(diffed, lhs); } } } while (topIndex >= 0) { - lhs = lhsStack[topIndex].recursor() - rhs = rhsStack[topIndex].recursor() + lhs = lhsStack[topIndex].recursor(); + rhs = rhsStack[topIndex].recursor(); if (lhs !== null && rhs !== null) { - break + break; } if (lhs === null && rhs === null) { - const lhsRecord = lhsStack.pop() - const rhsRecord = rhsStack.pop() - lhsCircular.delete(lhsRecord.subject) - rhsCircular.delete(rhsRecord.subject) - topIndex-- + const lhsRecord = lhsStack.pop(); + const rhsRecord = rhsStack.pop(); + lhsCircular.delete(lhsRecord.subject); + rhsCircular.delete(rhsRecord.subject); + topIndex--; if (lhsRecord.diffIndex === diffIndex) { - const record = diffStack.pop() - diffIndex-- - if (record.decreaseIndent) indent = indent.decrease() + const record = diffStack.pop(); + diffIndex--; + if (record.decreaseIndent) { + indent = indent.decrease(); + } - let formatted = record.formatter.finalize() + let formatted = record.formatter.finalize(); if (record.exceedsMaxDepth && !formatted.hasGutter) { // The record exceeds the max depth, but contains no actual diff. // Discard the potentially deep formatting and format just the // original subject. - const subject = lhsRecord.subject - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const isEmpty = subject.createRecursor()() === null + const {subject} = lhsRecord; + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent); + const isEmpty = subject.createRecursor()() === null; formatted = !isEmpty && typeof formatter.maxDepth === 'function' ? formatter.maxDepth() - : formatter.finalize() + : formatter.finalize(); } if (diffIndex === -1) { - buffer.append(formatted) + buffer.append(formatted); } else { - diffStack[diffIndex].formatter.append(formatted, record.subject) + diffStack[diffIndex].formatter.append(formatted, record.subject); } } } else { - let builder, circular, stack, subject + let builder; + let circular; + let stack; + let subject; + if (lhs === null) { - builder = lineBuilder.expected - circular = rhsCircular - stack = rhsStack - subject = rhs + builder = lineBuilder.expected; + circular = rhsCircular; + stack = rhsStack; + subject = rhs; } else { - builder = lineBuilder.actual - circular = lhsCircular - stack = lhsStack - subject = lhs + builder = lineBuilder.actual; + circular = lhsCircular; + stack = lhsStack; + subject = lhs; } do { - format(builder, subject, circular, indent.level) - subject = stack[topIndex].recursor() - } while (subject !== null) + format(builder, subject, circular, indent.level); + subject = stack[topIndex].recursor(); + } while (subject !== null); } } - } while (topIndex >= 0) + } while (topIndex >= 0); - return buffer.toString({ diff: true, invert, theme }) + return buffer.toString({diff: true, invert, theme}); } -export function diff (actual, expected, options) { - return diffDescriptors(describe(actual, options), describe(expected, options), options) +export function diff(actual, expected, options) { + return diffDescriptors(describe(actual, options), describe(expected, options), options); } diff --git a/lib/encoder.js b/lib/encoder.js index 5d55f48..662f17b 100644 --- a/lib/encoder.js +++ b/lib/encoder.js @@ -1,10 +1,12 @@ -import {flattenDeep} from './lodash/index.js' +import {Buffer} from 'node:buffer'; + +import {flattenDeep} from './lodash/index.js'; // Indexes are hexadecimal to make reading the binary output easier. const valueTypes = { zero: 0x00, int8: 0x01, // Note that the hex value equals the number of bytes required - int16: 0x02, // to store the integer. + int16: 0x02, // To store the integer. int24: 0x03, int32: 0x04, int40: 0x05, @@ -23,57 +25,101 @@ const valueTypes = { bytes: 0x12, list: 0x13, descriptor: 0x14, -} +}; -export const descriptorSymbol = Symbol('descriptor') +export const descriptorSymbol = Symbol('descriptor'); -function encodeInteger (type, value) { - const encoded = Buffer.alloc(type) - encoded.writeIntLE(value, 0, type) - return [type, encoded] +function encodeInteger(type, value) { + const encoded = Buffer.alloc(type); + encoded.writeIntLE(value, 0, type); + return [type, encoded]; } -function encodeValue (value) { - if (Object.is(value, 0)) return valueTypes.zero - if (Object.is(value, -0)) return valueTypes.negativeZero - if (Object.is(value, NaN)) return valueTypes.notANumber - if (value === Infinity) return valueTypes.infinity - if (value === -Infinity) return valueTypes.negativeInfinity - if (value === undefined) return valueTypes.undefined - if (value === null) return valueTypes.null - if (value === true) return valueTypes.true - if (value === false) return valueTypes.false - - const type = typeof value +// eslint-disable-next-line complexity +function encodeValue(value) { + if (Object.is(value, 0)) { + return valueTypes.zero; + } + + if (Object.is(value, -0)) { + return valueTypes.negativeZero; + } + + if (Object.is(value, Number.NaN)) { + return valueTypes.notANumber; + } + + if (value === Number.POSITIVE_INFINITY) { + return valueTypes.infinity; + } + + if (value === Number.NEGATIVE_INFINITY) { + return valueTypes.negativeInfinity; + } + + if (value === undefined) { + return valueTypes.undefined; + } + + if (value === null) { + return valueTypes.null; + } + + if (value === true) { + return valueTypes.true; + } + + if (value === false) { + return valueTypes.false; + } + + const type = typeof value; if (type === 'number') { if (Number.isInteger(value)) { // The integer types are signed, so int8 can only store 7 bits, int16 // only 15, etc. - if (value >= -0x80 && value < 0x80) return encodeInteger(valueTypes.int8, value) - if (value >= -0x8000 && value < 0x8000) return encodeInteger(valueTypes.int16, value) - if (value >= -0x800000 && value < 0x800000) return encodeInteger(valueTypes.int24, value) - if (value >= -0x80000000 && value < 0x80000000) return encodeInteger(valueTypes.int32, value) - if (value >= -0x8000000000 && value < 0x8000000000) return encodeInteger(valueTypes.int40, value) - if (value >= -0x800000000000 && value < 0x800000000000) return encodeInteger(valueTypes.int48, value) + if (value >= -0x80 && value < 0x80) { + return encodeInteger(valueTypes.int8, value); + } + + if (value >= -0x80_00 && value < 0x80_00) { + return encodeInteger(valueTypes.int16, value); + } + + if (value >= -0x80_00_00 && value < 0x80_00_00) { + return encodeInteger(valueTypes.int24, value); + } + + if (value >= -0x80_00_00_00 && value < 0x80_00_00_00) { + return encodeInteger(valueTypes.int32, value); + } + + if (value >= -0x80_00_00_00_00 && value < 0x80_00_00_00_00) { + return encodeInteger(valueTypes.int40, value); + } + + if (value >= -0x80_00_00_00_00_00 && value < 0x80_00_00_00_00_00) { + return encodeInteger(valueTypes.int48, value); + } // Fall through to encoding the value as a number string. } - const encoded = Buffer.from(String(value), 'utf8') - return [valueTypes.numberString, encodeValue(encoded.length), encoded] + const encoded = Buffer.from(String(value), 'utf8'); + return [valueTypes.numberString, encodeValue(encoded.length), encoded]; } if (type === 'string') { - const encoded = Buffer.from(value, 'utf8') - return [valueTypes.utf8, encodeValue(encoded.length), encoded] + const encoded = Buffer.from(value, 'utf8'); + return [valueTypes.utf8, encodeValue(encoded.length), encoded]; } if (type === 'bigint') { - const encoded = Buffer.from(String(value), 'utf8') - return [valueTypes.bigInt, encodeValue(encoded.length), encoded] + const encoded = Buffer.from(String(value), 'utf8'); + return [valueTypes.bigInt, encodeValue(encoded.length), encoded]; } if (Buffer.isBuffer(value)) { - return [valueTypes.bytes, encodeValue(value.byteLength), value] + return [valueTypes.bytes, encodeValue(value.byteLength), value]; } if (Array.isArray(value)) { @@ -81,215 +127,243 @@ function encodeValue (value) { value[descriptorSymbol] === true ? valueTypes.descriptor : valueTypes.list, encodeValue(value.length), value.map(x => encodeValue(x)), - ] + ]; } - const hex = `0x${type.toString(16).toUpperCase()}` - throw new TypeError(`Unexpected value with type ${hex}`) + const hex = `0x${type.toString(16).toUpperCase()}`; + throw new TypeError(`Unexpected value with type ${hex}`); } -function decodeValue (buffer, byteOffset) { - const type = buffer.readUInt8(byteOffset) - byteOffset += 1 +// eslint-disable-next-line complexity +function decodeValue(buffer, byteOffset) { + const type = buffer.readUInt8(byteOffset); + byteOffset += 1; - if (type === valueTypes.zero) return { byteOffset, value: 0 } - if (type === valueTypes.negativeZero) return { byteOffset, value: -0 } - if (type === valueTypes.notANumber) return { byteOffset, value: NaN } - if (type === valueTypes.infinity) return { byteOffset, value: Infinity } - if (type === valueTypes.negativeInfinity) return { byteOffset, value: -Infinity } - if (type === valueTypes.undefined) return { byteOffset, value: undefined } - if (type === valueTypes.null) return { byteOffset, value: null } - if (type === valueTypes.true) return { byteOffset, value: true } - if (type === valueTypes.false) return { byteOffset, value: false } + if (type === valueTypes.zero) { + return {byteOffset, value: 0}; + } + + if (type === valueTypes.negativeZero) { + return {byteOffset, value: -0}; + } + + if (type === valueTypes.notANumber) { + return {byteOffset, value: Number.NaN}; + } + + if (type === valueTypes.infinity) { + return {byteOffset, value: Number.POSITIVE_INFINITY}; + } + + if (type === valueTypes.negativeInfinity) { + return {byteOffset, value: Number.NEGATIVE_INFINITY}; + } + + if (type === valueTypes.undefined) { + return {byteOffset, value: undefined}; + } + + if (type === valueTypes.null) { + return {byteOffset, value: null}; + } + + if (type === valueTypes.true) { + return {byteOffset, value: true}; + } + + if (type === valueTypes.false) { + return {byteOffset, value: false}; + } if ( - type === valueTypes.int8 || type === valueTypes.int16 || type === valueTypes.int24 || - type === valueTypes.int32 || type === valueTypes.int40 || type === valueTypes.int48 + type === valueTypes.int8 || type === valueTypes.int16 || type === valueTypes.int24 + || type === valueTypes.int32 || type === valueTypes.int40 || type === valueTypes.int48 ) { - const value = buffer.readIntLE(byteOffset, type) - byteOffset += type - return { byteOffset, value } + const value = buffer.readIntLE(byteOffset, type); + byteOffset += type; + return {byteOffset, value}; } if (type === valueTypes.numberString || type === valueTypes.utf8 || type === valueTypes.bytes || type === valueTypes.bigInt) { - const length = decodeValue(buffer, byteOffset) - const start = length.byteOffset - const end = start + length.value + const length = decodeValue(buffer, byteOffset); + const start = length.byteOffset; + const end = start + length.value; if (type === valueTypes.numberString) { - const value = Number(buffer.toString('utf8', start, end)) - return { byteOffset: end, value } + const value = Number(buffer.toString('utf8', start, end)); + return {byteOffset: end, value}; } if (type === valueTypes.utf8) { - const value = buffer.toString('utf8', start, end) - return { byteOffset: end, value } + const value = buffer.toString('utf8', start, end); + return {byteOffset: end, value}; } if (type === valueTypes.bigInt) { - const value = BigInt(buffer.toString('utf8', start, end)) // eslint-disable-line no-undef - return { byteOffset: end, value } + const value = BigInt(buffer.toString('utf8', start, end)); + return {byteOffset: end, value}; } - const value = buffer.slice(start, end) - return { byteOffset: end, value } + const value = buffer.slice(start, end); + return {byteOffset: end, value}; } if (type === valueTypes.list || type === valueTypes.descriptor) { - const length = decodeValue(buffer, byteOffset) - byteOffset = length.byteOffset + const length = decodeValue(buffer, byteOffset); + byteOffset = length.byteOffset; - const value = new Array(length.value) + const value = Array.from({length: length.value}); if (type === valueTypes.descriptor) { - value[descriptorSymbol] = true + value[descriptorSymbol] = true; } for (let index = 0; index < length.value; index++) { - const item = decodeValue(buffer, byteOffset) - byteOffset = item.byteOffset - value[index] = item.value + const item = decodeValue(buffer, byteOffset); + byteOffset = item.byteOffset; + value[index] = item.value; } - return { byteOffset, value } + return {byteOffset, value}; } - const hex = `0x${type.toString(16).toUpperCase()}` - throw new TypeError(`Could not decode type ${hex}`) + const hex = `0x${type.toString(16).toUpperCase()}`; + throw new TypeError(`Could not decode type ${hex}`); } -function buildBuffer (numberOrArray) { +function buildBuffer(numberOrArray) { if (typeof numberOrArray === 'number') { - const byte = Buffer.alloc(1) - byte.writeUInt8(numberOrArray) - return byte + const byte = Buffer.alloc(1); + byte.writeUInt8(numberOrArray); + return byte; } - const array = flattenDeep(numberOrArray) - const buffers = new Array(array.length) - let byteLength = 0 + const array = flattenDeep(numberOrArray); + const buffers = Array.from({length: array.length}); + let byteLength = 0; for (const [index, element] of array.entries()) { if (typeof element === 'number') { - byteLength += 1 - const byte = Buffer.alloc(1) - byte.writeUInt8(element) - buffers[index] = byte + byteLength += 1; + const byte = Buffer.alloc(1); + byte.writeUInt8(element); + buffers[index] = byte; } else { - byteLength += element.byteLength - buffers[index] = element + byteLength += element.byteLength; + buffers[index] = element; } } - return Buffer.concat(buffers, byteLength) + + return Buffer.concat(buffers, byteLength); } -export function encode (serializerVersion, rootRecord, usedPlugins) { - const buffers = [] - let byteOffset = 0 +export function encode(serializerVersion, rootRecord, usedPlugins) { + const buffers = []; + let byteOffset = 0; - const versionHeader = Buffer.alloc(2) - versionHeader.writeUInt16LE(serializerVersion) - buffers.push(versionHeader) - byteOffset += versionHeader.byteLength + const versionHeader = Buffer.alloc(2); + versionHeader.writeUInt16LE(serializerVersion); + buffers.push(versionHeader); + byteOffset += versionHeader.byteLength; - const rootOffset = Buffer.alloc(4) - buffers.push(rootOffset) - byteOffset += rootOffset.byteLength + const rootOffset = Buffer.alloc(4); + buffers.push(rootOffset); + byteOffset += rootOffset.byteLength; - const numPlugins = buildBuffer(encodeValue(usedPlugins.size)) - buffers.push(numPlugins) - byteOffset += numPlugins.byteLength + const numberPlugins = buildBuffer(encodeValue(usedPlugins.size)); + buffers.push(numberPlugins); + byteOffset += numberPlugins.byteLength; for (const name of usedPlugins.keys()) { - const plugin = usedPlugins.get(name) + const plugin = usedPlugins.get(name); const record = buildBuffer([ encodeValue(name), encodeValue(plugin.serializerVersion), - ]) - buffers.push(record) - byteOffset += record.byteLength + ]); + buffers.push(record); + byteOffset += record.byteLength; } - const queue = [rootRecord] - const pointers = [rootOffset] + const queue = [rootRecord]; + const pointers = [rootOffset]; while (queue.length > 0) { - pointers.shift().writeUInt32LE(byteOffset, 0) + pointers.shift().writeUInt32LE(byteOffset, 0); - const record = queue.shift() + const record = queue.shift(); const recordHeader = buildBuffer([ encodeValue(record.pluginIndex), encodeValue(record.id), encodeValue(record.children.length), - ]) - buffers.push(recordHeader) - byteOffset += recordHeader.byteLength + ]); + buffers.push(recordHeader); + byteOffset += recordHeader.byteLength; // Add pointers before encoding the state. This allows, if it ever becomes // necessary, for records to be extracted from a buffer without having to // parse the (variable length) state field. for (const child of record.children) { - queue.push(child) + queue.push(child); - const pointer = Buffer.alloc(4) - pointers.push(pointer) - buffers.push(pointer) - byteOffset += 4 + const pointer = Buffer.alloc(4); + pointers.push(pointer); + buffers.push(pointer); + byteOffset += 4; } - const state = buildBuffer(encodeValue(record.state)) - buffers.push(state) - byteOffset += state.byteLength + const state = buildBuffer(encodeValue(record.state)); + buffers.push(state); + byteOffset += state.byteLength; } - return Buffer.concat(buffers, byteOffset) + return Buffer.concat(buffers, byteOffset); } -export function decodePlugins (buffer) { - const $numPlugins = decodeValue(buffer, 0) - let byteOffset = $numPlugins.byteOffset +export function decodePlugins(buffer) { + const $numberPlugins = decodeValue(buffer, 0); + let {byteOffset} = $numberPlugins; - const usedPlugins = new Map() - const lastIndex = $numPlugins.value + const usedPlugins = new Map(); + const lastIndex = $numberPlugins.value; for (let index = 1; index <= lastIndex; index++) { - const $name = decodeValue(buffer, byteOffset) - const name = $name.value - byteOffset = $name.byteOffset + const $name = decodeValue(buffer, byteOffset); + const name = $name.value; + byteOffset = $name.byteOffset; - const serializerVersion = decodeValue(buffer, byteOffset).value - usedPlugins.set(index, { name, serializerVersion }) + const serializerVersion = decodeValue(buffer, byteOffset).value; + usedPlugins.set(index, {name, serializerVersion}); } - return usedPlugins + return usedPlugins; } -export function decodeRecord (buffer, byteOffset) { - const $pluginIndex = decodeValue(buffer, byteOffset) - const pluginIndex = $pluginIndex.value - byteOffset = $pluginIndex.byteOffset +export function decodeRecord(buffer, byteOffset) { + const $pluginIndex = decodeValue(buffer, byteOffset); + const pluginIndex = $pluginIndex.value; + byteOffset = $pluginIndex.byteOffset; - const $id = decodeValue(buffer, byteOffset) - const id = $id.value - byteOffset = $id.byteOffset + const $id = decodeValue(buffer, byteOffset); + const id = $id.value; + byteOffset = $id.byteOffset; - const $numPointers = decodeValue(buffer, byteOffset) - const numPointers = $numPointers.value - byteOffset = $numPointers.byteOffset + const $numberPointers = decodeValue(buffer, byteOffset); + const numberPointers = $numberPointers.value; + byteOffset = $numberPointers.byteOffset; - const pointerAddresses = new Array(numPointers) - for (let index = 0; index < numPointers; index++) { - pointerAddresses[index] = buffer.readUInt32LE(byteOffset) - byteOffset += 4 + const pointerAddresses = Array.from({length: numberPointers}); + for (let index = 0; index < numberPointers; index++) { + pointerAddresses[index] = buffer.readUInt32LE(byteOffset); + byteOffset += 4; } - const state = decodeValue(buffer, byteOffset).value - return { id, pluginIndex, state, pointerAddresses } + const state = decodeValue(buffer, byteOffset).value; + return {id, pluginIndex, state, pointerAddresses}; } -export function extractVersion (buffer) { - return buffer.readUInt16LE(0) +export function extractVersion(buffer) { + return buffer.readUInt16LE(0); } -export function decode (buffer) { - const rootOffset = buffer.readUInt32LE(2) - const pluginBuffer = buffer.slice(6, rootOffset) - const rootRecord = decodeRecord(buffer, rootOffset) - return { pluginBuffer, rootRecord } +export function decode(buffer) { + const rootOffset = buffer.readUInt32LE(2); + const pluginBuffer = buffer.slice(6, rootOffset); + const rootRecord = decodeRecord(buffer, rootOffset); + return {pluginBuffer, rootRecord}; } diff --git a/lib/format.js b/lib/format.js index 06dc9b2..7e909d1 100644 --- a/lib/format.js +++ b/lib/format.js @@ -1,55 +1,57 @@ -import Circular from './Circular.js' -import Indenter from './Indenter.js' -import describe from './describe.js' -import lineBuilder from './lineBuilder.js' -import * as themeUtils from './themeUtils.js' +import Circular from './Circular.js'; +import Indenter from './Indenter.js'; +import describe from './describe.js'; +import lineBuilder from './lineBuilder.js'; +import * as themeUtils from './themeUtils.js'; -const alwaysFormat = () => true -const fixedIndent = new Indenter(0, ' ') +const alwaysFormat = () => true; +const fixedIndent = new Indenter(0, ' '); -export function formatDescriptor (subject, options) { - const theme = themeUtils.normalize(options) +// eslint-disable-next-line complexity +export function formatDescriptor(subject, options) { + const theme = themeUtils.normalize(options); if (subject.isPrimitive === true) { - const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), fixedIndent) - return formatted.toString({ diff: false }) + const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), fixedIndent); + return formatted.toString({diff: false}); } - const circular = new Circular() - const maxDepth = (options && options.maxDepth) || 0 + const circular = new Circular(); + const maxDepth = (options && options.maxDepth) || 0; - let indent = fixedIndent + let indent = fixedIndent; - const buffer = lineBuilder.buffer() - const stack = [] - let topIndex = -1 + const buffer = lineBuilder.buffer(); + const stack = []; + let topIndex = -1; do { if (circular.has(subject)) { - stack[topIndex].formatter.append(lineBuilder.single(theme.circular), subject) + stack[topIndex].formatter.append(lineBuilder.single(theme.circular), subject); } else { - let didFormat = false + let didFormat = false; if (typeof subject.formatDeep === 'function') { - const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent) + const formatted = subject.formatDeep(themeUtils.applyModifiers(subject, theme), indent); if (formatted !== null) { - didFormat = true + didFormat = true; + // eslint-disable-next-line max-depth if (topIndex === -1) { - buffer.append(formatted) + buffer.append(formatted); } else { - stack[topIndex].formatter.append(formatted, subject) + stack[topIndex].formatter.append(formatted, subject); } } } if (!didFormat && typeof subject.formatShallow === 'function') { - const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent) - const recursor = subject.createRecursor() + const formatter = subject.formatShallow(themeUtils.applyModifiers(subject, theme), indent); + const recursor = subject.createRecursor(); if (formatter.increaseIndent && maxDepth > 0 && indent.level === maxDepth) { - const isEmpty = recursor() === null + const isEmpty = recursor() === null; const formatted = !isEmpty && typeof formatter.maxDepth === 'function' ? formatter.maxDepth() - : formatter.finalize() - stack[topIndex].formatter.append(formatted, subject) + : formatter.finalize(); + stack[topIndex].formatter.append(formatted, subject); } else { stack.push({ formatter, @@ -57,41 +59,48 @@ export function formatDescriptor (subject, options) { decreaseIndent: formatter.increaseIndent, shouldFormat: formatter.shouldFormat || alwaysFormat, subject, - }) - topIndex++ + }); + topIndex++; - if (formatter.increaseIndent) indent = indent.increase() - circular.add(subject) + // eslint-disable-next-line max-depth + if (formatter.increaseIndent) { + indent = indent.increase(); + } + + circular.add(subject); } } } while (topIndex >= 0) { do { - subject = stack[topIndex].recursor() - } while (subject && !stack[topIndex].shouldFormat(subject)) + subject = stack[topIndex].recursor(); + } while (subject && !stack[topIndex].shouldFormat(subject)); if (subject) { - break + break; + } + + const record = stack.pop(); + topIndex--; + if (record.decreaseIndent) { + indent = indent.decrease(); } - const record = stack.pop() - topIndex-- - if (record.decreaseIndent) indent = indent.decrease() - circular.delete(record.subject) + circular.delete(record.subject); - const formatted = record.formatter.finalize() + const formatted = record.formatter.finalize(); if (topIndex === -1) { - buffer.append(formatted) + buffer.append(formatted); } else { - stack[topIndex].formatter.append(formatted, record.subject) + stack[topIndex].formatter.append(formatted, record.subject); } } - } while (topIndex >= 0) + } while (topIndex >= 0); - return buffer.toString({ diff: false }) + return buffer.toString({diff: false}); } -export function format (value, options) { - return formatDescriptor(describe(value, options), options) +export function format(value, options) { + return formatDescriptor(describe(value, options), options); } diff --git a/lib/formatUtils.js b/lib/formatUtils.js index 11a7a0d..fcaad29 100644 --- a/lib/formatUtils.js +++ b/lib/formatUtils.js @@ -1,117 +1,128 @@ -import lineBuilder from './lineBuilder.js' +import lineBuilder from './lineBuilder.js'; -export function wrap (fromTheme, value) { - return fromTheme.open + value + fromTheme.close +export function wrap(fromTheme, value) { + return fromTheme.open + value + fromTheme.close; } -export function formatCtorAndStringTag (theme, object) { - if (!object.ctor) return wrap(theme.object.stringTag, object.stringTag) +export function formatCtorAndStringTag(theme, object) { + if (!object.ctor) { + return wrap(theme.object.stringTag, object.stringTag); + } - let retval = wrap(theme.object.ctor, object.ctor) + let retval = wrap(theme.object.ctor, object.ctor); if (object.stringTag && object.stringTag !== object.ctor && object.stringTag !== 'Object') { - retval += ' ' + wrap(theme.object.secondaryStringTag, object.stringTag) + retval += ' ' + wrap(theme.object.secondaryStringTag, object.stringTag); } - return retval + + return retval; } export class ObjectFormatter { - constructor (object, theme, indent) { - this.object = object - this.theme = theme - this.indent = indent + constructor(object, theme, indent) { + this.object = object; + this.theme = theme; + this.indent = indent; - this.increaseIndent = true + this.increaseIndent = true; - this.innerLines = lineBuilder.buffer() - this.pendingStats = null + this.innerLines = lineBuilder.buffer(); + this.pendingStats = null; } - append (formatted, origin) { + append(formatted, origin) { if (origin.isStats === true) { - this.pendingStats = formatted + this.pendingStats = formatted; } else { if (this.pendingStats !== null) { if (!this.innerLines.isEmpty) { - this.innerLines.append(this.pendingStats) + this.innerLines.append(this.pendingStats); } - this.pendingStats = null + + this.pendingStats = null; } - this.innerLines.append(formatted) + + this.innerLines.append(formatted); } } - finalize () { + finalize() { const variant = this.object.isList ? this.theme.list - : this.theme.object + : this.theme.object; - const ctor = this.object.ctor - const stringTag = this.object.stringTag + const {ctor} = this.object; + const {stringTag} = this.object; const prefix = (ctor === 'Array' || ctor === 'Object') && ctor === stringTag ? '' - : formatCtorAndStringTag(this.theme, this.object) + ' ' + : formatCtorAndStringTag(this.theme, this.object) + ' '; if (this.innerLines.isEmpty) { - return lineBuilder.single(prefix + variant.openBracket + variant.closeBracket) + return lineBuilder.single(prefix + variant.openBracket + variant.closeBracket); } return lineBuilder.first(prefix + variant.openBracket) - .concat(this.innerLines.withFirstPrefixed(this.indent.increase()).stripFlags()) - .append(lineBuilder.last(this.indent + variant.closeBracket)) + .concat(this.innerLines.withFirstPrefixed(this.indent.increase()).stripFlags()) // eslint-disable-line unicorn/prefer-spread + .append(lineBuilder.last(this.indent + variant.closeBracket)); } - maxDepth () { + maxDepth() { const variant = this.object.isList ? this.theme.list - : this.theme.object + : this.theme.object; return lineBuilder.single( - formatCtorAndStringTag(this.theme, this.object) + ' ' + variant.openBracket + - ' ' + this.theme.maxDepth + ' ' + variant.closeBracket) + formatCtorAndStringTag(this.theme, this.object) + ' ' + variant.openBracket + + ' ' + this.theme.maxDepth + ' ' + variant.closeBracket); } - shouldFormat () { - return true + shouldFormat() { + return true; } - customize (methods) { + customize(methods) { if (methods.finalize) { - this.finalize = () => methods.finalize(this.innerLines) + this.finalize = () => methods.finalize(this.innerLines); } + if (methods.maxDepth) { - this.maxDepth = methods.maxDepth + this.maxDepth = methods.maxDepth; } + if (methods.shouldFormat) { - this.shouldFormat = methods.shouldFormat + this.shouldFormat = methods.shouldFormat; } - return this + return this; } } export class SingleValueFormatter { - constructor (theme, finalizeFn, increaseIndent) { - this.theme = theme - this.finalizeFn = finalizeFn - this.hasValue = false - this.increaseIndent = increaseIndent === true - this.value = null + constructor(theme, finalizeFn, increaseIndent) { + this.theme = theme; + this.finalizeFn = finalizeFn; + this.hasValue = false; + this.increaseIndent = increaseIndent === true; + this.value = null; } - append (formatted) { - if (this.hasValue) throw new Error('Formatter buffer can only take one formatted value.') + append(formatted) { + if (this.hasValue) { + throw new Error('Formatter buffer can only take one formatted value.'); + } - this.hasValue = true - this.value = formatted + this.hasValue = true; + this.value = formatted; } - finalize () { - if (!this.hasValue) throw new Error('Formatter buffer never received a formatted value.') + finalize() { + if (!this.hasValue) { + throw new Error('Formatter buffer never received a formatted value.'); + } - return this.finalizeFn(this.value) + return this.finalizeFn(this.value); } - maxDepth () { - return this.finalizeFn(lineBuilder.single(this.theme.maxDepth)) + maxDepth() { + return this.finalizeFn(lineBuilder.single(this.theme.maxDepth)); } } diff --git a/lib/getCtor.js b/lib/getCtor.js index 244708e..80d9fb8 100644 --- a/lib/getCtor.js +++ b/lib/getCtor.js @@ -1,13 +1,15 @@ -export default function getCtor (stringTag, value) { +export default function getCtor(stringTag, value) { if (value.constructor) { - const name = value.constructor.name + const {name} = value.constructor; return typeof name === 'string' && name !== '' ? name - : null + : null; } if (value.constructor === undefined) { - if (stringTag !== 'Object' || value instanceof Object) return null + if (stringTag !== 'Object' || value instanceof Object) { + return null; + } // Values without a constructor, that do not inherit from `Object`, but are // tagged as objects, may come from `Object.create(null)`. Or they can come @@ -30,10 +32,13 @@ export default function getCtor (stringTag, value) { // Using `const` prevents Crankshaft optimizations for (var p in value) { // eslint-disable-line no-var - if (!Object.hasOwn(value, p)) return null + if (!Object.hasOwn(value, p)) { + return null; + } } - return stringTag + + return stringTag; } - return null + return null; } diff --git a/lib/getObjectKeys.js b/lib/getObjectKeys.js index 6f3c521..0fd0161 100644 --- a/lib/getObjectKeys.js +++ b/lib/getObjectKeys.js @@ -1,32 +1,32 @@ import isEnumerable from './isEnumerable.js'; -export default function getObjectKeys (obj, excludeListItemAccessorsBelowLength) { - const keys = [] - let size = 0 +export default function getObjectKeys(object, excludeListItemAccessorsBelowLength) { + const keys = []; + let size = 0; // Sort property names, they should never be order-sensitive - const nameCandidates = Object.getOwnPropertyNames(obj).sort() + const nameCandidates = Object.getOwnPropertyNames(object).sort(); // Comparators should verify symbols in an order-insensitive manner if // possible. - const symbolCandidates = Object.getOwnPropertySymbols(obj) + const symbolCandidates = Object.getOwnPropertySymbols(object); for (const name of nameCandidates) { - let accept = true + let accept = true; if (excludeListItemAccessorsBelowLength > 0) { - const index = Number(name) - accept = !Number.isInteger(index) || index < 0 || index >= excludeListItemAccessorsBelowLength + const index = Number(name); + accept = !Number.isInteger(index) || index < 0 || index >= excludeListItemAccessorsBelowLength; } - if (accept && isEnumerable(obj, name)) { - keys[size++] = name + if (accept && isEnumerable(object, name)) { + keys[size++] = name; } } for (const symbol of symbolCandidates) { - if (isEnumerable(obj, symbol)) { - keys[size++] = symbol + if (isEnumerable(object, symbol)) { + keys[size++] = symbol; } } - return { keys, size } + return {keys, size}; } diff --git a/lib/getStringTag.js b/lib/getStringTag.js index c3b8d6e..d394ed2 100644 --- a/lib/getStringTag.js +++ b/lib/getStringTag.js @@ -1,27 +1,29 @@ -const ts = Object.prototype.toString -function getStringTag (value) { - return ts.call(value).slice(8, -1) +const ts = Object.prototype.toString; +function getStringTag(value) { + return ts.call(value).slice(8, -1); } -const fts = Function.prototype.toString -const promiseCtorString = fts.call(Promise) +const fts = Function.prototype.toString; +const promiseCtorString = fts.call(Promise); const isPromise = value => { - if (!value.constructor) return false + if (!value.constructor) { + return false; + } try { - return fts.call(value.constructor) === promiseCtorString + return fts.call(value.constructor) === promiseCtorString; } catch { - return false + return false; } -} +}; const getStringTagWithPromiseWorkaround = value => { - const stringTag = getStringTag(value) + const stringTag = getStringTag(value); return stringTag === 'Object' && isPromise(value) ? 'Promise' - : stringTag -} + : stringTag; +}; export default getStringTag(Promise.resolve()) === 'Promise' ? getStringTag - : getStringTagWithPromiseWorkaround + : getStringTagWithPromiseWorkaround; diff --git a/lib/hasLength.js b/lib/hasLength.js index e0b96a8..ab4594f 100644 --- a/lib/hasLength.js +++ b/lib/hasLength.js @@ -1,10 +1,10 @@ -import {isLength} from './lodash/index.js' +import {isLength} from './lodash/index.js'; -export default function hasLength (obj) { +export default function hasLength(object) { return ( - Array.isArray(obj) || - (Object.hasOwn(obj, 'length') && - isLength(obj.length) && - (obj.length === 0 || '0' in obj)) - ) + Array.isArray(object) + || (Object.hasOwn(object, 'length') + && isLength(object.length) + && (object.length === 0 || '0' in object)) + ); } diff --git a/lib/isEnumerable.js b/lib/isEnumerable.js index 3eab205..07f75be 100644 --- a/lib/isEnumerable.js +++ b/lib/isEnumerable.js @@ -1,4 +1,4 @@ -export default function isEnumerable (obj, key) { - const desc = Object.getOwnPropertyDescriptor(obj, key) - return desc && desc.enumerable +export default function isEnumerable(object, key) { + const desc = Object.getOwnPropertyDescriptor(object, key); + return desc && desc.enumerable; } diff --git a/lib/lineBuilder.js b/lib/lineBuilder.js index 2110631..6a81f2f 100644 --- a/lib/lineBuilder.js +++ b/lib/lineBuilder.js @@ -1,309 +1,342 @@ -const ACTUAL = Symbol('lineBuilder.gutters.ACTUAL') -const EXPECTED = Symbol('lineBuilder.gutters.EXPECTED') +const ACTUAL = Symbol('lineBuilder.gutters.ACTUAL'); +const EXPECTED = Symbol('lineBuilder.gutters.EXPECTED'); -function translateGutter (theme, invert, gutter) { +function translateGutter(theme, invert, gutter) { if (invert) { - if (gutter === ACTUAL) return theme.diffGutters.expected - if (gutter === EXPECTED) return theme.diffGutters.actual + if (gutter === ACTUAL) { + return theme.diffGutters.expected; + } + + if (gutter === EXPECTED) { + return theme.diffGutters.actual; + } } else { - if (gutter === ACTUAL) return theme.diffGutters.actual - if (gutter === EXPECTED) return theme.diffGutters.expected + if (gutter === ACTUAL) { + return theme.diffGutters.actual; + } + + if (gutter === EXPECTED) { + return theme.diffGutters.expected; + } } - return theme.diffGutters.padding + + return theme.diffGutters.padding; } class Line { - constructor (isFirst, isLast, gutter, stringValue) { - this.isFirst = isFirst - this.isLast = isLast - this.gutter = gutter - this.stringValue = stringValue + constructor(isFirst, isLast, gutter, stringValue) { + this.isFirst = isFirst; + this.isLast = isLast; + this.gutter = gutter; + this.stringValue = stringValue; } - * [Symbol.iterator] () { - yield this + * [Symbol.iterator]() { + yield this; } - get isEmpty () { - return false + get isEmpty() { + return false; } - get hasGutter () { - return this.gutter !== null + get hasGutter() { + return this.gutter !== null; } - get isSingle () { - return this.isFirst && this.isLast + get isSingle() { + return this.isFirst && this.isLast; } - append (other) { - return this.concat(other) + append(other) { + // eslint-disable-next-line unicorn/prefer-spread + return this.concat(other); } - concat (other) { + concat(other) { return new Collection() .append(this) - .append(other) + .append(other); } - toString (options) { - if (options.diff === false) return this.stringValue + toString(options) { + if (options.diff === false) { + return this.stringValue; + } - return translateGutter(options.theme, options.invert, this.gutter) + this.stringValue + return translateGutter(options.theme, options.invert, this.gutter) + this.stringValue; } - mergeWithInfix (infix, other) { + mergeWithInfix(infix, other) { if (other.isLine !== true) { return new Collection() .append(this) - .mergeWithInfix(infix, other) + .mergeWithInfix(infix, other); } - return new Line(this.isFirst, other.isLast, other.gutter, this.stringValue + infix + other.stringValue) + return new Line(this.isFirst, other.isLast, other.gutter, this.stringValue + infix + other.stringValue); } - withFirstPrefixed (prefix) { - if (!this.isFirst) return this + withFirstPrefixed(prefix) { + if (!this.isFirst) { + return this; + } - return new Line(true, this.isLast, this.gutter, prefix + this.stringValue) + return new Line(true, this.isLast, this.gutter, prefix + this.stringValue); } - withLastPostfixed (postfix) { - if (!this.isLast) return this + withLastPostfixed(postfix) { + if (!this.isLast) { + return this; + } - return new Line(this.isFirst, true, this.gutter, this.stringValue + postfix) + return new Line(this.isFirst, true, this.gutter, this.stringValue + postfix); } - stripFlags () { - return new Line(false, false, this.gutter, this.stringValue) + stripFlags() { + return new Line(false, false, this.gutter, this.stringValue); } - decompose () { + decompose() { return new Collection() .append(this) - .decompose() + .decompose(); } - isLine = true + isLine = true; } class Collection { - constructor () { - this.buffer = [] + constructor() { + this.buffer = []; } - * [Symbol.iterator] () { + * [Symbol.iterator]() { for (const appended of this.buffer) { - for (const line of appended) yield line + for (const line of appended) { + yield line; + } } } - get isEmpty () { - return this.buffer.length === 0 + get isEmpty() { + return this.buffer.length === 0; } - get hasGutter () { + get hasGutter() { for (const line of this) { - if (line.hasGutter) return true + if (line.hasGutter) { + return true; + } } - return false + + return false; } - get isSingle () { - const iterator = this[Symbol.iterator]() - iterator.next() - return iterator.next().done === true + get isSingle() { + const iterator = this[Symbol.iterator](); + iterator.next(); + return iterator.next().done === true; } - append (lineOrLines) { - if (!lineOrLines.isEmpty) this.buffer.push(lineOrLines) - return this + append(lineOrLines) { + if (!lineOrLines.isEmpty) { + this.buffer.push(lineOrLines); + } + + return this; } - concat (other) { + concat(other) { return new Collection() .append(this) - .append(other) + .append(other); } - toString (options) { - let lines = this + toString(options) { + // eslint-disable-next-line unicorn/no-this-assignment + let lines = this; if (options.invert) { - lines = new Collection() - let buffer = new Collection() + lines = new Collection(); + let buffer = new Collection(); - let prev = null + let previous = null; for (const line of this) { if (line.gutter === ACTUAL) { - if (prev !== null && prev.gutter !== ACTUAL && !buffer.isEmpty) { - lines.append(buffer) - buffer = new Collection() + if (previous !== null && previous.gutter !== ACTUAL && !buffer.isEmpty) { + lines.append(buffer); + buffer = new Collection(); } - buffer.append(line) + buffer.append(line); } else if (line.gutter === EXPECTED) { - lines.append(line) + lines.append(line); } else { if (!buffer.isEmpty) { - lines.append(buffer) - buffer = new Collection() + lines.append(buffer); + buffer = new Collection(); } - lines.append(line) + lines.append(line); } - prev = line + previous = line; } - lines.append(buffer) + + lines.append(buffer); } - return Array.from(lines, line => line.toString(options)).join('\n') + return Array.from(lines, line => line.toString(options)).join('\n'); } - mergeWithInfix (infix, from) { - if (from.isEmpty) throw new Error('Cannot merge, `from` is empty.') + mergeWithInfix(infix, from) { + if (from.isEmpty) { + throw new Error('Cannot merge, `from` is empty.'); + } - const otherLines = Array.from(from) - if (!otherLines[0].isFirst) throw new Error('Cannot merge, `from` has no first line.') + const otherLines = [...from]; + if (!otherLines[0].isFirst) { + throw new Error('Cannot merge, `from` has no first line.'); + } - const merged = new Collection() - let seenLast = false + const merged = new Collection(); + let seenLast = false; for (const line of this) { - if (seenLast) throw new Error('Cannot merge line, the last line has already been seen.') + if (seenLast) { + throw new Error('Cannot merge line, the last line has already been seen.'); + } if (!line.isLast) { - merged.append(line) - continue + merged.append(line); + continue; } - seenLast = true + seenLast = true; for (const other of otherLines) { if (other.isFirst) { - merged.append(line.mergeWithInfix(infix, other)) + merged.append(line.mergeWithInfix(infix, other)); } else { - merged.append(other) + merged.append(other); } } } - return merged + + return merged; } - withFirstPrefixed (prefix) { + withFirstPrefixed(prefix) { return new Collection() - .append(Array.from(this, line => line.withFirstPrefixed(prefix))) + .append(Array.from(this, line => line.withFirstPrefixed(prefix))); } - withLastPostfixed (postfix) { + withLastPostfixed(postfix) { return new Collection() - .append(Array.from(this, line => line.withLastPostfixed(postfix))) + .append(Array.from(this, line => line.withLastPostfixed(postfix))); } - stripFlags () { + stripFlags() { return new Collection() - .append(Array.from(this, line => line.stripFlags())) + .append(Array.from(this, line => line.stripFlags())); } - decompose () { - const first = { actual: new Collection(), expected: new Collection() } - const last = { actual: new Collection(), expected: new Collection() } - const remaining = new Collection() + decompose() { + const first = {actual: new Collection(), expected: new Collection()}; + const last = {actual: new Collection(), expected: new Collection()}; + const remaining = new Collection(); for (const line of this) { if (line.isFirst && line.gutter === ACTUAL) { - first.actual.append(line) + first.actual.append(line); } else if (line.isFirst && line.gutter === EXPECTED) { - first.expected.append(line) + first.expected.append(line); } else if (line.isLast && line.gutter === ACTUAL) { - last.actual.append(line) + last.actual.append(line); } else if (line.isLast && line.gutter === EXPECTED) { - last.expected.append(line) + last.expected.append(line); } else { - remaining.append(line) + remaining.append(line); } } - return { first, last, remaining } + return {first, last, remaining}; } - isCollection = true + isCollection = true; } -function setDefaultGutter (iterable, gutter) { +function setDefaultGutter(iterable, gutter) { return new Collection() - .append(Array.from(iterable, line => { - return line.gutter === null - ? new Line(line.isFirst, line.isLast, gutter, line.stringValue) - : line - })) + .append(Array.from(iterable, line => line.gutter === null + ? new Line(line.isFirst, line.isLast, gutter, line.stringValue) + : line)); } export default { - buffer () { - return new Collection() + buffer() { + return new Collection(); }, - first (stringValue) { - return new Line(true, false, null, stringValue) + first(stringValue) { + return new Line(true, false, null, stringValue); }, - last (stringValue) { - return new Line(false, true, null, stringValue) + last(stringValue) { + return new Line(false, true, null, stringValue); }, - line (stringValue) { - return new Line(false, false, null, stringValue) + line(stringValue) { + return new Line(false, false, null, stringValue); }, - single (stringValue) { - return new Line(true, true, null, stringValue) + single(stringValue) { + return new Line(true, true, null, stringValue); }, - setDefaultGutter (lineOrCollection) { - return lineOrCollection + setDefaultGutter(lineOrCollection) { + return lineOrCollection; }, actual: { - first (stringValue) { - return new Line(true, false, ACTUAL, stringValue) + first(stringValue) { + return new Line(true, false, ACTUAL, stringValue); }, - last (stringValue) { - return new Line(false, true, ACTUAL, stringValue) + last(stringValue) { + return new Line(false, true, ACTUAL, stringValue); }, - line (stringValue) { - return new Line(false, false, ACTUAL, stringValue) + line(stringValue) { + return new Line(false, false, ACTUAL, stringValue); }, - single (stringValue) { - return new Line(true, true, ACTUAL, stringValue) + single(stringValue) { + return new Line(true, true, ACTUAL, stringValue); }, - setDefaultGutter (lineOrCollection) { - return setDefaultGutter(lineOrCollection, ACTUAL) + setDefaultGutter(lineOrCollection) { + return setDefaultGutter(lineOrCollection, ACTUAL); }, }, expected: { - first (stringValue) { - return new Line(true, false, EXPECTED, stringValue) + first(stringValue) { + return new Line(true, false, EXPECTED, stringValue); }, - last (stringValue) { - return new Line(false, true, EXPECTED, stringValue) + last(stringValue) { + return new Line(false, true, EXPECTED, stringValue); }, - line (stringValue) { - return new Line(false, false, EXPECTED, stringValue) + line(stringValue) { + return new Line(false, false, EXPECTED, stringValue); }, - single (stringValue) { - return new Line(true, true, EXPECTED, stringValue) + single(stringValue) { + return new Line(true, true, EXPECTED, stringValue); }, - setDefaultGutter (lineOrCollection) { - return setDefaultGutter(lineOrCollection, EXPECTED) + setDefaultGutter(lineOrCollection) { + return setDefaultGutter(lineOrCollection, EXPECTED); }, }, -} +}; diff --git a/lib/metaDescriptors/item.js b/lib/metaDescriptors/item.js index e11d083..2964cc6 100644 --- a/lib/metaDescriptors/item.js +++ b/lib/metaDescriptors/item.js @@ -1,93 +1,96 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import * as recursorUtils from '../recursorUtils.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import * as recursorUtils from '../recursorUtils.js'; -export function describeComplex (index, value) { - return new ComplexItem(index, value) +export function describeComplex(index, value) { + return new ComplexItem(index, value); } -export function deserializeComplex (index, recursor) { - const value = recursor() - return new ComplexItem(index, value) +export function deserializeComplex(index, recursor) { + const value = recursor(); + return new ComplexItem(index, value); } -export function describePrimitive (index, value) { - return new PrimitiveItem(index, value) +export function describePrimitive(index, value) { + return new PrimitiveItem(index, value); } -export function deserializePrimitive (state) { - const index = state[0] - const value = state[1] - return new PrimitiveItem(index, value) +export function deserializePrimitive(state) { + const index = state[0]; + const value = state[1]; + return new PrimitiveItem(index, value); } -export const complexTag = Symbol('ComplexItem') +export const complexTag = Symbol('ComplexItem'); -export const primitiveTag = Symbol('PrimitiveItem') +export const primitiveTag = Symbol('PrimitiveItem'); class ComplexItem { - constructor (index, value) { - this.index = index - this.value = value + constructor(index, value) { + this.index = index; + this.value = value; } - createRecursor () { - return recursorUtils.singleValue(this.value) + createRecursor() { + return recursorUtils.singleValue(this.value); } - compare (expected) { + compare(expected) { return expected.tag === complexTag && this.index === expected.index ? this.value.compare(expected.value) - : UNEQUAL + : UNEQUAL; } - formatShallow (theme, indent) { - const increaseValueIndent = theme.item.increaseValueIndent === true + formatShallow(theme, indent) { + const increaseValueIndent = theme.item.increaseValueIndent === true; return new formatUtils.SingleValueFormatter(theme, value => { if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, value) + return theme.item.customFormat(theme, indent, value); } - return value.withLastPostfixed(theme.item.after) - }, increaseValueIndent) + return value.withLastPostfixed(theme.item.after); + }, increaseValueIndent); } - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // eslint-disable-next-line max-params, complexity + prepareDiff(expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + if (isCircular(this.value) || isCircular(expected.value)) { + return {compareResult: UNEQUAL}; + } // Try to line up this or remaining items with the expected items. - const lhsFork = recursorUtils.fork(lhsRecursor) - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected + const lhsFork = recursorUtils.fork(lhsRecursor); + const rhsFork = recursorUtils.fork(rhsRecursor); + const initialExpected = expected; - let expectedIsMissing = false + let expectedIsMissing = false; while (!expectedIsMissing && expected !== null && expected.isItem === true) { if (expected.tag === complexTag) { - expectedIsMissing = compareComplexShape(this.value, expected.value) !== UNEQUAL + expectedIsMissing = compareComplexShape(this.value, expected.value) !== UNEQUAL; } - expected = rhsFork.shared() + expected = rhsFork.shared(); } - let actualIsExtraneous = false + let actualIsExtraneous = false; if (initialExpected.tag === complexTag) { - let actual = this + let actual = this; // eslint-disable-line unicorn/no-this-assignment while (!actualIsExtraneous && actual !== null && actual.isItem === true) { if (actual.tag === complexTag) { - actualIsExtraneous = compareComplexShape(actual.value, initialExpected.value) !== UNEQUAL + actualIsExtraneous = compareComplexShape(actual.value, initialExpected.value) !== UNEQUAL; } - actual = lhsFork.shared() + actual = lhsFork.shared(); } } else if (initialExpected.tag === primitiveTag) { - let actual = this + let actual = this; // eslint-disable-line unicorn/no-this-assignment while (!actualIsExtraneous && actual !== null && actual.isItem === true) { if (actual.tag === primitiveTag) { - actualIsExtraneous = initialExpected.value.compare(actual.value) === DEEP_EQUAL + actualIsExtraneous = initialExpected.value.compare(actual.value) === DEEP_EQUAL; } - actual = lhsFork.shared() + actual = lhsFork.shared(); } } @@ -98,12 +101,14 @@ class ComplexItem { rhsRecursor: recursorUtils.map( recursorUtils.unshift(rhsFork.recursor, initialExpected), next => { - if (next.isItem !== true) return next + if (next.isItem !== true) { + return next; + } - next.index++ - return next + next.index++; + return next; }), - } + }; } if (expectedIsMissing && !actualIsExtraneous) { @@ -112,77 +117,82 @@ class ComplexItem { lhsRecursor: recursorUtils.map( recursorUtils.unshift(lhsFork.recursor, this), next => { - if (next.isItem !== true) return next + if (next.isItem !== true) { + return next; + } - next.index++ - return next + next.index++; + return next; }), rhsRecursor: rhsFork.recursor, - } + }; } - const mustRecurse = this.tag === complexTag && initialExpected.tag === complexTag && - this.value.compare(initialExpected.value) !== UNEQUAL + const mustRecurse = this.tag === complexTag && initialExpected.tag === complexTag + && this.value.compare(initialExpected.value) !== UNEQUAL; return { mustRecurse, isUnequal: !mustRecurse, lhsRecursor: lhsFork.recursor, rhsRecursor: rhsFork.recursor, - } + }; } - serialize () { - return this.index + serialize() { + return this.index; } - isItem = true + isItem = true; - tag = complexTag + tag = complexTag; } class PrimitiveItem { - constructor (index, value) { - this.index = index - this.value = value + constructor(index, value) { + this.index = index; + this.value = value; } - compare (expected) { + compare(expected) { return expected.tag === primitiveTag && this.index === expected.index ? this.value.compare(expected.value) - : UNEQUAL + : UNEQUAL; } - formatDeep (theme, indent) { - const increaseValueIndent = theme.item.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent + formatDeep(theme, indent) { + const increaseValueIndent = theme.item.increaseValueIndent === true; + const valueIndent = increaseValueIndent ? indent.increase() : indent; // Since the value is formatted directly, modifiers are not applied. Apply // modifiers to the item descriptor instead. - const formatted = this.value.formatDeep(theme, valueIndent) + const formatted = this.value.formatDeep(theme, valueIndent); if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, formatted) + return theme.item.customFormat(theme, indent, formatted); } - return formatted.withLastPostfixed(theme.item.after) + return formatted.withLastPostfixed(theme.item.after); } - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { - const compareResult = this.compare(expected) + // eslint-disable-next-line max-params + prepareDiff(expected, lhsRecursor, rhsRecursor, _compareComplexShape, _isCircular) { + const compareResult = this.compare(expected); // Short-circuit when values are deeply equal. - if (compareResult === DEEP_EQUAL) return { compareResult } + if (compareResult === DEEP_EQUAL) { + return {compareResult}; + } // Short-circut when values can be diffed directly. if ( - expected.tag === primitiveTag && - this.value.tag === expected.value.tag && typeof this.value.diffDeep === 'function' + expected.tag === primitiveTag + && this.value.tag === expected.value.tag && typeof this.value.diffDeep === 'function' ) { - return { compareResult } + return {compareResult}; } // Try to line up this or remaining items with the expected items. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected + const rhsFork = recursorUtils.fork(rhsRecursor); + const initialExpected = expected; do { if (expected === null || expected.isItem !== true) { @@ -191,12 +201,14 @@ class PrimitiveItem { rhsRecursor: recursorUtils.map( recursorUtils.unshift(rhsFork.recursor, initialExpected), next => { - if (next.isItem !== true) return next + if (next.isItem !== true) { + return next; + } - next.index++ - return next + next.index++; + return next; }), - } + }; } if (this.value.compare(expected.value) === DEEP_EQUAL) { @@ -205,43 +217,49 @@ class PrimitiveItem { lhsRecursor: recursorUtils.map( recursorUtils.unshift(lhsRecursor, this), next => { - if (next.isItem !== true) return next + if (next.isItem !== true) { + return next; + } - next.index++ - return next + next.index++; + return next; }), rhsRecursor: rhsFork.recursor, - } + }; } - expected = rhsFork.shared() - } while (true) + expected = rhsFork.shared(); + } while (true); // eslint-disable-line no-constant-condition } - diffDeep (expected, theme, indent, invert) { + diffDeep(expected, theme, indent, invert) { // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') { + return null; + } - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent + const increaseValueIndent = theme.property.increaseValueIndent === true; + const valueIndent = increaseValueIndent ? indent.increase() : indent; // Since the value is diffed directly, modifiers are not applied. Apply // modifiers to the item descriptor instead. - const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) - if (diff === null) return null + const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert); + if (diff === null) { + return null; + } if (typeof theme.item.customFormat === 'function') { - return theme.item.customFormat(theme, indent, diff) + return theme.item.customFormat(theme, indent, diff); } - return diff.withLastPostfixed(theme.item.after) + return diff.withLastPostfixed(theme.item.after); } - serialize () { - return [this.index, this.value] + serialize() { + return [this.index, this.value]; } - isItem = true + isItem = true; - tag = primitiveTag + tag = primitiveTag; } diff --git a/lib/metaDescriptors/mapEntry.js b/lib/metaDescriptors/mapEntry.js index 863ec21..b7d6ae9 100644 --- a/lib/metaDescriptors/mapEntry.js +++ b/lib/metaDescriptors/mapEntry.js @@ -1,174 +1,201 @@ -import { DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL } from '../constants.js' -import lineBuilder from '../lineBuilder.js' -import * as recursorUtils from '../recursorUtils.js' -import * as themeUtils from '../themeUtils.js' +import {DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL} from '../constants.js'; +import lineBuilder from '../lineBuilder.js'; +import * as recursorUtils from '../recursorUtils.js'; +import * as themeUtils from '../themeUtils.js'; -export function describe (keyDescriptor, valueDescriptor) { - const keyIsPrimitive = keyDescriptor.isPrimitive === true - const valueIsPrimitive = valueDescriptor.isPrimitive === true +export function describe(keyDescriptor, valueDescriptor) { + const keyIsPrimitive = keyDescriptor.isPrimitive === true; + const valueIsPrimitive = valueDescriptor.isPrimitive === true; - return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) + return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive); } -export function deserialize (state, recursor) { - const keyIsPrimitive = state[0] - const valueIsPrimitive = state[1] - const keyDescriptor = recursor() - const valueDescriptor = recursor() +export function deserialize(state, recursor) { + const keyIsPrimitive = state[0]; + const valueIsPrimitive = state[1]; + const keyDescriptor = recursor(); + const valueDescriptor = recursor(); - return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive) + return new MapEntry(keyDescriptor, valueDescriptor, keyIsPrimitive, valueIsPrimitive); } -export const tag = Symbol('MapEntry') +export const tag = Symbol('MapEntry'); -function mergeWithKey (theme, key, values) { - const lines = lineBuilder.buffer() - const keyRemainder = lineBuilder.buffer() +function mergeWithKey(theme, key, values) { + const lines = lineBuilder.buffer(); + const keyRemainder = lineBuilder.buffer(); for (const line of key) { if (!line.isLast && !line.hasGutter) { - lines.append(line) + lines.append(line); } else { - keyRemainder.append(line) + keyRemainder.append(line); } } + for (const value of values) { - lines.append(keyRemainder.mergeWithInfix(theme.mapEntry.separator, value).withLastPostfixed(theme.mapEntry.after)) + lines.append(keyRemainder.mergeWithInfix(theme.mapEntry.separator, value).withLastPostfixed(theme.mapEntry.after)); } - return lines + + return lines; } class MapEntry { - constructor (key, value, keyIsPrimitive, valueIsPrimitive) { - this.key = key - this.value = value - this.keyIsPrimitive = keyIsPrimitive - this.valueIsPrimitive = valueIsPrimitive + constructor(key, value, keyIsPrimitive, valueIsPrimitive) { + this.key = key; + this.value = value; + this.keyIsPrimitive = keyIsPrimitive; + this.valueIsPrimitive = valueIsPrimitive; } - createRecursor () { - let emitKey = true - let emitValue = true + createRecursor() { + let emitKey = true; + let emitValue = true; return () => { if (emitKey) { - emitKey = false - return this.key + emitKey = false; + return this.key; } if (emitValue) { - emitValue = false - return this.value + emitValue = false; + return this.value; } - return null - } + return null; + }; } - compare (expected) { - if (this.tag !== expected.tag) return UNEQUAL - if (this.keyIsPrimitive !== expected.keyIsPrimitive) return UNEQUAL - if (this.valueIsPrimitive !== expected.valueIsPrimitive) return UNEQUAL + compare(expected) { + if (this.tag !== expected.tag) { + return UNEQUAL; + } + + if (this.keyIsPrimitive !== expected.keyIsPrimitive) { + return UNEQUAL; + } + + if (this.valueIsPrimitive !== expected.valueIsPrimitive) { + return UNEQUAL; + } - if (!this.keyIsPrimitive) return SHALLOW_EQUAL + if (!this.keyIsPrimitive) { + return SHALLOW_EQUAL; + } - const keyResult = this.key.compare(expected.key) - if (keyResult !== DEEP_EQUAL) return keyResult + const keyResult = this.key.compare(expected.key); + if (keyResult !== DEEP_EQUAL) { + return keyResult; + } - if (!this.valueIsPrimitive) return SHALLOW_EQUAL - return this.value.compare(expected.value) + if (!this.valueIsPrimitive) { + return SHALLOW_EQUAL; + } + + return this.value.compare(expected.value); } - formatDeep (theme, indent) { + formatDeep(theme, indent) { // Verify the map entry can be formatted directly. - if (!this.keyIsPrimitive || typeof this.value.formatDeep !== 'function') return null + if (!this.keyIsPrimitive || typeof this.value.formatDeep !== 'function') { + return null; + } // Since formatShallow() would result in theme modifiers being applied // before the key and value are formatted, do the same here. - const value = this.value.formatDeep(themeUtils.applyModifiersToOriginal(this.value, theme), indent) - if (value === null) return null + const value = this.value.formatDeep(themeUtils.applyModifiersToOriginal(this.value, theme), indent); + if (value === null) { + return null; + } - const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent) - return mergeWithKey(theme, key, [value]) + const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent); + return mergeWithKey(theme, key, [value]); } - formatShallow (theme, indent) { - let key = null - const values = [] + formatShallow(theme, _indent) { + let key = null; + const values = []; return { append: (formatted, origin) => { if (this.key === origin) { - key = formatted + key = formatted; } else { - values.push(formatted) + values.push(formatted); } }, - finalize () { - return mergeWithKey(theme, key, values) + finalize() { + return mergeWithKey(theme, key, values); }, - } + }; } - diffDeep (expected, theme, indent, invert) { + diffDeep(expected, theme, indent, invert) { // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') { + return null; + } + // Only use this logic to format value diffs when the keys are primitive and equal. if (!this.keyIsPrimitive || !expected.keyIsPrimitive || this.key.compare(expected.key) !== DEEP_EQUAL) { - return null + return null; } // Since formatShallow() would result in theme modifiers being applied // before the key and value are formatted, do the same here. - const diff = this.value.diffDeep(expected.value, themeUtils.applyModifiersToOriginal(this.value, theme), indent, invert) - if (diff === null) return null + const diff = this.value.diffDeep(expected.value, themeUtils.applyModifiersToOriginal(this.value, theme), indent, invert); + if (diff === null) { + return null; + } - const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent, '') - return mergeWithKey(theme, key, [diff]) + const key = this.key.formatDeep(themeUtils.applyModifiersToOriginal(this.key, theme), indent, ''); + return mergeWithKey(theme, key, [diff]); } - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // eslint-disable-next-line max-params, complexity + prepareDiff(expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + if (isCircular(this.value) || isCircular(expected.value)) { + return {compareResult: UNEQUAL}; + } - const compareResult = this.compare(expected) - const keysAreEqual = this.tag === expected.tag && this.key.compare(expected.key) === DEEP_EQUAL + const compareResult = this.compare(expected); + const keysAreEqual = this.tag === expected.tag && this.key.compare(expected.key) === DEEP_EQUAL; // Short-circuit when keys and/or values are deeply equal. - if (compareResult === DEEP_EQUAL || keysAreEqual) return { compareResult } + if (compareResult === DEEP_EQUAL || keysAreEqual) { + return {compareResult}; + } // Try to line up this or remaining map entries with the expected entries. - const lhsFork = recursorUtils.fork(lhsRecursor) - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected + const lhsFork = recursorUtils.fork(lhsRecursor); + const rhsFork = recursorUtils.fork(rhsRecursor); + const initialExpected = expected; - let expectedIsMissing = false + let expectedIsMissing = false; while (!expectedIsMissing && expected !== null && this.tag === expected.tag) { - if (expected.keyIsPrimitive) { - expectedIsMissing = this.key.compare(expected.key) !== UNEQUAL - } else { - expectedIsMissing = compareComplexShape(this.key, expected.key) !== UNEQUAL - } + expectedIsMissing = expected.keyIsPrimitive ? this.key.compare(expected.key) !== UNEQUAL : compareComplexShape(this.key, expected.key) !== UNEQUAL; - expected = rhsFork.shared() + expected = rhsFork.shared(); } - let actualIsExtraneous = false + let actualIsExtraneous = false; if (this.tag === initialExpected.tag) { if (initialExpected.keyIsPrimitive) { - let actual = this + let actual = this; // eslint-disable-line unicorn/no-this-assignment while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { if (actual.keyIsPrimitive) { - actualIsExtraneous = initialExpected.key.compare(actual.key) === DEEP_EQUAL + actualIsExtraneous = initialExpected.key.compare(actual.key) === DEEP_EQUAL; } - actual = lhsFork.shared() + actual = lhsFork.shared(); } } else { - let actual = this + let actual = this; // eslint-disable-line unicorn/no-this-assignment while (!actualIsExtraneous && actual !== null && this.tag === actual.tag) { if (!actual.keyIsPrimitive) { - actualIsExtraneous = compareComplexShape(actual.key, initialExpected.key) !== UNEQUAL + actualIsExtraneous = compareComplexShape(actual.key, initialExpected.key) !== UNEQUAL; } - actual = lhsFork.shared() + actual = lhsFork.shared(); } } } @@ -178,7 +205,7 @@ class MapEntry { actualIsExtraneous: true, lhsRecursor: lhsFork.recursor, rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } + }; } if (expectedIsMissing && !actualIsExtraneous) { @@ -186,16 +213,14 @@ class MapEntry { expectedIsMissing: true, lhsRecursor: recursorUtils.unshift(lhsFork.recursor, this), rhsRecursor: rhsFork.recursor, - } + }; } - let mustRecurse = false + let mustRecurse = false; if (!this.keyIsPrimitive && !initialExpected.keyIsPrimitive) { - if (this.valueIsPrimitive || initialExpected.valueIsPrimitive) { - mustRecurse = this.value.compare(initialExpected.value) !== UNEQUAL - } else { - mustRecurse = compareComplexShape(this.value, initialExpected.value) !== UNEQUAL - } + mustRecurse = this.valueIsPrimitive || initialExpected.valueIsPrimitive + ? this.value.compare(initialExpected.value) !== UNEQUAL + : compareComplexShape(this.value, initialExpected.value) !== UNEQUAL; } return { @@ -203,14 +228,14 @@ class MapEntry { isUnequal: !mustRecurse, lhsRecursor: lhsFork.recursor, rhsRecursor: rhsFork.recursor, - } + }; } - serialize () { - return [this.keyIsPrimitive, this.valueIsPrimitive] + serialize() { + return [this.keyIsPrimitive, this.valueIsPrimitive]; } - isMapEntry = true + isMapEntry = true; - tag = tag + tag = tag; } diff --git a/lib/metaDescriptors/pointer.js b/lib/metaDescriptors/pointer.js index 2e1137c..1ba65b0 100644 --- a/lib/metaDescriptors/pointer.js +++ b/lib/metaDescriptors/pointer.js @@ -1,29 +1,29 @@ -import { UNEQUAL } from '../constants.js' +import {UNEQUAL} from '../constants.js'; -export function describe (index) { - return new Pointer(index) +export function describe(index) { + return new Pointer(index); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('Pointer') +export const tag = Symbol('Pointer'); class Pointer { - constructor (index) { - this.index = index + constructor(index) { + this.index = index; } // Pointers cannot be compared, and are not expected to be part of the // comparisons. - compare (expected) { - return UNEQUAL + compare(_expected) { + return UNEQUAL; } - serialize () { - return this.index + serialize() { + return this.index; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/metaDescriptors/property.js b/lib/metaDescriptors/property.js index d43a11c..4d3be3c 100644 --- a/lib/metaDescriptors/property.js +++ b/lib/metaDescriptors/property.js @@ -1,181 +1,201 @@ -import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import {tag as symbolPrimitive} from '../primitiveValues/symbol.js' -import * as recursorUtils from '../recursorUtils.js' +import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import {tag as symbolPrimitive} from '../primitiveValues/symbol.js'; +import * as recursorUtils from '../recursorUtils.js'; -export function describeComplex (key, value) { - return new ComplexProperty(key, value) +export function describeComplex(key, value) { + return new ComplexProperty(key, value); } -export function deserializeComplex (key, recursor) { - const value = recursor() - return new ComplexProperty(key, value) +export function deserializeComplex(key, recursor) { + const value = recursor(); + return new ComplexProperty(key, value); } -export function describePrimitive (key, value) { - return new PrimitiveProperty(key, value) +export function describePrimitive(key, value) { + return new PrimitiveProperty(key, value); } -export function deserializePrimitive (state) { - const key = state[0] - const value = state[1] - return new PrimitiveProperty(key, value) +export function deserializePrimitive(state) { + const key = state[0]; + const value = state[1]; + return new PrimitiveProperty(key, value); } -export const complexTag = Symbol('ComplexProperty') +export const complexTag = Symbol('ComplexProperty'); -export const primitiveTag = Symbol('PrimitiveProperty') +export const primitiveTag = Symbol('PrimitiveProperty'); class Property { - constructor (key) { - this.key = key + constructor(key) { + this.key = key; } - compareKeys (expected) { - const result = this.key.compare(expected.key) + compareKeys(expected) { + const result = this.key.compare(expected.key); // Return AMBIGUOUS if symbol keys are unequal. It's likely that properties // are compared in order of declaration, which is not the desired strategy. // Returning AMBIGUOUS allows compare() and diff() to recognize this // situation and sort the symbol properties before comparing them. return result === UNEQUAL && this.key.tag === symbolPrimitive && expected.key.tag === symbolPrimitive ? AMBIGUOUS - : result + : result; } - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { + // eslint-disable-next-line max-params + prepareDiff(expected, lhsRecursor, rhsRecursor, compareComplexShape, isCircular) { // Circular values cannot be compared. They must be treated as being unequal when diffing. - if (isCircular(this.value) || isCircular(expected.value)) return { compareResult: UNEQUAL } + if (isCircular(this.value) || isCircular(expected.value)) { + return {compareResult: UNEQUAL}; + } // Try to line up this or remaining properties with the expected properties. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected + const rhsFork = recursorUtils.fork(rhsRecursor); + const initialExpected = expected; do { if (expected === null || expected.isProperty !== true) { return { actualIsExtraneous: true, rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } - } else if (this.key.compare(expected.key) === DEEP_EQUAL) { + }; + } + + if (this.key.compare(expected.key) === DEEP_EQUAL) { if (expected === initialExpected) { - return null - } else { - return { - expectedIsMissing: true, - lhsRecursor: recursorUtils.unshift(lhsRecursor, this), - rhsRecursor: rhsFork.recursor, - } + return null; } + + return { + expectedIsMissing: true, + lhsRecursor: recursorUtils.unshift(lhsRecursor, this), + rhsRecursor: rhsFork.recursor, + }; } - expected = rhsFork.shared() - } while (true) + expected = rhsFork.shared(); + } while (true); // eslint-disable-line no-constant-condition } - isProperty = true + isProperty = true; } class ComplexProperty extends Property { - constructor (key, value) { - super(key) - this.value = value + constructor(key, value) { + super(key); + this.value = value; } - createRecursor () { - return recursorUtils.singleValue(this.value) + createRecursor() { + return recursorUtils.singleValue(this.value); } - compare (expected) { - if (expected.isProperty !== true) return UNEQUAL + compare(expected) { + if (expected.isProperty !== true) { + return UNEQUAL; + } - const keyResult = this.compareKeys(expected) - if (keyResult !== DEEP_EQUAL) return keyResult + const keyResult = this.compareKeys(expected); + if (keyResult !== DEEP_EQUAL) { + return keyResult; + } return this.tag === expected.tag ? this.value.compare(expected.value) - : UNEQUAL + : UNEQUAL; } - formatShallow (theme, indent) { - const increaseValueIndent = theme.property.increaseValueIndent === true + formatShallow(theme, indent) { + const increaseValueIndent = theme.property.increaseValueIndent === true; return new formatUtils.SingleValueFormatter(theme, value => { if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, value) + return theme.property.customFormat(theme, indent, this.key, value); } return value .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) - }, increaseValueIndent) + .withLastPostfixed(theme.property.after); + }, increaseValueIndent); } - serialize () { - return this.key + serialize() { + return this.key; } - tag = complexTag + tag = complexTag; } class PrimitiveProperty extends Property { - constructor (key, value) { - super(key) - this.value = value + constructor(key, value) { + super(key); + this.value = value; } - compare (expected) { - if (expected.isProperty !== true) return UNEQUAL + compare(expected) { + if (expected.isProperty !== true) { + return UNEQUAL; + } - const keyResult = this.compareKeys(expected) - if (keyResult !== DEEP_EQUAL) return keyResult + const keyResult = this.compareKeys(expected); + if (keyResult !== DEEP_EQUAL) { + return keyResult; + } - return this.tag !== expected.tag - ? UNEQUAL - : this.value.compare(expected.value) + return this.tag === expected.tag + ? this.value.compare(expected.value) + : UNEQUAL; } - formatDeep (theme, indent) { - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent + formatDeep(theme, indent) { + const increaseValueIndent = theme.property.increaseValueIndent === true; + const valueIndent = increaseValueIndent ? indent.increase() : indent; // Since the key and value are formatted directly, modifiers are not // applied. Apply modifiers to the property descriptor instead. - const formatted = this.value.formatDeep(theme, valueIndent) + const formatted = this.value.formatDeep(theme, valueIndent); if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, formatted) + return theme.property.customFormat(theme, indent, this.key, formatted); } return formatted .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) + .withLastPostfixed(theme.property.after); } - diffDeep (expected, theme, indent, invert) { + diffDeep(expected, theme, indent, invert) { // Verify a diff can be returned. - if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') return null + if (this.tag !== expected.tag || typeof this.value.diffDeep !== 'function') { + return null; + } + // Only use this logic to diff values when the keys are the same. - if (this.key.compare(expected.key) !== DEEP_EQUAL) return null + if (this.key.compare(expected.key) !== DEEP_EQUAL) { + return null; + } - const increaseValueIndent = theme.property.increaseValueIndent === true - const valueIndent = increaseValueIndent ? indent.increase() : indent + const increaseValueIndent = theme.property.increaseValueIndent === true; + const valueIndent = increaseValueIndent ? indent.increase() : indent; // Since the key and value are diffed directly, modifiers are not // applied. Apply modifiers to the property descriptor instead. - const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert) - if (diff === null) return null + const diff = this.value.diffDeep(expected.value, theme, valueIndent, invert); + if (diff === null) { + return null; + } if (typeof theme.property.customFormat === 'function') { - return theme.property.customFormat(theme, indent, this.key, diff) + return theme.property.customFormat(theme, indent, this.key, diff); } return diff .withFirstPrefixed(this.key.formatAsKey(theme) + theme.property.separator) - .withLastPostfixed(theme.property.after) + .withLastPostfixed(theme.property.after); } - serialize () { - return [this.key, this.value] + serialize() { + return [this.key, this.value]; } - tag = primitiveTag + tag = primitiveTag; } diff --git a/lib/metaDescriptors/stats.js b/lib/metaDescriptors/stats.js index 02f6e3f..0c9c5b7 100644 --- a/lib/metaDescriptors/stats.js +++ b/lib/metaDescriptors/stats.js @@ -1,57 +1,59 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import lineBuilder from '../lineBuilder.js' -import * as recursorUtils from '../recursorUtils.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import lineBuilder from '../lineBuilder.js'; +import * as recursorUtils from '../recursorUtils.js'; -export function describeIterableRecursor (recursor) { - return new IterableStats(recursor.size) +export function describeIterableRecursor(recursor) { + return new IterableStats(recursor.size); } -export function describeListRecursor (recursor) { - return new ListStats(recursor.size) +export function describeListRecursor(recursor) { + return new ListStats(recursor.size); } -export function describePropertyRecursor (recursor) { - return new PropertyStats(recursor.size) +export function describePropertyRecursor(recursor) { + return new PropertyStats(recursor.size); } -export function deserializeIterableStats (size) { - return new IterableStats(size) +export function deserializeIterableStats(size) { + return new IterableStats(size); } -export function deserializeListStats (size) { - return new ListStats(size) +export function deserializeListStats(size) { + return new ListStats(size); } -export function deserializePropertyStats (size) { - return new PropertyStats(size) +export function deserializePropertyStats(size) { + return new PropertyStats(size); } -export const iterableTag = Symbol('IterableStats') +export const iterableTag = Symbol('IterableStats'); -export const listTag = Symbol('ListStats') +export const listTag = Symbol('ListStats'); -export const propertyTag = Symbol('PropertyStats') +export const propertyTag = Symbol('PropertyStats'); class Stats { - constructor (size) { - this.size = size + constructor(size) { + this.size = size; } - formatDeep (theme) { - return lineBuilder.single(theme.stats.separator) + formatDeep(theme) { + return lineBuilder.single(theme.stats.separator); } - prepareDiff (expected, lhsRecursor, rhsRecursor, compareComplexShape) { - if (expected.isStats !== true || expected.tag === this.tag) return null + prepareDiff(expected, lhsRecursor, rhsRecursor, _compareComplexShape) { + if (expected.isStats !== true || expected.tag === this.tag) { + return null; + } // Try to line up stats descriptors with the same tag. - const rhsFork = recursorUtils.fork(rhsRecursor) - const initialExpected = expected + const rhsFork = recursorUtils.fork(rhsRecursor); + const initialExpected = expected; - const missing = [] + const missing = []; while (expected !== null && this.tag !== expected.tag) { - missing.push(expected) - expected = rhsFork.shared() + missing.push(expected); + expected = rhsFork.shared(); } if (expected !== null && missing.length > 0) { @@ -62,16 +64,16 @@ class Stats { // Use original `rhsRecursor`, not `rhsFork`, since the consumed // descriptors are returned with the `missing` array. rhsRecursor: recursorUtils.unshift(rhsRecursor, expected), - } + }; } - const lhsFork = recursorUtils.fork(lhsRecursor) - let actual = this + const lhsFork = recursorUtils.fork(lhsRecursor); + let actual = this; // eslint-disable-line unicorn/no-this-assignment - const extraneous = [] + const extraneous = []; while (actual !== null && actual.tag !== initialExpected.tag) { - extraneous.push(actual) - actual = lhsFork.shared() + extraneous.push(actual); + actual = lhsFork.shared(); } if (actual !== null && extraneous.length > 0) { @@ -82,45 +84,45 @@ class Stats { // descriptors are returned with the `extraneous` array. lhsRecursor: recursorUtils.unshift(lhsRecursor, actual), rhsRecursor: recursorUtils.unshift(rhsFork.recursor, initialExpected), - } + }; } - return null + return null; } - serialize () { - return this.size + serialize() { + return this.size; } - isStats = true + isStats = true; } class IterableStats extends Stats { - compare (expected) { + compare(expected) { return expected.tag === iterableTag && this.size === expected.size ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - tag = iterableTag + tag = iterableTag; } class ListStats extends Stats { - compare (expected) { + compare(expected) { return expected.tag === listTag && this.size === expected.size ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - tag = listTag + tag = listTag; } class PropertyStats extends Stats { - compare (expected) { + compare(expected) { return expected.tag === propertyTag && this.size === expected.size ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - tag = propertyTag + tag = propertyTag; } diff --git a/lib/pluginRegistry.js b/lib/pluginRegistry.js index 6cb83b0..0eabb62 100644 --- a/lib/pluginRegistry.js +++ b/lib/pluginRegistry.js @@ -1,89 +1,91 @@ -import fs from 'node:fs' -import semver from 'semver' -import * as object from './complexValues/object.js' -import * as constants from './constants.js' -import * as formatUtils from './formatUtils.js' -import lineBuilder from './lineBuilder.js' -import * as itemDescriptor from './metaDescriptors/item.js' -import * as propertyDescriptor from './metaDescriptors/property.js' -import * as stringDescriptor from './primitiveValues/string.js' -import * as recursorUtils from './recursorUtils.js' -import * as themeUtils from './themeUtils.js' +import fs from 'node:fs'; + +import semver from 'semver'; + +import * as object from './complexValues/object.js'; +import * as constants from './constants.js'; +import * as formatUtils from './formatUtils.js'; +import lineBuilder from './lineBuilder.js'; +import * as itemDescriptor from './metaDescriptors/item.js'; +import * as propertyDescriptor from './metaDescriptors/property.js'; +import * as stringDescriptor from './primitiveValues/string.js'; +import * as recursorUtils from './recursorUtils.js'; +import * as themeUtils from './themeUtils.js'; const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url))); -const API_VERSION = 1 -const CONCORDANCE_VERSION = pkg.version +const API_VERSION = 1; +const CONCORDANCE_VERSION = pkg.version; -const descriptorRegistry = new Map() -const registry = new Map() +const descriptorRegistry = new Map(); +const registry = new Map(); class PluginError extends Error { - constructor (message, plugin) { - super(message) - this.name = 'PluginError' - this.plugin = plugin + constructor(message, plugin) { + super(message); + this.name = 'PluginError'; + this.plugin = plugin; } } class PluginTypeError extends TypeError { - constructor (message, plugin) { - super(message) - this.name = 'PluginTypeError' - this.plugin = plugin + constructor(message, plugin) { + super(message); + this.name = 'PluginTypeError'; + this.plugin = plugin; } } class UnsupportedApiError extends PluginError { - constructor (plugin) { - super('Plugin requires an unsupported API version', plugin) - this.name = 'UnsupportedApiError' + constructor(plugin) { + super('Plugin requires an unsupported API version', plugin); + this.name = 'UnsupportedApiError'; } } class UnsupportedError extends PluginError { - constructor (plugin) { - super('Plugin does not support this version of Concordance', plugin) - this.name = 'UnsupportedError' + constructor(plugin) { + super('Plugin does not support this version of Concordance', plugin); + this.name = 'UnsupportedError'; } } class DuplicateDescriptorTagError extends PluginError { - constructor (tag, plugin) { - super(`Could not add descriptor: tag ${String(tag)} has already been registered`, plugin) - this.name = 'DuplicateDescriptorTagError' - this.tag = tag + constructor(tag, plugin) { + super(`Could not add descriptor: tag ${String(tag)} has already been registered`, plugin); + this.name = 'DuplicateDescriptorTagError'; + this.tag = tag; } } class DuplicateDescriptorIdError extends PluginError { - constructor (id, plugin) { + constructor(id, plugin) { const printed = typeof id === 'number' ? `0x${id.toString(16).toUpperCase()}` - : String(id) - super(`Could not add descriptor: id ${printed} has already been registered`, plugin) - this.name = 'DuplicateDescriptorIdError' - this.id = id + : String(id); + super(`Could not add descriptor: id ${printed} has already been registered`, plugin); + this.name = 'DuplicateDescriptorIdError'; + this.id = id; } } -function verify (plugin) { +function verify(plugin) { if (typeof plugin.name !== 'string' || !plugin.name) { - throw new PluginTypeError('Plugin must have a `name`', plugin) + throw new PluginTypeError('Plugin must have a `name`', plugin); } if (plugin.apiVersion !== API_VERSION) { - throw new UnsupportedApiError(plugin) + throw new UnsupportedApiError(plugin); } if ('minimalConcordanceVersion' in plugin) { if (!semver.valid(plugin.minimalConcordanceVersion)) { - throw new PluginTypeError('If specified, `minimalConcordanceVersion` must be a valid SemVer version', plugin) + throw new PluginTypeError('If specified, `minimalConcordanceVersion` must be a valid SemVer version', plugin); } - const range = `>=${plugin.minimalConcordanceVersion}` + const range = `>=${plugin.minimalConcordanceVersion}`; if (!semver.satisfies(CONCORDANCE_VERSION, range)) { - throw new UnsupportedError(plugin) + throw new UnsupportedError(plugin); } } } @@ -94,7 +96,7 @@ const publicDescriptorTags = Object.freeze({ primitiveItem: itemDescriptor.primitiveTag, primitiveProperty: propertyDescriptor.primitiveTag, string: stringDescriptor.tag, -}) +}); // Don't expose `setDefaultGutter()`. const publicLineBuilder = Object.freeze({ @@ -117,28 +119,35 @@ const publicLineBuilder = Object.freeze({ line: lineBuilder.expected.line, single: lineBuilder.expected.single, }), -}) +}); -function modifyTheme (descriptor, modifier) { - themeUtils.addModifier(descriptor, modifier) - return descriptor +function modifyTheme(descriptor, modifier) { + themeUtils.addModifier(descriptor, modifier); + return descriptor; } -export function add (plugin) { - verify(plugin) +export function add(plugin) { + verify(plugin); - const name = plugin.name - if (registry.has(name)) return registry.get(name) + const {name} = plugin; + if (registry.has(name)) { + return registry.get(name); + } - const id2deserialize = new Map() - const tag2id = new Map() + const id2deserialize = new Map(); + const tag2id = new Map(); const addDescriptor = (id, tag, deserialize) => { - if (id2deserialize.has(id)) throw new DuplicateDescriptorIdError(id, plugin) - if (descriptorRegistry.has(tag) || tag2id.has(tag)) throw new DuplicateDescriptorTagError(tag, plugin) + if (id2deserialize.has(id)) { + throw new DuplicateDescriptorIdError(id, plugin); + } - id2deserialize.set(id, deserialize) - tag2id.set(tag, id) - } + if (descriptorRegistry.has(tag) || tag2id.has(tag)) { + throw new DuplicateDescriptorTagError(tag, plugin); + } + + id2deserialize.set(id, deserialize); + tag2id.set(tag, id); + }; const tryDescribeValue = plugin.register({ // Concordance makes assumptions about when AMBIGUOUS occurs. Do not expose @@ -158,7 +167,7 @@ export function add (plugin) { mapRecursor: recursorUtils.map, modifyTheme, wrapFromTheme: formatUtils.wrap, - }) + }); const registered = { id2deserialize, @@ -167,50 +176,52 @@ export function add (plugin) { tag2id, theme: plugin.theme || {}, tryDescribeValue, - } + }; - registry.set(name, registered) + registry.set(name, registered); for (const tag of tag2id.keys()) { - descriptorRegistry.set(tag, registered) + descriptorRegistry.set(tag, registered); } - return registered + return registered; } -export function getDeserializers (plugins) { +export function getDeserializers(plugins) { return plugins.map(plugin => { - const registered = add(plugin) + const registered = add(plugin); return { id2deserialize: registered.id2deserialize, name: registered.name, serializerVersion: registered.serializerVersion, - } - }) + }; + }); } -export function getThemes (plugins) { +export function getThemes(plugins) { return plugins.map(plugin => { - const registered = add(plugin) + const registered = add(plugin); return { name: registered.name, theme: registered.theme, - } - }) + }; + }); } -export function getTryDescribeValues (plugins) { - return plugins.map(plugin => add(plugin).tryDescribeValue) +export function getTryDescribeValues(plugins) { + return plugins.map(plugin => add(plugin).tryDescribeValue); } -export function resolveDescriptorRef (tag) { - if (!descriptorRegistry.has(tag)) return null +export function resolveDescriptorRef(tag) { + if (!descriptorRegistry.has(tag)) { + return null; + } - const registered = descriptorRegistry.get(tag) + const registered = descriptorRegistry.get(tag); return { id: registered.tag2id.get(tag), name: registered.name, serialization: { serializerVersion: registered.serializerVersion, }, - } + }; } diff --git a/lib/primitiveValues/bigInt.js b/lib/primitiveValues/bigInt.js index 907441e..7e7a00d 100644 --- a/lib/primitiveValues/bigInt.js +++ b/lib/primitiveValues/bigInt.js @@ -1,35 +1,35 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe (value) { - return new BigIntValue(value) +export function describe(value) { + return new BigIntValue(value); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('BigIntValue') +export const tag = Symbol('BigIntValue'); class BigIntValue { - constructor (value) { - this.value = value + constructor(value) { + this.value = value; } - compare (expected) { + compare(expected) { return expected.tag === tag && Object.is(this.value, expected.value) ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.bigInt, `${this.value}n`)) + formatDeep(theme) { + return lineBuilder.single(formatUtils.wrap(theme.bigInt, `${this.value}n`)); } - serialize () { - return this.value + serialize() { + return this.value; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/primitiveValues/boolean.js b/lib/primitiveValues/boolean.js index 98aa1f9..628ba4a 100644 --- a/lib/primitiveValues/boolean.js +++ b/lib/primitiveValues/boolean.js @@ -1,35 +1,35 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe (value) { - return new BooleanValue(value) +export function describe(value) { + return new BooleanValue(value); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('BooleanValue') +export const tag = Symbol('BooleanValue'); class BooleanValue { - constructor (value) { - this.value = value + constructor(value) { + this.value = value; } - compare (expected) { + compare(expected) { return this.tag === expected.tag && this.value === expected.value ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.boolean, this.value === true ? 'true' : 'false')) + formatDeep(theme) { + return lineBuilder.single(formatUtils.wrap(theme.boolean, this.value === true ? 'true' : 'false')); } - serialize () { - return this.value + serialize() { + return this.value; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/primitiveValues/null.js b/lib/primitiveValues/null.js index bc62235..50f0e68 100644 --- a/lib/primitiveValues/null.js +++ b/lib/primitiveValues/null.js @@ -1,27 +1,27 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe () { - return new NullValue() +export function describe() { + return new NullValue(); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('NullValue') +export const tag = Symbol('NullValue'); class NullValue { - compare (expected) { + compare(expected) { return expected.tag === tag ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.null, 'null')) + formatDeep(theme) { + return lineBuilder.single(formatUtils.wrap(theme.null, 'null')); } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/primitiveValues/number.js b/lib/primitiveValues/number.js index bcd1ff4..203b11c 100644 --- a/lib/primitiveValues/number.js +++ b/lib/primitiveValues/number.js @@ -1,36 +1,36 @@ -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe (value) { - return new NumberValue(value) +export function describe(value) { + return new NumberValue(value); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('NumberValue') +export const tag = Symbol('NumberValue'); class NumberValue { - constructor (value) { - this.value = value + constructor(value) { + this.value = value; } - compare (expected) { + compare(expected) { return expected.tag === tag && Object.is(this.value, expected.value) ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { - const string = Object.is(this.value, -0) ? '-0' : String(this.value) - return lineBuilder.single(formatUtils.wrap(theme.number, string)) + formatDeep(theme) { + const string = Object.is(this.value, -0) ? '-0' : String(this.value); + return lineBuilder.single(formatUtils.wrap(theme.number, string)); } - serialize () { - return this.value + serialize() { + return this.value; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/primitiveValues/string.js b/lib/primitiveValues/string.js index 66c9bdc..27a9a65 100644 --- a/lib/primitiveValues/string.js +++ b/lib/primitiveValues/string.js @@ -1,312 +1,337 @@ -import {keyword} from 'esutils' -import fastDiff from 'fast-diff' -import {DEEP_EQUAL, UNEQUAL} from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' - -export function describe (value) { - return new StringValue(value) +import {keyword} from 'esutils'; +import fastDiff from 'fast-diff'; + +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; + +export function describe(value) { + return new StringValue(value); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('StringValue') +export const tag = Symbol('StringValue'); // TODO: Escape invisible characters (e.g. zero-width joiner, non-breaking space), // ambiguous characters (other kinds of spaces, combining characters). Use // http://graphemica.com/blocks/control-pictures where applicable. -function basicEscape (string) { - return string.replace(/\\/g, '\\\\') +function basicEscape(string) { + return string.replaceAll('\\', '\\\\'); } -const CRLF_CONTROL_PICTURE = '\u240D\u240A' -const LF_CONTROL_PICTURE = '\u240A' -const CR_CONTROL_PICTURE = '\u240D' +const CRLF_CONTROL_PICTURE = '\u240D\u240A'; +const LF_CONTROL_PICTURE = '\u240A'; +const CR_CONTROL_PICTURE = '\u240D'; -const MATCH_CONTROL_PICTURES = new RegExp(`${CR_CONTROL_PICTURE}|${LF_CONTROL_PICTURE}|${CR_CONTROL_PICTURE}`, 'g') +const MATCH_CONTROL_PICTURES = new RegExp(`${CR_CONTROL_PICTURE}|${LF_CONTROL_PICTURE}|${CR_CONTROL_PICTURE}`, 'g'); -function escapeLinebreak (string) { - if (string === '\r\n') return CRLF_CONTROL_PICTURE - if (string === '\n') return LF_CONTROL_PICTURE - if (string === '\r') return CR_CONTROL_PICTURE - return string +function escapeLinebreak(string) { + if (string === '\r\n') { + return CRLF_CONTROL_PICTURE; + } + + if (string === '\n') { + return LF_CONTROL_PICTURE; + } + + if (string === '\r') { + return CR_CONTROL_PICTURE; + } + + return string; } -function themeControlPictures (theme, resetWrap, str) { - return str.replace(MATCH_CONTROL_PICTURES, picture => { - return resetWrap.close + formatUtils.wrap(theme.string.controlPicture, picture) + resetWrap.open - }) +function themeControlPictures(theme, resetWrap, string_) { + return string_.replaceAll(MATCH_CONTROL_PICTURES, picture => resetWrap.close + formatUtils.wrap(theme.string.controlPicture, picture) + resetWrap.open); } -const MATCH_SINGLE_QUOTE = /'/g -const MATCH_DOUBLE_QUOTE = /"/g -const MATCH_BACKTICKS = /`/g -function escapeQuotes (line, string) { - const quote = line.escapeQuote - if (quote === '\'') return string.replace(MATCH_SINGLE_QUOTE, "\\'") - if (quote === '"') return string.replace(MATCH_DOUBLE_QUOTE, '\\"') - if (quote === '`') return string.replace(MATCH_BACKTICKS, '\\`') - return string +const MATCH_SINGLE_QUOTE = /'/g; +const MATCH_DOUBLE_QUOTE = /"/g; +const MATCH_BACKTICKS = /`/g; +function escapeQuotes(line, string) { + const quote = line.escapeQuote; + if (quote === '\'') { + return string.replaceAll(MATCH_SINGLE_QUOTE, '\\\''); + } + + if (quote === '"') { + return string.replaceAll(MATCH_DOUBLE_QUOTE, '\\"'); + } + + if (quote === '`') { + return string.replaceAll(MATCH_BACKTICKS, '\\`'); + } + + return string; } -function includesLinebreaks (string) { - return string.includes('\r') || string.includes('\n') +function includesLinebreaks(string) { + return string.includes('\r') || string.includes('\n'); } -function diffLine (theme, actual, expected, invert) { - const outcome = fastDiff(actual, expected) +function diffLine(theme, actual, expected, invert) { + const outcome = fastDiff(actual, expected); // TODO: Compute when line is mostly unequal (80%? 90%?) and treat it as being // completely unequal. const isPartiallyEqual = !( - (outcome.length === 2 && outcome[0][1] === actual && outcome[1][1] === expected) || + (outcome.length === 2 && outcome[0][1] === actual && outcome[1][1] === expected) // Discount line ending control pictures, which will be equal even when the // rest of the line isn't. - ( - outcome.length === 3 && - outcome[2][0] === fastDiff.EQUAL && - MATCH_CONTROL_PICTURES.test(outcome[2][1]) && - outcome[0][1] + outcome[2][1] === actual && - outcome[1][1] + outcome[2][1] === expected + || ( + outcome.length === 3 + && outcome[2][0] === fastDiff.EQUAL + && MATCH_CONTROL_PICTURES.test(outcome[2][1]) + && outcome[0][1] + outcome[2][1] === actual + && outcome[1][1] + outcome[2][1] === expected ) - ) + ); - let stringActual = '' - let stringExpected = '' + let stringActual = ''; + let stringExpected = ''; - const noopWrap = { open: '', close: '' } - let deleteWrap = isPartiallyEqual ? theme.string.diff.delete : noopWrap - let insertWrap = isPartiallyEqual ? theme.string.diff.insert : noopWrap - const equalWrap = isPartiallyEqual ? theme.string.diff.equal : noopWrap + const noopWrap = {open: '', close: ''}; + let deleteWrap = isPartiallyEqual ? theme.string.diff.delete : noopWrap; + let insertWrap = isPartiallyEqual ? theme.string.diff.insert : noopWrap; + const equalWrap = isPartiallyEqual ? theme.string.diff.equal : noopWrap; if (invert) { - [deleteWrap, insertWrap] = [insertWrap, deleteWrap] + [deleteWrap, insertWrap] = [insertWrap, deleteWrap]; } for (const diff of outcome) { if (diff[0] === fastDiff.DELETE) { - stringActual += formatUtils.wrap(deleteWrap, diff[1]) + stringActual += formatUtils.wrap(deleteWrap, diff[1]); } else if (diff[0] === fastDiff.INSERT) { - stringExpected += formatUtils.wrap(insertWrap, diff[1]) + stringExpected += formatUtils.wrap(insertWrap, diff[1]); } else { - const string = formatUtils.wrap(equalWrap, themeControlPictures(theme, equalWrap, diff[1])) - stringActual += string - stringExpected += string + const string = formatUtils.wrap(equalWrap, themeControlPictures(theme, equalWrap, diff[1])); + stringActual += string; + stringExpected += string; } } if (!isPartiallyEqual) { - const deleteLineWrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine - const insertLineWrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine + const deleteLineWrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine; + const insertLineWrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine; - stringActual = formatUtils.wrap(deleteLineWrap, stringActual) - stringExpected = formatUtils.wrap(insertLineWrap, stringExpected) + stringActual = formatUtils.wrap(deleteLineWrap, stringActual); + stringExpected = formatUtils.wrap(insertLineWrap, stringExpected); } - return [stringActual, stringExpected] + return [stringActual, stringExpected]; } -const LINEBREAKS = /\r\n|\r|\n/g +const LINEBREAKS = /\r\n|\r|\n/g; -function gatherLines (string) { - const lines = [] - let prevIndex = 0 - for (let match; (match = LINEBREAKS.exec(string)); prevIndex = match.index + match[0].length) { - lines.push(string.slice(prevIndex, match.index) + escapeLinebreak(match[0])) +function gatherLines(string) { + const lines = []; + let previousIndex = 0; + for (let match; (match = LINEBREAKS.exec(string)); previousIndex = match.index + match[0].length) { + lines.push(string.slice(previousIndex, match.index) + escapeLinebreak(match[0])); } - lines.push(string.slice(prevIndex)) - return lines + + lines.push(string.slice(previousIndex)); + return lines; } class StringValue { - constructor (value) { - this.value = value + constructor(value) { + this.value = value; } - compare (expected) { + compare(expected) { return expected.tag === tag && this.value === expected.value ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - get includesLinebreaks () { - return includesLinebreaks(this.value) + get includesLinebreaks() { + return includesLinebreaks(this.value); } - formatDeep (theme, indent) { + formatDeep(theme, indent) { // Escape backslashes - let escaped = basicEscape(this.value) + let escaped = basicEscape(this.value); if (!this.includesLinebreaks) { - escaped = escapeQuotes(theme.string.line, escaped) - return lineBuilder.single(formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped))) + escaped = escapeQuotes(theme.string.line, escaped); + return lineBuilder.single(formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped))); } - escaped = escapeQuotes(theme.string.multiline, escaped) - const lineStrings = gatherLines(escaped).map(string => { - return formatUtils.wrap(theme.string, themeControlPictures(theme, theme.string, string)) - }) - const lastIndex = lineStrings.length - 1 - const indentation = indent + escaped = escapeQuotes(theme.string.multiline, escaped); + const lineStrings = gatherLines(escaped).map(string => formatUtils.wrap(theme.string, themeControlPictures(theme, theme.string, string))); + const lastIndex = lineStrings.length - 1; + const indentation = indent; return lineBuilder.buffer() .append( lineStrings.map((string, index) => { - if (index === 0) return lineBuilder.first(theme.string.multiline.start + string) - if (index === lastIndex) return lineBuilder.last(indentation + string + theme.string.multiline.end) - return lineBuilder.line(indentation + string) - })) + if (index === 0) { + return lineBuilder.first(theme.string.multiline.start + string); + } + + if (index === lastIndex) { + return lineBuilder.last(indentation + string + theme.string.multiline.end); + } + + return lineBuilder.line(indentation + string); + })); } - formatAsKey (theme) { - const key = this.value - if (keyword.isIdentifierNameES6(key, true) || String(parseInt(key, 10)) === key) { - return key + formatAsKey(theme) { + const key = this.value; + if (keyword.isIdentifierNameES6(key, true) || String(Number.parseInt(key, 10)) === key) { + return key; } const escaped = basicEscape(key) - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/'/g, "\\'") - return formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped)) + .replaceAll('\n', '\\n') + .replaceAll('\r', '\\r') + .replaceAll('\'', '\\\''); + return formatUtils.wrap(theme.string.line, formatUtils.wrap(theme.string, escaped)); } - diffDeep (expected, theme, indent, invert) { - if (expected.tag !== tag) return null + // eslint-disable-next-line complexity + diffDeep(expected, theme, indent, invert) { + if (expected.tag !== tag) { + return null; + } - const escapedActual = basicEscape(this.value) - const escapedExpected = basicEscape(expected.value) + const escapedActual = basicEscape(this.value); + const escapedExpected = basicEscape(expected.value); if (!includesLinebreaks(escapedActual) && !includesLinebreaks(escapedExpected)) { const result = diffLine(theme, escapeQuotes(theme.string.line, escapedActual), escapeQuotes(theme.string.line, escapedExpected), invert, - ) + ); return lineBuilder.actual.single(formatUtils.wrap(theme.string.line, result[0])) - .concat(lineBuilder.expected.single(formatUtils.wrap(theme.string.line, result[1]))) + .concat(lineBuilder.expected.single(formatUtils.wrap(theme.string.line, result[1]))); // eslint-disable-line unicorn/prefer-spread } - const actualLines = gatherLines(escapeQuotes(theme.string.multiline, escapedActual)) - const expectedLines = gatherLines(escapeQuotes(theme.string.multiline, escapedExpected)) + const actualLines = gatherLines(escapeQuotes(theme.string.multiline, escapedActual)); + const expectedLines = gatherLines(escapeQuotes(theme.string.multiline, escapedExpected)); - const indentation = indent - const lines = lineBuilder.buffer() - const lastActualIndex = actualLines.length - 1 - const lastExpectedIndex = expectedLines.length - 1 + const indentation = indent; + const lines = lineBuilder.buffer(); + const lastActualIndex = actualLines.length - 1; + const lastExpectedIndex = expectedLines.length - 1; - let actualBuffer = [] - let expectedBuffer = [] - let mustOpenNextExpected = false + let actualBuffer = []; + let expectedBuffer = []; + let mustOpenNextExpected = false; for (let actualIndex = 0, expectedIndex = 0, extraneousOffset = 0; actualIndex < actualLines.length;) { if (actualLines[actualIndex] === expectedLines[expectedIndex]) { - lines.append(actualBuffer) - lines.append(expectedBuffer) - actualBuffer = [] - expectedBuffer = [] + lines.append(actualBuffer); + lines.append(expectedBuffer); + actualBuffer = []; + expectedBuffer = []; - let string = actualLines[actualIndex] - string = themeControlPictures(theme, theme.string.diff.equal, string) - string = formatUtils.wrap(theme.string.diff.equal, string) + let string = actualLines[actualIndex]; + string = themeControlPictures(theme, theme.string.diff.equal, string); + string = formatUtils.wrap(theme.string.diff.equal, string); if (actualIndex === 0) { - lines.append(lineBuilder.first(theme.string.multiline.start + string)) + lines.append(lineBuilder.first(theme.string.multiline.start + string)); } else if (actualIndex === lastActualIndex && expectedIndex === lastExpectedIndex) { - lines.append(lineBuilder.last(indentation + string + theme.string.multiline.end)) + lines.append(lineBuilder.last(indentation + string + theme.string.multiline.end)); } else { - lines.append(lineBuilder.line(indentation + string)) + lines.append(lineBuilder.line(indentation + string)); } - actualIndex++ - expectedIndex++ - continue + actualIndex++; + expectedIndex++; + continue; } - let expectedIsMissing = false + let expectedIsMissing = false; { - const compare = actualLines[actualIndex] + const compare = actualLines[actualIndex]; for (let index = expectedIndex; !expectedIsMissing && index < expectedLines.length; index++) { - expectedIsMissing = compare === expectedLines[index] + expectedIsMissing = compare === expectedLines[index]; } } - let actualIsExtraneous = (actualIndex - extraneousOffset) > lastExpectedIndex || expectedIndex > lastExpectedIndex + let actualIsExtraneous = (actualIndex - extraneousOffset) > lastExpectedIndex || expectedIndex > lastExpectedIndex; if (!actualIsExtraneous) { - const compare = expectedLines[expectedIndex] + const compare = expectedLines[expectedIndex]; for (let index = actualIndex; !actualIsExtraneous && index < actualLines.length; index++) { - actualIsExtraneous = compare === actualLines[index] + actualIsExtraneous = compare === actualLines[index]; } if (!actualIsExtraneous && (actualIndex - extraneousOffset) === lastExpectedIndex && actualIndex < lastActualIndex) { - actualIsExtraneous = true + actualIsExtraneous = true; } } if (actualIsExtraneous && !expectedIsMissing) { - const wrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine - const string = formatUtils.wrap(wrap, actualLines[actualIndex]) + const wrap = invert ? theme.string.diff.insertLine : theme.string.diff.deleteLine; + const string = formatUtils.wrap(wrap, actualLines[actualIndex]); if (actualIndex === 0) { - actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + string)) - mustOpenNextExpected = true + actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + string)); + mustOpenNextExpected = true; } else if (actualIndex === lastActualIndex) { - actualBuffer.push(lineBuilder.actual.last(indentation + string + theme.string.multiline.end)) + actualBuffer.push(lineBuilder.actual.last(indentation + string + theme.string.multiline.end)); } else { - actualBuffer.push(lineBuilder.actual.line(indentation + string)) + actualBuffer.push(lineBuilder.actual.line(indentation + string)); } - actualIndex++ - extraneousOffset++ + actualIndex++; + extraneousOffset++; } else if (expectedIsMissing && !actualIsExtraneous) { - const wrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine - const string = formatUtils.wrap(wrap, expectedLines[expectedIndex]) + const wrap = invert ? theme.string.diff.deleteLine : theme.string.diff.insertLine; + const string = formatUtils.wrap(wrap, expectedLines[expectedIndex]); if (mustOpenNextExpected) { - expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + string)) - mustOpenNextExpected = false + expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + string)); + mustOpenNextExpected = false; } else if (expectedIndex === lastExpectedIndex) { - expectedBuffer.push(lineBuilder.expected.last(indentation + string + theme.string.multiline.end)) + expectedBuffer.push(lineBuilder.expected.last(indentation + string + theme.string.multiline.end)); } else { - expectedBuffer.push(lineBuilder.expected.line(indentation + string)) + expectedBuffer.push(lineBuilder.expected.line(indentation + string)); } - expectedIndex++ + expectedIndex++; } else { - const result = diffLine(theme, actualLines[actualIndex], expectedLines[expectedIndex], invert) + const result = diffLine(theme, actualLines[actualIndex], expectedLines[expectedIndex], invert); if (actualIndex === 0) { - actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + result[0])) - mustOpenNextExpected = true + actualBuffer.push(lineBuilder.actual.first(theme.string.multiline.start + result[0])); + mustOpenNextExpected = true; } else if (actualIndex === lastActualIndex) { - actualBuffer.push(lineBuilder.actual.last(indentation + result[0] + theme.string.multiline.end)) + actualBuffer.push(lineBuilder.actual.last(indentation + result[0] + theme.string.multiline.end)); } else { - actualBuffer.push(lineBuilder.actual.line(indentation + result[0])) + actualBuffer.push(lineBuilder.actual.line(indentation + result[0])); } if (mustOpenNextExpected) { - expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + result[1])) - mustOpenNextExpected = false + expectedBuffer.push(lineBuilder.expected.first(theme.string.multiline.start + result[1])); + mustOpenNextExpected = false; } else if (expectedIndex === lastExpectedIndex) { - expectedBuffer.push(lineBuilder.expected.last(indentation + result[1] + theme.string.multiline.end)) + expectedBuffer.push(lineBuilder.expected.last(indentation + result[1] + theme.string.multiline.end)); } else { - expectedBuffer.push(lineBuilder.expected.line(indentation + result[1])) + expectedBuffer.push(lineBuilder.expected.line(indentation + result[1])); } - actualIndex++ - expectedIndex++ + actualIndex++; + expectedIndex++; } } - lines.append(actualBuffer) - lines.append(expectedBuffer) - return lines + lines.append(actualBuffer); + lines.append(expectedBuffer); + return lines; } - serialize () { - return this.value + serialize() { + return this.value; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/primitiveValues/symbol.js b/lib/primitiveValues/symbol.js index 6e5f104..6d08b64 100644 --- a/lib/primitiveValues/symbol.js +++ b/lib/primitiveValues/symbol.js @@ -1,97 +1,104 @@ -import stringEscape from 'js-string-escape' -import wellKnownSymbols from 'well-known-symbols' +import stringEscape from 'js-string-escape'; +import wellKnownSymbols from 'well-known-symbols'; -import { DEEP_EQUAL, UNEQUAL } from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe (value) { - let stringCompare = null +export function describe(value) { + let stringCompare = null; - const key = Symbol.keyFor(value) + const key = Symbol.keyFor(value); if (key !== undefined) { - stringCompare = `Symbol.for(${stringEscape(key)})` + stringCompare = `Symbol.for(${stringEscape(key)})`; } else if (wellKnownSymbols.isWellKnown(value)) { - stringCompare = wellKnownSymbols.getLabel(value) + stringCompare = wellKnownSymbols.getLabel(value); } return new SymbolValue({ stringCompare, value, - }) + }); } -export function deserialize (state) { - const stringCompare = state[0] - const string = state[1] || state[0] +export function deserialize(state) { + const stringCompare = state[0]; + const string = state[1] || state[0]; return new DeserializedSymbolValue({ string, stringCompare, value: null, - }) + }); } -export const tag = Symbol('SymbolValue') +export const tag = Symbol('SymbolValue'); class SymbolValue { - constructor (props) { - this.stringCompare = props.stringCompare - this.value = props.value + constructor(props) { + this.stringCompare = props.stringCompare; + this.value = props.value; } - compare (expected) { - if (expected.tag !== tag) return UNEQUAL + compare(expected) { + if (expected.tag !== tag) { + return UNEQUAL; + } if (this.stringCompare !== null) { return this.stringCompare === expected.stringCompare ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } return this.value === expected.value ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatString () { - if (this.stringCompare !== null) return this.stringCompare - return stringEscape(this.value.toString()) + formatString() { + if (this.stringCompare !== null) { + return this.stringCompare; + } + + return stringEscape(this.value.toString()); } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.symbol, this.formatString())) + formatDeep(theme) { + return lineBuilder.single(formatUtils.wrap(theme.symbol, this.formatString())); } - formatAsKey (theme) { - return formatUtils.wrap(theme.property.keyBracket, formatUtils.wrap(theme.symbol, this.formatString())) + formatAsKey(theme) { + return formatUtils.wrap(theme.property.keyBracket, formatUtils.wrap(theme.symbol, this.formatString())); } - serialize () { - const string = this.formatString() + serialize() { + const string = this.formatString(); return this.stringCompare === string ? [this.stringCompare] - : [this.stringCompare, string] + : [this.stringCompare, string]; } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } class DeserializedSymbolValue extends SymbolValue { - constructor (props) { - super(props) - this.string = props.string + constructor(props) { + super(props); + this.string = props.string; } - compare (expected) { - if (expected.tag !== tag) return UNEQUAL + compare(expected) { + if (expected.tag !== tag) { + return UNEQUAL; + } if (this.stringCompare !== null) { return this.stringCompare === expected.stringCompare ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } // Symbols that are not in the global symbol registry, and are not @@ -99,10 +106,10 @@ class DeserializedSymbolValue extends SymbolValue { // as equal if they are formatted the same. return this.string === expected.formatString() ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatString () { - return this.string + formatString() { + return this.string; } } diff --git a/lib/primitiveValues/undefined.js b/lib/primitiveValues/undefined.js index 2c1acf8..7d9f0b7 100644 --- a/lib/primitiveValues/undefined.js +++ b/lib/primitiveValues/undefined.js @@ -1,27 +1,27 @@ -import {DEEP_EQUAL, UNEQUAL} from '../constants.js' -import * as formatUtils from '../formatUtils.js' -import lineBuilder from '../lineBuilder.js' +import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; +import * as formatUtils from '../formatUtils.js'; +import lineBuilder from '../lineBuilder.js'; -export function describe () { - return new UndefinedValue() +export function describe() { + return new UndefinedValue(); } -export const deserialize = describe +export const deserialize = describe; -export const tag = Symbol('UndefinedValue') +export const tag = Symbol('UndefinedValue'); class UndefinedValue { - compare (expected) { + compare(expected) { return expected.tag === tag ? DEEP_EQUAL - : UNEQUAL + : UNEQUAL; } - formatDeep (theme) { - return lineBuilder.single(formatUtils.wrap(theme.undefined, 'undefined')) + formatDeep(theme) { + return lineBuilder.single(formatUtils.wrap(theme.undefined, 'undefined')); } - isPrimitive = true + isPrimitive = true; - tag = tag + tag = tag; } diff --git a/lib/recursorUtils.js b/lib/recursorUtils.js index 135a586..3aa41c5 100644 --- a/lib/recursorUtils.js +++ b/lib/recursorUtils.js @@ -1,116 +1,134 @@ export const NOOP_RECURSOR = { size: 0, - next () { return null }, -} + next() { + return null; + }, +}; -export function fork (recursor) { - const buffer = [] +export function fork(recursor) { + const buffer = []; return { - shared () { - const next = recursor() - if (next !== null) buffer.push(next) - return next + shared() { + const next = recursor(); + if (next !== null) { + buffer.push(next); + } + + return next; }, - recursor () { - if (buffer.length > 0) return buffer.shift() - return recursor() + recursor() { + if (buffer.length > 0) { + return buffer.shift(); + } + + return recursor(); }, - } + }; } -export function consumeDeep (recursor) { - const stack = [recursor] +export function consumeDeep(recursor) { + const stack = [recursor]; while (stack.length > 0) { - const subject = stack[stack.length - 1]() + const subject = stack.at(-1)(); if (subject === null) { - stack.pop() - continue + stack.pop(); + continue; } if (typeof subject.createRecursor === 'function') { - stack.push(subject.createRecursor()) + stack.push(subject.createRecursor()); } } } -export function map (recursor, mapFn) { +export function map(recursor, mapFn) { return () => { - const next = recursor() - if (next === null) return null + const next = recursor(); + if (next === null) { + return null; + } - return mapFn(next) - } + return mapFn(next); + }; } -export function replay (state, create) { +export function replay(state, create) { if (!state) { - const recursor = create() + const recursor = create(); if (recursor === NOOP_RECURSOR) { - state = recursor + state = recursor; } else { - state = Object.assign({ - buffer: [], - done: false, - }, recursor) + state = {buffer: [], + done: false, ...recursor}; } } - if (state === NOOP_RECURSOR) return { state, recursor: state } + if (state === NOOP_RECURSOR) { + return {state, recursor: state}; + } - let done = false - let index = 0 + let done = false; + let index = 0; const next = () => { - if (done) return null + if (done) { + return null; + } - let retval = state.buffer[index] + let retval = state.buffer[index]; if (retval === undefined) { - retval = state.buffer[index] = state.next() + // eslint-disable-next-line no-multi-assign + retval = state.buffer[index] = state.next(); } - index++ + index++; if (retval === null) { - done = true + done = true; } - return retval - } - return { state, recursor: { next, size: state.size } } + return retval; + }; + + return {state, recursor: {next, size: state.size}}; } -export function sequence (first, second) { - let fromFirst = true +export function sequence(first, second) { + let fromFirst = true; return () => { if (fromFirst) { - const next = first() - if (next !== null) return next + const next = first(); + if (next !== null) { + return next; + } - fromFirst = false + fromFirst = false; } - return second() - } + return second(); + }; } -export function singleValue (value) { - let done = false +export function singleValue(value) { + let done = false; return () => { - if (done) return null + if (done) { + return null; + } - done = true - return value - } + done = true; + return value; + }; } -export function unshift (recursor, value) { +export function unshift(recursor, value) { return () => { if (value !== null) { - const next = value - value = null - return next + const next = value; + value = null; + return next; } - return recursor() - } + return recursor(); + }; } diff --git a/lib/serialize.js b/lib/serialize.js index 10363af..20edef3 100644 --- a/lib/serialize.js +++ b/lib/serialize.js @@ -1,45 +1,40 @@ -import md5hex from 'md5-hex' - -import * as argumentsValue from './complexValues/arguments.js' -import * as arrayBufferValue from './complexValues/arrayBuffer.js' -import * as boxedValue from './complexValues/boxed.js' -import * as dataViewValue from './complexValues/dataView.js' -import * as dateValue from './complexValues/date.js' -import * as errorValue from './complexValues/error.js' -import * as functionValue from './complexValues/function.js' -import * as globalValue from './complexValues/global.js' -import * as mapValue from './complexValues/map.js' -import * as objectValue from './complexValues/object.js' -import * as promiseValue from './complexValues/promise.js' -import * as regexpValue from './complexValues/regexp.js' -import * as setValue from './complexValues/set.js' -import * as typedArrayValue from './complexValues/typedArray.js' - -import * as encoder from './encoder.js' - -import * as itemDescriptor from './metaDescriptors/item.js' -import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js' -import * as pointerDescriptor from './metaDescriptors/pointer.js' -import * as propertyDescriptor from './metaDescriptors/property.js' -import * as statsDescriptors from './metaDescriptors/stats.js' - -import * as pluginRegistry from './pluginRegistry.js' - -import * as bigIntValue from './primitiveValues/bigInt.js' -import * as booleanValue from './primitiveValues/boolean.js' -import * as nullValue from './primitiveValues/null.js' -import * as numberValue from './primitiveValues/number.js' -import * as stringValue from './primitiveValues/string.js' -import * as symbolValue from './primitiveValues/symbol.js' -import * as undefinedValue from './primitiveValues/undefined.js' - -import * as recursorUtils from './recursorUtils.js' +import md5hex from 'md5-hex'; + +import * as argumentsValue from './complexValues/arguments.js'; +import * as arrayBufferValue from './complexValues/arrayBuffer.js'; +import * as boxedValue from './complexValues/boxed.js'; +import * as dataViewValue from './complexValues/dataView.js'; +import * as dateValue from './complexValues/date.js'; +import * as errorValue from './complexValues/error.js'; +import * as functionValue from './complexValues/function.js'; +import * as globalValue from './complexValues/global.js'; +import * as mapValue from './complexValues/map.js'; +import * as objectValue from './complexValues/object.js'; +import * as promiseValue from './complexValues/promise.js'; +import * as regexpValue from './complexValues/regexp.js'; +import * as setValue from './complexValues/set.js'; +import * as typedArrayValue from './complexValues/typedArray.js'; +import * as encoder from './encoder.js'; +import * as itemDescriptor from './metaDescriptors/item.js'; +import * as mapEntryDescriptor from './metaDescriptors/mapEntry.js'; +import * as pointerDescriptor from './metaDescriptors/pointer.js'; +import * as propertyDescriptor from './metaDescriptors/property.js'; +import * as statsDescriptors from './metaDescriptors/stats.js'; +import * as pluginRegistry from './pluginRegistry.js'; +import * as bigIntValue from './primitiveValues/bigInt.js'; +import * as booleanValue from './primitiveValues/boolean.js'; +import * as nullValue from './primitiveValues/null.js'; +import * as numberValue from './primitiveValues/number.js'; +import * as stringValue from './primitiveValues/string.js'; +import * as symbolValue from './primitiveValues/symbol.js'; +import * as undefinedValue from './primitiveValues/undefined.js'; +import * as recursorUtils from './recursorUtils.js'; // Increment if encoding layout, descriptor IDs, or value types change. Previous // Concordance versions will not be able to decode buffers generated by a newer // version, so changing this value will require a major version bump of // Concordance itself. The version is encoded as an unsigned 16 bit integer. -const VERSION = 3 +const VERSION = 3; // Adding or removing mappings or changing an index requires the version in // encoder.js to be bumped, which necessitates a major version bump of @@ -80,126 +75,136 @@ const mappings = [ [0x1D, setValue.tag, setValue.deserialize], [0x1E, typedArrayValue.tag, typedArrayValue.deserialize], [0x1F, typedArrayValue.bytesTag, typedArrayValue.deserializeBytes], -] -const tag2id = new Map(mappings.map(mapping => [mapping[1], mapping[0]])) -const id2deserialize = new Map(mappings.map(mapping => [mapping[0], mapping[2]])) +]; +const tag2id = new Map(mappings.map(mapping => [mapping[1], mapping[0]])); +const id2deserialize = new Map(mappings.map(mapping => [mapping[0], mapping[2]])); class DescriptorSerializationError extends Error { - constructor (descriptor) { - super('Could not serialize descriptor') - this.name = 'DescriptorSerializationError' - this.descriptor = descriptor + constructor(descriptor) { + super('Could not serialize descriptor'); + this.name = 'DescriptorSerializationError'; + this.descriptor = descriptor; } } class MissingPluginError extends Error { - constructor (pluginName) { - super(`Could not deserialize buffer: missing plugin ${JSON.stringify(pluginName)}`) - this.name = 'MissingPluginError' - this.pluginName = pluginName + constructor(pluginName) { + super(`Could not deserialize buffer: missing plugin ${JSON.stringify(pluginName)}`); + this.name = 'MissingPluginError'; + this.pluginName = pluginName; } } class PointerLookupError extends Error { - constructor (index) { - super(`Could not deserialize buffer: pointer ${index} could not be resolved`) - this.name = 'PointerLookupError' - this.index = index + constructor(index) { + super(`Could not deserialize buffer: pointer ${index} could not be resolved`); + this.name = 'PointerLookupError'; + this.index = index; } } class UnsupportedPluginError extends Error { - constructor (pluginName, serializerVersion) { - super(`Could not deserialize buffer: plugin ${JSON.stringify(pluginName)} expects a different serialization`) - this.name = 'UnsupportedPluginError' - this.pluginName = pluginName - this.serializerVersion = serializerVersion + constructor(pluginName, serializerVersion) { + super(`Could not deserialize buffer: plugin ${JSON.stringify(pluginName)} expects a different serialization`); + this.name = 'UnsupportedPluginError'; + this.pluginName = pluginName; + this.serializerVersion = serializerVersion; } } -class UnsupportedVersion extends Error { // eslint-disable-line unicorn/custom-error-definition - constructor (serializerVersion) { - super('Could not deserialize buffer: a different serialization was expected') - this.name = 'UnsupportedVersion' - this.serializerVersion = serializerVersion +class UnsupportedVersion extends Error { + constructor(serializerVersion) { + super('Could not deserialize buffer: a different serialization was expected'); + this.name = 'UnsupportedVersion'; + this.serializerVersion = serializerVersion; } } -function shallowSerializeDescriptor (descriptor, resolvePluginRef) { - if (!descriptor.serialize) return undefined +function shallowSerializeDescriptor(descriptor, resolvePluginRef) { + if (!descriptor.serialize) { + return undefined; + } - return serializeState(descriptor.serialize(), resolvePluginRef) + return serializeState(descriptor.serialize(), resolvePluginRef); } -function serializeState (state, resolvePluginRef) { - if (Array.isArray(state)) return state.map(x => serializeState(x)) +function serializeState(state, resolvePluginRef) { + if (Array.isArray(state)) { + return state.map(x => serializeState(x)); + } if (state && state.tag) { - let id, pluginIndex + let id; + let pluginIndex; + if (tag2id.has(state.tag)) { - id = tag2id.get(state.tag) - pluginIndex = 0 + id = tag2id.get(state.tag); + pluginIndex = 0; } else { - const ref = resolvePluginRef(state.tag) + const ref = resolvePluginRef(state.tag); if (ref) { - id = ref.id - pluginIndex = ref.pluginIndex + id = ref.id; + pluginIndex = ref.pluginIndex; } } if (id !== undefined) { - const serialized = [pluginIndex, id, shallowSerializeDescriptor(state, resolvePluginRef)] - serialized[encoder.descriptorSymbol] = true - return serialized + const serialized = [pluginIndex, id, shallowSerializeDescriptor(state, resolvePluginRef)]; + serialized[encoder.descriptorSymbol] = true; + return serialized; } } - return state + return state; } -export function serialize (descriptor) { - const usedPlugins = new Map() +export function serialize(descriptor) { + const usedPlugins = new Map(); const resolvePluginRef = tag => { - const ref = pluginRegistry.resolveDescriptorRef(tag) - if (!ref) return null + const ref = pluginRegistry.resolveDescriptorRef(tag); + if (!ref) { + return null; + } if (!usedPlugins.has(ref.name)) { // Start at 1, since 0 is reserved for Concordance's descriptors. - const index = usedPlugins.size + 1 - usedPlugins.set(ref.name, Object.assign({ index }, ref.serialization)) + const index = usedPlugins.size + 1; + usedPlugins.set(ref.name, {index, ...ref.serialization}); } return { id: ref.id, pluginIndex: usedPlugins.get(ref.name).index, - } - } + }; + }; - const seen = new Set() + const seen = new Set(); - const stack = [] - let topIndex = -1 + const stack = []; + let topIndex = -1; - let rootRecord + let rootRecord; do { if (descriptor.isComplex === true) { if (seen.has(descriptor.pointer)) { - descriptor = pointerDescriptor.describe(descriptor.pointer) + descriptor = pointerDescriptor.describe(descriptor.pointer); } else { - seen.add(descriptor.pointer) + seen.add(descriptor.pointer); } } - let id - let pluginIndex = 0 + let id; + let pluginIndex = 0; if (tag2id.has(descriptor.tag)) { - id = tag2id.get(descriptor.tag) + id = tag2id.get(descriptor.tag); } else { - const ref = resolvePluginRef(descriptor.tag) - if (!ref) throw new DescriptorSerializationError(descriptor) + const ref = resolvePluginRef(descriptor.tag); + if (!ref) { + throw new DescriptorSerializationError(descriptor); + } - id = ref.id - pluginIndex = ref.pluginIndex + id = ref.id; + pluginIndex = ref.pluginIndex; } const record = { @@ -207,151 +212,162 @@ export function serialize (descriptor) { pluginIndex, children: [], state: shallowSerializeDescriptor(descriptor, resolvePluginRef), - } - if (!rootRecord) { - rootRecord = record + }; + if (rootRecord) { + stack[topIndex].children.push(record); } else { - stack[topIndex].children.push(record) + rootRecord = record; } if (descriptor.createRecursor) { - stack.push({ recursor: descriptor.createRecursor(), children: record.children }) - topIndex++ + stack.push({recursor: descriptor.createRecursor(), children: record.children}); + topIndex++; } while (topIndex >= 0) { - descriptor = stack[topIndex].recursor() + descriptor = stack[topIndex].recursor(); if (descriptor === null) { - stack.pop() - topIndex-- + stack.pop(); + topIndex--; } else { - break + break; } } - } while (topIndex >= 0) + } while (topIndex >= 0); - return encoder.encode(VERSION, rootRecord, usedPlugins) + return encoder.encode(VERSION, rootRecord, usedPlugins); } -function deserializeState (state, getDescriptorDeserializer) { +function deserializeState(state, getDescriptorDeserializer) { if (state && state[encoder.descriptorSymbol] === true) { - return shallowDeserializeDescriptor(state, getDescriptorDeserializer) + return shallowDeserializeDescriptor(state, getDescriptorDeserializer); } return Array.isArray(state) ? state.map(item => deserializeState(item, getDescriptorDeserializer)) - : state + : state; } -function shallowDeserializeDescriptor (entry, getDescriptorDeserializer) { - const deserializeDescriptor = getDescriptorDeserializer(entry[0], entry[1]) - return deserializeDescriptor(entry[2]) +function shallowDeserializeDescriptor(entry, getDescriptorDeserializer) { + const deserializeDescriptor = getDescriptorDeserializer(entry[0], entry[1]); + return deserializeDescriptor(entry[2]); } -function deserializeRecord (record, getDescriptorDeserializer, buffer) { - const deserializeDescriptor = getDescriptorDeserializer(record.pluginIndex, record.id) - const state = deserializeState(record.state, getDescriptorDeserializer) +function deserializeRecord(record, getDescriptorDeserializer, buffer) { + const deserializeDescriptor = getDescriptorDeserializer(record.pluginIndex, record.id); + const state = deserializeState(record.state, getDescriptorDeserializer); if (record.pointerAddresses.length === 0) { - return deserializeDescriptor(state) + return deserializeDescriptor(state); } - const endIndex = record.pointerAddresses.length - let index = 0 + const endIndex = record.pointerAddresses.length; + let index = 0; const recursor = () => { - if (index === endIndex) return null + if (index === endIndex) { + return null; + } - const recursorRecord = encoder.decodeRecord(buffer, record.pointerAddresses[index++]) - return deserializeRecord(recursorRecord, getDescriptorDeserializer, buffer) - } + const recursorRecord = encoder.decodeRecord(buffer, record.pointerAddresses[index++]); + return deserializeRecord(recursorRecord, getDescriptorDeserializer, buffer); + }; - return deserializeDescriptor(state, recursor) + return deserializeDescriptor(state, recursor); } -function buildPluginMap (buffer, options) { - const cache = options && options.deserializedPluginsCache - const cacheKey = md5hex(buffer) - if (cache && cache.has(cacheKey)) return cache.get(cacheKey) +function buildPluginMap(buffer, options) { + const cache = options && options.deserializedPluginsCache; + const cacheKey = md5hex(buffer); + if (cache && cache.has(cacheKey)) { + return cache.get(cacheKey); + } - const decodedPlugins = encoder.decodePlugins(buffer) + const decodedPlugins = encoder.decodePlugins(buffer); if (decodedPlugins.size === 0) { - const pluginMap = new Map() - if (cache) cache.set(cacheKey, pluginMap) - return pluginMap + const pluginMap = new Map(); + if (cache) { + cache.set(cacheKey, pluginMap); + } + + return pluginMap; } - const deserializerLookup = new Map() + const deserializerLookup = new Map(); if (Array.isArray(options && options.plugins)) { for (const deserializer of pluginRegistry.getDeserializers(options.plugins)) { - deserializerLookup.set(deserializer.name, deserializer) + deserializerLookup.set(deserializer.name, deserializer); } } - const pluginMap = new Map() + const pluginMap = new Map(); for (const index of decodedPlugins.keys()) { - const used = decodedPlugins.get(index) - const pluginName = used.name - const serializerVersion = used.serializerVersion + const used = decodedPlugins.get(index); + const pluginName = used.name; + const {serializerVersion} = used; // TODO: Allow plugin author to encode a helpful message in its serialization if (!deserializerLookup.has(pluginName)) { - throw new MissingPluginError(pluginName) + throw new MissingPluginError(pluginName); } + if (serializerVersion !== deserializerLookup.get(pluginName).serializerVersion) { - throw new UnsupportedPluginError(pluginName, serializerVersion) + throw new UnsupportedPluginError(pluginName, serializerVersion); } - pluginMap.set(index, deserializerLookup.get(pluginName).id2deserialize) + pluginMap.set(index, deserializerLookup.get(pluginName).id2deserialize); + } + + if (cache) { + cache.set(cacheKey, pluginMap); } - if (cache) cache.set(cacheKey, pluginMap) - return pluginMap + return pluginMap; } -export function deserialize (buffer, options) { - const version = encoder.extractVersion(buffer) - if (version !== VERSION) throw new UnsupportedVersion(version) +export function deserialize(buffer, options) { + const version = encoder.extractVersion(buffer); + if (version !== VERSION) { + throw new UnsupportedVersion(version); + } - const decoded = encoder.decode(buffer) - const pluginMap = buildPluginMap(decoded.pluginBuffer, options) + const decoded = encoder.decode(buffer); + const pluginMap = buildPluginMap(decoded.pluginBuffer, options); - const descriptorsByPointerIndex = new Map() + const descriptorsByPointerIndex = new Map(); const mapPointerDescriptor = descriptor => { if (descriptor.isPointer === true) { if (descriptorsByPointerIndex.has(descriptor.index)) { - return descriptorsByPointerIndex.get(descriptor.index) + return descriptorsByPointerIndex.get(descriptor.index); } if (typeof rootDescriptor.createRecursor === 'function') { // The descriptor we're pointing to may be elsewhere in the serialized // structure. Consume the entire structure and check again. - recursorUtils.consumeDeep(rootDescriptor.createRecursor()) + recursorUtils.consumeDeep(rootDescriptor.createRecursor()); if (descriptorsByPointerIndex.has(descriptor.index)) { - return descriptorsByPointerIndex.get(descriptor.index) + return descriptorsByPointerIndex.get(descriptor.index); } } - throw new PointerLookupError(descriptor.index) + throw new PointerLookupError(descriptor.index); } if (descriptor.isComplex === true) { - descriptorsByPointerIndex.set(descriptor.pointer, descriptor) + descriptorsByPointerIndex.set(descriptor.pointer, descriptor); } - return descriptor - } + return descriptor; + }; - const getDescriptorDeserializer = (pluginIndex, id) => { - return (state, recursor) => { - const deserializeDescriptor = pluginIndex === 0 - ? id2deserialize.get(id) - : pluginMap.get(pluginIndex).get(id) + const getDescriptorDeserializer = (pluginIndex, id) => (state, recursor) => { + const deserializeDescriptor = pluginIndex === 0 + ? id2deserialize.get(id) + : pluginMap.get(pluginIndex).get(id); - return mapPointerDescriptor(deserializeDescriptor(state, recursor)) - } - } + return mapPointerDescriptor(deserializeDescriptor(state, recursor)); + }; - const rootDescriptor = deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer) - return rootDescriptor + const rootDescriptor = deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer); + return rootDescriptor; } diff --git a/lib/shouldCompareDeep.js b/lib/shouldCompareDeep.js index 1d34152..f529df1 100644 --- a/lib/shouldCompareDeep.js +++ b/lib/shouldCompareDeep.js @@ -1,11 +1,16 @@ -import { tag as argumentsObject } from './complexValues/arguments.js' -import { AMBIGUOUS, SHALLOW_EQUAL } from './constants.js' +import {tag as argumentsObject} from './complexValues/arguments.js'; +import {AMBIGUOUS, SHALLOW_EQUAL} from './constants.js'; -export default function shouldCompareDeep (result, lhs, rhs) { - if (result === SHALLOW_EQUAL) return true - if (result !== AMBIGUOUS) return false +export default function shouldCompareDeep(result, lhs, _rhs) { + if (result === SHALLOW_EQUAL) { + return true; + } + + if (result !== AMBIGUOUS) { + return false; + } // Properties are only ambiguous if they have symbol keys. These properties // must be compared in an order-insensitive manner. - return lhs.tag === argumentsObject || lhs.isProperty === true + return lhs.tag === argumentsObject || lhs.isProperty === true; } diff --git a/lib/symbolProperties.js b/lib/symbolProperties.js index f645cbe..9c9abdb 100644 --- a/lib/symbolProperties.js +++ b/lib/symbolProperties.js @@ -1,100 +1,112 @@ -import { DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL } from './constants.js' -import * as recursorUtils from './recursorUtils.js' +import {DEEP_EQUAL, SHALLOW_EQUAL, UNEQUAL} from './constants.js'; +import * as recursorUtils from './recursorUtils.js'; export class Comparable { - constructor (properties) { - this.properties = properties - this.ordered = properties.slice() + constructor(properties) { + this.properties = properties; + this.ordered = [...properties]; } - createRecursor () { - const length = this.ordered.length - let index = 0 + createRecursor() { + const {length} = this.ordered; + let index = 0; return () => { - if (index === length) return null + if (index === length) { + return null; + } - return this.ordered[index++] - } + return this.ordered[index++]; + }; } - compare (expected) { - if (this.properties.length !== expected.properties.length) return UNEQUAL + compare(expected) { + if (this.properties.length !== expected.properties.length) { + return UNEQUAL; + } // Compare property keys, reordering the expected properties in the process // so values can be compared if all keys are equal. - const ordered = [] - const processed = new Set() + const ordered = []; + const processed = new Set(); for (const property of this.properties) { - let extraneous = true + let extraneous = true; for (const other of expected.properties) { - if (processed.has(other.key)) continue + if (processed.has(other.key)) { + continue; + } if (property.key.compare(other.key) === DEEP_EQUAL) { - extraneous = false - processed.add(other.key) - ordered.push(other) - break + extraneous = false; + processed.add(other.key); + ordered.push(other); + break; } } - if (extraneous) return UNEQUAL + if (extraneous) { + return UNEQUAL; + } } - expected.ordered = ordered - return SHALLOW_EQUAL + expected.ordered = ordered; + + return SHALLOW_EQUAL; } - prepareDiff (expected) { + prepareDiff(expected) { // Reorder the expected properties before recursion starts. - const missingProperties = [] - const ordered = [] - const processed = new Set() + const missingProperties = []; + const ordered = []; + const processed = new Set(); for (const other of expected.properties) { - let missing = true + let missing = true; for (const property of this.properties) { - if (processed.has(property.key)) continue + if (processed.has(property.key)) { + continue; + } if (property.key.compare(other.key) === DEEP_EQUAL) { - missing = false - processed.add(property.key) - ordered.push(other) - break + missing = false; + processed.add(property.key); + ordered.push(other); + break; } } if (missing) { - missingProperties.push(other) + missingProperties.push(other); } } - expected.ordered = ordered.concat(missingProperties) - return { mustRecurse: true } + expected.ordered = [...ordered, ...missingProperties]; + + return {mustRecurse: true}; } - isSymbolPropertiesComparable = true + isSymbolPropertiesComparable = true; } export class Collector { - constructor (firstProperty, recursor) { - this.properties = [firstProperty] - this.recursor = recursor - this.remainder = null + constructor(firstProperty, recursor) { + this.properties = [firstProperty]; + this.recursor = recursor; + this.remainder = null; } - collectAll () { + collectAll() { do { - const next = this.recursor() + const next = this.recursor(); if (next && next.isProperty === true) { // All properties will have symbol keys - this.properties.push(next) + this.properties.push(next); } else { - return next + return next; } - } while (true) + } while (true); // eslint-disable-line no-constant-condition } - createRecursor () { - return recursorUtils.singleValue(new Comparable(this.properties)) + createRecursor() { + return recursorUtils.singleValue(new Comparable(this.properties)); } - isSymbolPropertiesCollector = true + isSymbolPropertiesCollector = true; } diff --git a/lib/themeUtils.js b/lib/themeUtils.js index df1c732..3adf7ff 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -1,188 +1,199 @@ -import {cloneDeep, merge} from './lodash/index.js' -import * as pluginRegistry from './pluginRegistry.js' +import {cloneDeep, merge} from './lodash/index.js'; +import * as pluginRegistry from './pluginRegistry.js'; -function freezeTheme (theme) { - const queue = [theme] +function freezeTheme(theme) { + const queue = [theme]; while (queue.length > 0) { - const object = queue.shift() - Object.freeze(object) + const object = queue.shift(); + Object.freeze(object); for (const key of Object.keys(object)) { - const value = object[key] + const value = object[key]; if (value !== null && typeof value === 'object') { - queue.push(value) + queue.push(value); } } } - return theme + return theme; } const defaultTheme = freezeTheme({ - bigInt: { open: '', close: '' }, - boolean: { open: '', close: '' }, + bigInt: {open: '', close: ''}, + boolean: {open: '', close: ''}, circular: '[Circular]', date: { invalid: 'invalid', - value: { open: '', close: '' }, + value: {open: '', close: ''}, }, diffGutters: { actual: '- ', expected: '+ ', - padding: ' ', + padding: ' ', }, error: { - ctor: { open: '(', close: ')' }, - name: { open: '', close: '' }, + ctor: {open: '(', close: ')'}, + name: {open: '', close: ''}, }, function: { - name: { open: '', close: '' }, - stringTag: { open: '', close: '' }, + name: {open: '', close: ''}, + stringTag: {open: '', close: ''}, }, - global: { open: '', close: '' }, + global: {open: '', close: ''}, item: { after: ',', customFormat: null, increaseValueIndent: false, }, - list: { openBracket: '[', closeBracket: ']' }, + list: {openBracket: '[', closeBracket: ']'}, mapEntry: { after: ',', separator: ' => ', }, maxDepth: '…', - null: { open: '', close: '' }, - number: { open: '', close: '' }, + null: {open: '', close: ''}, + number: {open: '', close: ''}, object: { openBracket: '{', closeBracket: '}', - ctor: { open: '', close: '' }, - stringTag: { open: '@', close: '' }, - secondaryStringTag: { open: '@', close: '' }, + ctor: {open: '', close: ''}, + stringTag: {open: '@', close: ''}, + secondaryStringTag: {open: '@', close: ''}, }, property: { after: ',', customFormat: null, - keyBracket: { open: '[', close: ']' }, + keyBracket: {open: '[', close: ']'}, separator: ': ', increaseValueIndent: false, }, regexp: { - source: { open: '/', close: '/' }, - flags: { open: '', close: '' }, + source: {open: '/', close: '/'}, + flags: {open: '', close: ''}, separator: '---', }, - stats: { separator: '---' }, + stats: {separator: '---'}, string: { open: '', close: '', - line: { open: "'", close: "'", escapeQuote: "'" }, - multiline: { start: '`', end: '`', escapeQuote: '`' }, - controlPicture: { open: '', close: '' }, + line: {open: '\'', close: '\'', escapeQuote: '\''}, + multiline: {start: '`', end: '`', escapeQuote: '`'}, + controlPicture: {open: '', close: ''}, diff: { - insert: { open: '', close: '' }, - delete: { open: '', close: '' }, - equal: { open: '', close: '' }, - insertLine: { open: '', close: '' }, - deleteLine: { open: '', close: '' }, + insert: {open: '', close: ''}, + delete: {open: '', close: ''}, + equal: {open: '', close: ''}, + insertLine: {open: '', close: ''}, + deleteLine: {open: '', close: ''}, }, }, - symbol: { open: '', close: '' }, + symbol: {open: '', close: ''}, typedArray: { - bytes: { open: '', close: '' }, + bytes: {open: '', close: ''}, }, - undefined: { open: '', close: '' }, -}) - -const pluginRefs = new Map() -pluginRefs.count = 0 -const normalizedPluginThemes = new Map() -function normalizePlugins (plugins) { - if (!Array.isArray(plugins) || plugins.length === 0) return null + undefined: {open: '', close: ''}, +}); + +const pluginRefs = new Map(); +pluginRefs.count = 0; +const normalizedPluginThemes = new Map(); +function normalizePlugins(plugins) { + if (!Array.isArray(plugins) || plugins.length === 0) { + return null; + } - const refs = [] - const themes = [] + const refs = []; + const themes = []; for (const fromPlugin of pluginRegistry.getThemes(plugins)) { if (!pluginRefs.has(fromPlugin.name)) { - pluginRefs.set(fromPlugin.name, pluginRefs.count++) + pluginRefs.set(fromPlugin.name, pluginRefs.count++); } - refs.push(pluginRefs.get(fromPlugin.name)) - themes.push(fromPlugin.theme) + refs.push(pluginRefs.get(fromPlugin.name)); + themes.push(fromPlugin.theme); } - const ref = refs.join('.') + const ref = refs.join('.'); if (normalizedPluginThemes.has(ref)) { return { ref, theme: normalizedPluginThemes.get(ref), - } + }; } - const theme = freezeTheme(themes.reduce((acc, pluginTheme) => { - return merge(acc, pluginTheme) - }, cloneDeep(defaultTheme))) - normalizedPluginThemes.set(ref, theme) - return { ref, theme } + // eslint-disable-next-line unicorn/no-array-reduce + const theme = freezeTheme(themes.reduce((acc, pluginTheme) => merge(acc, pluginTheme), cloneDeep(defaultTheme))); + normalizedPluginThemes.set(ref, theme); + return {ref, theme}; } -const normalizedCache = new WeakMap() -export function normalize (options) { - options = Object.assign({ plugins: [], theme: null }, options) +const normalizedCache = new WeakMap(); +export function normalize(options) { + options = {plugins: [], theme: null, ...options}; - const normalizedPlugins = normalizePlugins(options.plugins) + const normalizedPlugins = normalizePlugins(options.plugins); if (!options.theme) { - return normalizedPlugins ? normalizedPlugins.theme : defaultTheme + return normalizedPlugins ? normalizedPlugins.theme : defaultTheme; } - const entry = normalizedCache.get(options.theme) || { theme: null, withPlugins: new Map() } - if (!normalizedCache.has(options.theme)) normalizedCache.set(options.theme, entry) + const entry = normalizedCache.get(options.theme) || {theme: null, withPlugins: new Map()}; + if (!normalizedCache.has(options.theme)) { + normalizedCache.set(options.theme, entry); + } if (normalizedPlugins) { if (entry.withPlugins.has(normalizedPlugins.ref)) { - return entry.withPlugins.get(normalizedPlugins.ref) + return entry.withPlugins.get(normalizedPlugins.ref); } - const theme = freezeTheme(merge(cloneDeep(normalizedPlugins.theme), options.theme)) - entry.withPlugins.set(normalizedPlugins.ref, theme) - return theme + const theme = freezeTheme(merge(cloneDeep(normalizedPlugins.theme), options.theme)); + entry.withPlugins.set(normalizedPlugins.ref, theme); + return theme; } if (!entry.theme) { - entry.theme = freezeTheme(merge(cloneDeep(defaultTheme), options.theme)) + entry.theme = freezeTheme(merge(cloneDeep(defaultTheme), options.theme)); } - return entry.theme + + return entry.theme; } -const modifiers = new WeakMap() -export function addModifier (descriptor, modifier) { +const modifiers = new WeakMap(); +export function addModifier(descriptor, modifier) { if (modifiers.has(descriptor)) { - modifiers.get(descriptor).add(modifier) + modifiers.get(descriptor).add(modifier); } else { - modifiers.set(descriptor, new Set([modifier])) + modifiers.set(descriptor, new Set([modifier])); } } -const modifierCache = new WeakMap() -const originalCache = new WeakMap() -export function applyModifiers (descriptor, theme) { - if (!modifiers.has(descriptor)) return theme +const modifierCache = new WeakMap(); +const originalCache = new WeakMap(); +export function applyModifiers(descriptor, theme) { + if (!modifiers.has(descriptor)) { + return theme; + } - return Array.from(modifiers.get(descriptor)).reduce((prev, modifier) => { - const cache = modifierCache.get(modifier) || new WeakMap() - if (!modifierCache.has(modifier)) modifierCache.set(modifier, cache) + // eslint-disable-next-line unicorn/no-array-reduce + return [...modifiers.get(descriptor)].reduce((previous, modifier) => { + const cache = modifierCache.get(modifier) || new WeakMap(); + if (!modifierCache.has(modifier)) { + modifierCache.set(modifier, cache); + } - if (cache.has(prev)) return cache.get(prev) + if (cache.has(previous)) { + return cache.get(previous); + } - const modifiedTheme = cloneDeep(prev) - modifier(modifiedTheme) - freezeTheme(modifiedTheme) - cache.set(prev, modifiedTheme) - originalCache.set(modifiedTheme, theme) - return modifiedTheme - }, theme) + const modifiedTheme = cloneDeep(previous); + modifier(modifiedTheme); + freezeTheme(modifiedTheme); + cache.set(previous, modifiedTheme); + originalCache.set(modifiedTheme, theme); + return modifiedTheme; + }, theme); } -export function applyModifiersToOriginal (descriptor, theme) { - return applyModifiers(descriptor, originalCache.get(theme) || theme) +export function applyModifiersToOriginal(descriptor, theme) { + return applyModifiers(descriptor, originalCache.get(theme) || theme); } diff --git a/package.json b/package.json index 609d883..ca85e2f 100644 --- a/package.json +++ b/package.json @@ -1,59 +1,73 @@ { - "name": "concordance", - "version": "5.0.4", - "description": "Compare, format, diff and serialize any JavaScript value", - "type": "module", - "exports": { - "default": "./index.js" - }, - "files": [ - "lib", - "index.js" - ], - "engines": { - "node": ">=16.9" - }, - "scripts": { - "test": "as-i-preach && c8 ava" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/concordancejs/concordance.git" - }, - "author": "Mark Wubben (https://novemberborn.net/)", - "license": "ISC", - "bugs": { - "url": "https://github.com/concordancejs/concordance/issues" - }, - "homepage": "https://github.com/concordancejs/concordance#readme", - "dependencies": { - "date-time": "^4.0.0", - "esutils": "^2.0.3", - "fast-diff": "^1.3.0", - "js-string-escape": "^1.0.1", - "md5-hex": "^4.0.0", - "semver": "^7.5.4", - "well-known-symbols": "^2.0.0" - }, - "devDependencies": { - "@novemberborn/eslint-plugin-as-i-preach": "^12.0.0", - "@types/node": "16.9", - "ava": "^3.15.0", - "c8": "^8.0.1", - "eslint": "^6.8.0", - "eslint-plugin-ava": "^10.3.0", - "eslint-plugin-import": "^2.20.2", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", - "eslint-plugin-security": "^1.4.0", - "eslint-plugin-standard": "^4.0.1", - "eslint-plugin-unicorn": "^17.2.0", - "esmock": "^2.3.8" - }, - "ava": { - "nodeArguments": [ - "--loader=esmock", - "--no-warnings=ExperimentalWarning" - ] - } + "name": "concordance", + "version": "5.0.4", + "description": "Compare, format, diff and serialize any JavaScript value", + "type": "module", + "exports": { + "default": "./index.js" + }, + "files": [ + "lib", + "index.js" + ], + "engines": { + "node": ">=16.9" + }, + "scripts": { + "test": "xo && c8 ava" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/concordancejs/concordance.git" + }, + "author": "Mark Wubben (https://novemberborn.net/)", + "license": "ISC", + "bugs": { + "url": "https://github.com/concordancejs/concordance/issues" + }, + "homepage": "https://github.com/concordancejs/concordance#readme", + "dependencies": { + "date-time": "^4.0.0", + "esutils": "^2.0.3", + "fast-diff": "^1.3.0", + "js-string-escape": "^1.0.1", + "md5-hex": "^4.0.0", + "semver": "^7.5.4", + "well-known-symbols": "^2.0.0" + }, + "devDependencies": { + "@types/node": "16.9", + "ava": "^3.15.0", + "c8": "^8.0.1", + "esmock": "^2.3.8", + "xo": "^0.56.0" + }, + "xo": { + "ignores": [ + "lib/lodash" + ], + "rules": { + "import/order": [ + "error", + { + "alphabetize": { + "order": "asc" + }, + "newlines-between": "always" + } + ], + "import/newline-after-import": "error", + "unicorn/require-post-message-target-origin": "off", + "unicorn/filename-case": "off", + "import/no-anonymous-default-export": "off", + "new-cap": "off", + "func-names": "off" + } + }, + "ava": { + "nodeArguments": [ + "--loader=esmock", + "--no-warnings=ExperimentalWarning" + ] + } } diff --git a/test/_instrumentedTheme.js b/test/_instrumentedTheme.js index 548724d..39b9b39 100644 --- a/test/_instrumentedTheme.js +++ b/test/_instrumentedTheme.js @@ -1,36 +1,37 @@ -import { normalize } from '../lib/themeUtils.js' +import {normalize} from '../lib/themeUtils.js'; -const unused = new Set() +const unused = new Set(); -const freeze = Object.freeze +const {freeze} = Object; const createAccessors = (object, path = '') => { for (const key of Object.keys(object)) { - const value = object[key] - const keyPath = path ? `${path}.${key}` : key + const value = object[key]; + const keyPath = path ? `${path}.${key}` : key; if (value && typeof value === 'object') { - createAccessors(value, keyPath) + createAccessors(value, keyPath); } else if (typeof value === 'string') { - unused.add(keyPath) + unused.add(keyPath); Object.defineProperty(object, key, { - get () { - unused.delete(keyPath) - return `%${keyPath}${value ? '#' + value : ''}%` + get() { + unused.delete(keyPath); + return `%${keyPath}${value ? '#' + value : ''}%`; }, - }) + }); } } - freeze.call(Object, object) -} -export const theme = {} // normalize() caches the result, so this is just a cache key + freeze.call(Object, object); +}; -Object.freeze = obj => obj // Stub out so accessors can be created -const normalized = normalize({ theme }) -createAccessors(normalized) -Object.freeze = freeze +export const theme = {}; // Normalize() caches the result, so this is just a cache key -export const normalizedTheme = normalized +Object.freeze = object => object; // Stub out so accessors can be created +const normalized = normalize({theme}); +createAccessors(normalized); +Object.freeze = freeze; + +export const normalizedTheme = normalized; export const checkThemeUsage = t => { - t.deepEqual(unused, new Set(), 'All theme properties should be accessed at least once') -} + t.deepEqual(unused, new Set(), 'All theme properties should be accessed at least once'); +}; diff --git a/test/compare.js b/test/compare.js index b608ab4..498d8e6 100644 --- a/test/compare.js +++ b/test/compare.js @@ -1,67 +1,78 @@ -import test from 'ava' -import {compare} from '../lib/compare.js' +import test from 'ava'; + +import {compare} from '../lib/compare.js'; test('compare functions by reference', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - const a_ = (() => { - return function a () { return 1 + 2 } // eslint-disable-line no-shadow - })() + function a() { + return 1 + 2; + } + + const a_ = (() => + function a() { + return 1 + 2; + } + )(); - t.false(compare(a, a_).pass) -}) + t.false(compare(a, a_).pass); +}); test('compare function by names', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping + function a() { + return 1 + 2; + } - t.false(compare(a, b).pass) -}) + function b() { + return 1 + 2; + } + + t.false(compare(a, b).pass); +}); test('objects compare even if symbol properties are out of order', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const o1 = { [s1]: 1, [s2]: 2 } - const o2 = { [s2]: 2, [s1]: 1 } + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); + const o1 = {[s1]: 1, [s2]: 2}; + const o2 = {[s2]: 2, [s1]: 1}; - t.true(compare(o1, o2).pass) + t.true(compare(o1, o2).pass); - const a1 = new Set([1, 2]) - a1[s1] = 1 - a1[s2] = 2 - const a2 = new Set([1, 2]) - a2[s2] = 2 - a2[s1] = 1 + const a1 = new Set([1, 2]); + a1[s1] = 1; + a1[s2] = 2; + const a2 = new Set([1, 2]); + a2[s2] = 2; + a2[s1] = 1; - t.true(compare(a1, a2).pass) -}) + t.true(compare(a1, a2).pass); +}); test('-0 is not equal to +0', t => { - t.false(compare(-0, +0).pass) - t.false(compare({ zero: -0 }, { zero: +0 }).pass) -}) + t.false(compare(-0, +0).pass); + t.false(compare({zero: -0}, {zero: +0}).pass); +}); test('NaN is equal to NaN', t => { - t.true(compare(NaN, NaN).pass) - t.true(compare({ notANumber: NaN }, { notANumber: NaN }).pass) -}) + t.true(compare(Number.NaN, Number.NaN).pass); + t.true(compare({notANumber: Number.NaN}, {notANumber: Number.NaN}).pass); +}); test('survives odd circular references', t => { - const foo = { foo: {} } - foo.foo.foo = foo - const foo2 = {} - foo2.foo = foo - t.false(compare(foo, foo2).pass) -}) + const foo = {foo: {}}; + foo.foo.foo = foo; + const foo2 = {}; + foo2.foo = foo; + t.false(compare(foo, foo2).pass); +}); test('arrays are also compared by property', t => { - const a1 = [1, 2, 3] - a1.p = 'a1' - const a2 = [1, 2, 3] - a2.p = 'a2' - t.false(compare(a1, a2).pass) - - const a3 = [1, 2, 3] - const a4 = [1, 2, 3] - a4[-1] = -1 - t.false(compare(a3, a4).pass) -}) + const a1 = [1, 2, 3]; + a1.p = 'a1'; + const a2 = [1, 2, 3]; + a2.p = 'a2'; + t.false(compare(a1, a2).pass); + + const a3 = [1, 2, 3]; + const a4 = [1, 2, 3]; + a4[-1] = -1; + t.false(compare(a3, a4).pass); +}); diff --git a/test/diff.js b/test/diff.js index dc52653..89d7864 100644 --- a/test/diff.js +++ b/test/diff.js @@ -1,30 +1,33 @@ -import test from 'ava' +/* eslint-disable max-params */ +import {Buffer} from 'node:buffer'; -import concordance from '../index.js' -import {diff as _diff} from '../lib/diff.js' +import test from 'ava'; -import { theme, normalizedTheme, checkThemeUsage } from './_instrumentedTheme.js' +import concordance from '../index.js'; +import {diff as _diff} from '../lib/diff.js'; -const diff = (actual, expected, { invert } = {}) => _diff(actual, expected, { invert, theme }) -test.after(checkThemeUsage) +import {theme, normalizedTheme, checkThemeUsage} from './_instrumentedTheme.js'; +const diff = (actual, expected, {invert} = {}) => _diff(actual, expected, {invert, theme}); +test.after(checkThemeUsage); + +// eslint-disable-next-line no-void void ( // Tested separately normalizedTheme.maxDepth -) +); if (typeof BigInt === 'undefined') { + // eslint-disable-next-line no-void void ( normalizedTheme.bigInt.open, normalizedTheme.bigInt.close - ) + ); } { - const diffsPrimitives = (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)) - diffsPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { - return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` - } + const diffsPrimitives = (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)); + diffsPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`; for (const [lhs, rhs] of [ [null, undefined], [null, false], @@ -35,65 +38,65 @@ if (typeof BigInt === 'undefined') { [Symbol(), Symbol()], // eslint-disable-line symbol-description [null, {}], ]) { - test(diffsPrimitives, lhs, rhs) + test(diffsPrimitives, lhs, rhs); } if (typeof BigInt === 'function') { - test(diffsPrimitives, null, BigInt(42), 'null', '42n') // eslint-disable-line no-undef + test(diffsPrimitives, null, BigInt(42), 'null', '42n'); } } { - const diffsBoxedPrimitives = (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))) - diffsBoxedPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => { - return `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}` - } + // eslint-disable-next-line no-new-object + const diffsBoxedPrimitives = (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))); + diffsBoxedPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`; for (const [lhs, rhs] of [ [true, false], [-42, 42], ['foo', 'bar'], ]) { - test(diffsBoxedPrimitives, lhs, rhs) + test(diffsBoxedPrimitives, lhs, rhs); } if (typeof BigInt === 'function') { - test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n') // eslint-disable-line no-undef + test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n'); } } test('diffs boxed primitives with extra properties', t => { - t.snapshot(diff(new Object('foo'), Object.assign(new Object('foo'), { bar: 'baz' }))) -}) + // eslint-disable-next-line no-new-object + t.snapshot(diff(new Object('foo'), Object.assign(new Object('foo'), {bar: 'baz'}))); +}); test('diffs single line strings', t => { - const actual1 = diff('foo', 'bar') - t.snapshot(actual1) + const actual1 = diff('foo', 'bar'); + t.snapshot(actual1); - const actual2 = diff('bar', 'baz') - t.snapshot(actual2) -}) + const actual2 = diff('bar', 'baz'); + t.snapshot(actual2); +}); test('diffs multiline strings', t => { - const actual1 = diff('foo\nbar', 'baz\nbar') - t.snapshot(actual1) + const actual1 = diff('foo\nbar', 'baz\nbar'); + t.snapshot(actual1); - const actual2 = diff('foo\nbar', 'foo\nbaz') - t.snapshot(actual2) + const actual2 = diff('foo\nbar', 'foo\nbaz'); + t.snapshot(actual2); - const actual3 = diff('foo\nbar\nbaz', 'foo\nbaz') - t.snapshot(actual3) + const actual3 = diff('foo\nbar\nbaz', 'foo\nbaz'); + t.snapshot(actual3); - const actual4 = diff('foo\nbaz', 'foo\nbar\nbaz') - t.snapshot(actual4) + const actual4 = diff('foo\nbaz', 'foo\nbar\nbaz'); + t.snapshot(actual4); - const actual5 = diff('foo\n', 'foo\nbaz') - t.snapshot(actual5) + const actual5 = diff('foo\n', 'foo\nbaz'); + t.snapshot(actual5); - const actual6 = diff('foo\nbaz', 'foo\n') - t.snapshot(actual6) + const actual6 = diff('foo\nbaz', 'foo\n'); + t.snapshot(actual6); - const actual7 = diff('foo\nbar\nbaz', 'foo\n') - t.snapshot(actual7) + const actual7 = diff('foo\nbar\nbaz', 'foo\n'); + t.snapshot(actual7); const actual8 = diff(`foo bar @@ -103,379 +106,408 @@ quux`, `corge grault baz garply -quux`) - t.snapshot(actual8) +quux`); + t.snapshot(actual8); - const actual9 = diff('foo\nbar\ncorge\nbaz\nqux\nquux\n', 'foo\nbar\nbaz\ngrault\nqux\nquux') - t.snapshot(actual9) -}) + const actual9 = diff('foo\nbar\ncorge\nbaz\nqux\nquux\n', 'foo\nbar\nbaz\ngrault\nqux\nquux'); + t.snapshot(actual9); +}); test('diffs diverging complex types', t => { - const actual = diff({ foo: 'bar' }, ['baz']) - t.snapshot(actual) -}) + const actual = diff({foo: 'bar'}, ['baz']); + t.snapshot(actual); +}); { - const mapArray = arr => arr - const mapArguments = arr => { let args; (function () { args = arguments })(...arr); return args } - const mapSet = arr => new Set(arr) + const mapArray = array => array; + const mapArguments = array => { + let args; + (function () { + // eslint-disable-next-line prefer-rest-params + args = arguments; + })(...array); + + return args; + }; + + const mapSet = array => new Set(array); const equalLength = (t, map) => { - const actual1 = diff(map([1, 2, 4]), map([1, 3, 4])) - t.snapshot(actual1) + const actual1 = diff(map([1, 2, 4]), map([1, 3, 4])); + t.snapshot(actual1); const actual2 = diff( - map([1, { foo: 'bar' }, 2]), - map([1, { baz: 'qux' }, 2])) - t.snapshot(actual2) + map([1, {foo: 'bar'}, 2]), + map([1, {baz: 'qux'}, 2])); + t.snapshot(actual2); class Foo { - constructor () { - this.foo = 'foo' + constructor() { + this.foo = 'foo'; } } class Bar { - constructor () { - this.bar = 'bar' + constructor() { + this.bar = 'bar'; } } const actual3 = diff( map([new Foo()]), - map([new Bar()])) - t.snapshot(actual3) + map([new Bar()])); + t.snapshot(actual3); const actual4 = diff( map([Buffer.alloc(0)]), - map([new Uint8Array()])) - t.snapshot(actual4) + map([new Uint8Array()])); + t.snapshot(actual4); - const actual5 = diff(map([1, 2]), map([1])) - t.snapshot(actual5) - } - test('diffs arrays', equalLength, mapArray) - test('diffs arguments', equalLength, mapArguments) - test('diffs sets', equalLength, mapSet) + const actual5 = diff(map([1, 2]), map([1])); + t.snapshot(actual5); + }; + + test('diffs arrays', equalLength, mapArray); + test('diffs arguments', equalLength, mapArguments); + test('diffs sets', equalLength, mapSet); const extraneous = (t, map) => { - const actual1 = diff(map([1, 3, 2]), map([1, 2])) - t.snapshot(actual1) + const actual1 = diff(map([1, 3, 2]), map([1, 2])); + t.snapshot(actual1); - const actual2 = diff(map([1, {}, 2]), map([1, 2])) - t.snapshot(actual2) + const actual2 = diff(map([1, {}, 2]), map([1, 2])); + t.snapshot(actual2); const actual3 = diff( - map([1, { foo: 'bar' }, { baz: 'qux' }, 2]), - map([1, { baz: 'qux' }, 2])) - t.snapshot(actual3) + map([1, {foo: 'bar'}, {baz: 'qux'}, 2]), + map([1, {baz: 'qux'}, 2])); + t.snapshot(actual3); - const s1 = Symbol('s1') - const s2 = Symbol('s2') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); const actual4 = diff( - map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2]), - map([1, { [s2]: 'qux' }, 2])) - t.snapshot(actual4) - } - test('detects extraneous array items', extraneous, mapArray) - test('detects extraneous arguments items', extraneous, mapArguments) - test('detects extraneous set items', extraneous, mapSet) + map([1, {[s1]: 'bar'}, {[s2]: 'qux'}, 2]), + map([1, {[s2]: 'qux'}, 2])); + t.snapshot(actual4); + }; + + test('detects extraneous array items', extraneous, mapArray); + test('detects extraneous arguments items', extraneous, mapArguments); + test('detects extraneous set items', extraneous, mapSet); const missing = (t, map) => { - const actual1 = diff(map([1, 2]), map([1, 3, 2])) - t.snapshot(actual1) + const actual1 = diff(map([1, 2]), map([1, 3, 2])); + t.snapshot(actual1); - const actual2 = diff(map([1, 2]), map([1, {}, 2])) - t.snapshot(actual2) + const actual2 = diff(map([1, 2]), map([1, {}, 2])); + t.snapshot(actual2); const actual3 = diff( - map([1, { baz: 'qux' }, 2]), - map([1, { foo: 'bar' }, { baz: 'qux' }, 2])) - t.snapshot(actual3) + map([1, {baz: 'qux'}, 2]), + map([1, {foo: 'bar'}, {baz: 'qux'}, 2])); + t.snapshot(actual3); - const s1 = Symbol('s1') - const s2 = Symbol('s2') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); const actual4 = diff( - map([1, { [s2]: 'qux' }, 2]), - map([1, { [s1]: 'bar' }, { [s2]: 'qux' }, 2])) - t.snapshot(actual4) - } - test('detects missing array items', missing, mapArray) - test('detects missing arguments items', missing, mapArguments) - test('detects missing set items', missing, mapSet) + map([1, {[s2]: 'qux'}, 2]), + map([1, {[s1]: 'bar'}, {[s2]: 'qux'}, 2])); + t.snapshot(actual4); + }; + + test('detects missing array items', missing, mapArray); + test('detects missing arguments items', missing, mapArguments); + test('detects missing set items', missing, mapSet); } test('detects extraneous name properties', t => { const actual1 = diff( - { a: 1, b: 2, c: 3 }, - { a: 1, c: 3 }) - t.snapshot(actual1) + {a: 1, b: 2, c: 3}, + {a: 1, c: 3}); + t.snapshot(actual1); const actual2 = diff( - { a: 1, b: {}, c: 3 }, - { a: 1, c: 3 }) - t.snapshot(actual2) -}) + {a: 1, b: {}, c: 3}, + {a: 1, c: 3}); + t.snapshot(actual2); +}); test('detects missing name properties', t => { const actual1 = diff( - { a: 1, c: 3 }, - { a: 1, b: 2, c: 3 }) - t.snapshot(actual1) + {a: 1, c: 3}, + {a: 1, b: 2, c: 3}); + t.snapshot(actual1); const actual2 = diff( - { a: 1, c: 3 }, - { a: 1, b: {}, c: 3 }) - t.snapshot(actual2) -}) + {a: 1, c: 3}, + {a: 1, b: {}, c: 3}); + t.snapshot(actual2); +}); test('detects extraneous symbol properties', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const s3 = Symbol('s3') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); + const s3 = Symbol('s3'); const actual1 = diff( - { [s1]: 1, [s2]: 2, [s3]: 3 }, - { [s1]: 1, [s3]: 3 }) - t.snapshot(actual1) + {[s1]: 1, [s2]: 2, [s3]: 3}, + {[s1]: 1, [s3]: 3}); + t.snapshot(actual1); const actual2 = diff( - { [s1]: 1, [s2]: {}, [s3]: 3 }, - { [s1]: 1, [s3]: 3 }) - t.snapshot(actual2) -}) + {[s1]: 1, [s2]: {}, [s3]: 3}, + {[s1]: 1, [s3]: 3}); + t.snapshot(actual2); +}); test('detects missing symbol properties', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const s3 = Symbol('s3') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); + const s3 = Symbol('s3'); const actual1 = diff( - { [s1]: 1, [s3]: 3 }, - { [s1]: 1, [s2]: 2, [s3]: 3 }) + {[s1]: 1, [s3]: 3}, + {[s1]: 1, [s2]: 2, [s3]: 3}); // Note that when symbol properties are sorted, they're sorted according to // their order in the actual value. Missing properties will end up at the // bottom. - t.snapshot(actual1) + t.snapshot(actual1); const actual2 = diff( - { [s1]: 1, [s3]: 3 }, - { [s1]: 1, [s2]: {}, [s3]: 3 }) - t.snapshot(actual2) -}) + {[s1]: 1, [s3]: 3}, + {[s1]: 1, [s2]: {}, [s3]: 3}); + t.snapshot(actual2); +}); test('diffs maps', t => { const actual1 = diff( new Map([[1, 1], [2, 2], [4, 4]]), - new Map([[1, 1], [3, 3], [4, 4]])) - t.snapshot(actual1) + new Map([[1, 1], [3, 3], [4, 4]])); + t.snapshot(actual1); const actual2 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), - new Map([[1, 1], [{ baz: 'qux' }, 2], [4, 4]])) - t.snapshot(actual2) + new Map([[1, 1], [{foo: 'bar'}, 2], [4, 4]]), + new Map([[1, 1], [{baz: 'qux'}, 2], [4, 4]])); + t.snapshot(actual2); const actual3 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 2], [4, 4]]), - new Map([[1, 1], [{ baz: 'qux' }, 3], [4, 4]])) - t.snapshot(actual3) -}) + new Map([[1, 1], [{foo: 'bar'}, 2], [4, 4]]), + new Map([[1, 1], [{baz: 'qux'}, 3], [4, 4]])); + t.snapshot(actual3); +}); test('detects extraneous map entries', t => { const actual1 = diff( new Map([[1, 1], [3, 3], [2, 2]]), - new Map([[1, 1], [2, 2]])) - t.snapshot(actual1) + new Map([[1, 1], [2, 2]])); + t.snapshot(actual1); const actual2 = diff( new Map([[1, 1], [{}, 3], [2, 2]]), - new Map([[1, 1], [2, 2]])) - t.snapshot(actual2) + new Map([[1, 1], [2, 2]])); + t.snapshot(actual2); const actual3 = diff( - new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]])) - t.snapshot(actual3) + new Map([[1, 1], [{foo: 'bar'}, 4], [{baz: 'qux'}, 2], [3, 3]]), + new Map([[1, 1], [{baz: 'qux'}, 2], [3, 3]])); + t.snapshot(actual3); - const s1 = Symbol('s1') - const s2 = Symbol('s2') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); const actual4 = diff( - new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]])) - t.snapshot(actual4) -}) + new Map([[1, 1], [{[s1]: 'bar'}, 4], [{[s2]: 'qux'}, 2], [3, 3]]), + new Map([[1, 1], [{[s2]: 'qux'}, 2], [3, 3]])); + t.snapshot(actual4); +}); test('detects missing map entries', t => { const actual1 = diff( new Map([[1, 1], [2, 2]]), - new Map([[1, 1], [3, 3], [2, 2]])) - t.snapshot(actual1) + new Map([[1, 1], [3, 3], [2, 2]])); + t.snapshot(actual1); const actual2 = diff( new Map([[1, 1], [2, 2]]), - new Map([[1, 1], [{}, 3], [2, 2]])) - t.snapshot(actual2) + new Map([[1, 1], [{}, 3], [2, 2]])); + t.snapshot(actual2); const actual3 = diff( - new Map([[1, 1], [{ baz: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ foo: 'bar' }, 4], [{ baz: 'qux' }, 2], [3, 3]])) - t.snapshot(actual3) + new Map([[1, 1], [{baz: 'qux'}, 2], [3, 3]]), + new Map([[1, 1], [{foo: 'bar'}, 4], [{baz: 'qux'}, 2], [3, 3]])); + t.snapshot(actual3); - const s1 = Symbol('s1') - const s2 = Symbol('s2') + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); const actual4 = diff( - new Map([[1, 1], [{ [s2]: 'qux' }, 2], [3, 3]]), - new Map([[1, 1], [{ [s1]: 'bar' }, 4], [{ [s2]: 'qux' }, 2], [3, 3]])) - t.snapshot(actual4) -}) + new Map([[1, 1], [{[s2]: 'qux'}, 2], [3, 3]]), + new Map([[1, 1], [{[s1]: 'bar'}, 4], [{[s2]: 'qux'}, 2], [3, 3]])); + t.snapshot(actual4); +}); test('diffs maps with extra properties', t => { - const actual1 = diff(new Map([['foo', 'bar']]), Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' })) - t.snapshot(actual1) + const actual1 = diff(new Map([['foo', 'bar']]), Object.assign(new Map([['foo', 'bar']]), {baz: 'qux'})); + t.snapshot(actual1); - const actual2 = diff(Object.assign(new Map([['foo', 'bar']]), { baz: 'qux' }), new Map([['foo', 'bar']])) - t.snapshot(actual2) -}) + const actual2 = diff(Object.assign(new Map([['foo', 'bar']]), {baz: 'qux'}), new Map([['foo', 'bar']])); + t.snapshot(actual2); +}); test('diffs multiline string values in objects', t => { - const actual1 = diff({ foo: 'bar\nbaz' }, { foo: 'qux\nbaz' }) - t.snapshot(actual1) + const actual1 = diff({foo: 'bar\nbaz'}, {foo: 'qux\nbaz'}); + t.snapshot(actual1); - const actual2 = diff({ foo: 'bar\nbaz\nqux' }, { foo: 'bar\nqux\nbaz' }) - t.snapshot(actual2) + const actual2 = diff({foo: 'bar\nbaz\nqux'}, {foo: 'bar\nqux\nbaz'}); + t.snapshot(actual2); - const s1 = Symbol('s1') - const actual3 = diff({ [s1]: 'bar\nbaz' }, { [s1]: 'qux\nbaz' }) - t.snapshot(actual3) -}) + const s1 = Symbol('s1'); + const actual3 = diff({[s1]: 'bar\nbaz'}, {[s1]: 'qux\nbaz'}); + t.snapshot(actual3); +}); test('diffs multiline string values in arrays', t => { - const actual = diff(['foo\nbar'], ['baz\nbar']) - t.snapshot(actual) -}) + const actual = diff(['foo\nbar'], ['baz\nbar']); + t.snapshot(actual); +}); test('diffs multiline string values in sets', t => { - const actual = diff(new Set(['foo\nbar']), new Set(['baz\nbar'])) - t.snapshot(actual) -}) + const actual = diff(new Set(['foo\nbar']), new Set(['baz\nbar'])); + t.snapshot(actual); +}); test('diffs multiline string values in maps when key is primitive', t => { - const actual1 = diff(new Map([[1, 'foo\nbar']]), new Map([[1, 'baz\nbar']])) - t.snapshot(actual1) + const actual1 = diff(new Map([[1, 'foo\nbar']]), new Map([[1, 'baz\nbar']])); + t.snapshot(actual1); - const actual2 = diff(new Map([['foo\nbar', 'foo\nbar']]), new Map([['foo\nbar', 'baz\nbar']])) - t.snapshot(actual2) + const actual2 = diff(new Map([['foo\nbar', 'foo\nbar']]), new Map([['foo\nbar', 'baz\nbar']])); + t.snapshot(actual2); - const actual3 = diff(new Map([['foo', 'bar\nbaz\nqux']]), new Map([['foo', 'bar\nqux\nbaz']])) - t.snapshot(actual3) -}) + const actual3 = diff(new Map([['foo', 'bar\nbaz\nqux']]), new Map([['foo', 'bar\nqux\nbaz']])); + t.snapshot(actual3); +}); test('does not diff multiline string values in maps when key is complex', t => { - const actual = diff(new Map([[{}, 'foo\nbar']]), new Map([[{}, 'baz\nbar']])) - t.snapshot(actual) -}) + const actual = diff(new Map([[{}, 'foo\nbar']]), new Map([[{}, 'baz\nbar']])); + t.snapshot(actual); +}); test('diffs properties with different values', t => { - class Foo { constructor () { this.value = 42 } } - class Bar { constructor () { this.value = 42 } } - const actual1 = diff({ value: new Foo() }, { value: new Bar() }) - t.snapshot(actual1) + class Foo { + constructor() { + this.value = 42; + } + } + class Bar { + constructor() { + this.value = 42; + } + } + const actual1 = diff({value: new Foo()}, {value: new Bar()}); + t.snapshot(actual1); - const actual2 = diff({ value: new Foo() }, { value: 42 }) - t.snapshot(actual2) + const actual2 = diff({value: new Foo()}, {value: 42}); + t.snapshot(actual2); - const actual3 = diff({ value: new Foo() }, { value: 'foo\nbar' }) - t.snapshot(actual3) + const actual3 = diff({value: new Foo()}, {value: 'foo\nbar'}); + t.snapshot(actual3); - const actual4 = diff({ foo: 'bar' }, { foo: 'not bar' }) - t.snapshot(actual4) -}) + const actual4 = diff({foo: 'bar'}, {foo: 'not bar'}); + t.snapshot(actual4); +}); test('diffs map keys with different values', t => { - class Foo { constructor () { this.value = 42 } } - class Bar { constructor () { this.value = 42 } } - const actual1 = diff(new Map([['key', new Foo()]]), new Map([['key', new Bar()]])) - t.snapshot(actual1) + class Foo { + constructor() { + this.value = 42; + } + } + class Bar { + constructor() { + this.value = 42; + } + } + const actual1 = diff(new Map([['key', new Foo()]]), new Map([['key', new Bar()]])); + t.snapshot(actual1); - const actual2 = diff(new Map([['key', new Foo()]]), new Map([['key', 42]])) - t.snapshot(actual2) + const actual2 = diff(new Map([['key', new Foo()]]), new Map([['key', 42]])); + t.snapshot(actual2); - const actual3 = diff(new Map([['key', new Foo()]]), new Map([['key', 'foo\nbar']])) - t.snapshot(actual3) + const actual3 = diff(new Map([['key', new Foo()]]), new Map([['key', 'foo\nbar']])); + t.snapshot(actual3); - const actual4 = diff(new Map([['key\nline', new Foo()]]), new Map([['key\nline', new Bar()]])) - t.snapshot(actual4) -}) + const actual4 = diff(new Map([['key\nline', new Foo()]]), new Map([['key\nline', new Bar()]])); + t.snapshot(actual4); +}); test('diffs circular references', t => { - const obj1 = { obj: {} } - obj1.obj.obj = obj1 - const obj2 = {} - obj2.obj = obj2 - t.snapshot(diff(obj1, obj2)) - - obj2.obj = obj1 - t.snapshot(diff(obj1, obj2)) - - const arr1 = [[]] - arr1[0][0] = arr1 - const arr2 = [] - arr2[0] = arr1 - t.snapshot(diff(arr1, arr2)) - - const map1 = new Map([['map', new Map()]]) - map1.get('map').set('map', map1) - const map2 = new Map() - map2.set('map', map1) - t.snapshot(diff(map1, map2)) - - const key = { key: true } - const map3 = new Map([[key, new Map()]]) - map3.get(key).set(key, map3) - const map4 = new Map() - map4.set(key, map3) - t.snapshot(diff(map3, map4)) -}) + const object1 = {obj: {}}; + object1.obj.obj = object1; + const object2 = {}; + object2.obj = object2; + t.snapshot(diff(object1, object2)); + + object2.obj = object1; + t.snapshot(diff(object1, object2)); + + const array1 = [[]]; + array1[0][0] = array1; + const array2 = []; + array2[0] = array1; + t.snapshot(diff(array1, array2)); + + const map1 = new Map([['map', new Map()]]); + map1.get('map').set('map', map1); + const map2 = new Map(); + map2.set('map', map1); + t.snapshot(diff(map1, map2)); + + const key = {key: true}; + const map3 = new Map([[key, new Map()]]); + map3.get(key).set(key, map3); + const map4 = new Map(); + map4.set(key, map3); + t.snapshot(diff(map3, map4)); +}); test('diff invalid dates', t => { - t.snapshot(diff(new Date('🚀🌔🛬'), new Date('🚀💥💧'))) -}) + t.snapshot(diff(new Date('🚀🌔🛬'), new Date('🚀💥💧'))); +}); test('diff dates with extra properties', t => { const actual = diff(new Date('1969-07-20T20:17:40.000Z'), Object.assign(new Date('1969-07-21T20:17:40.000Z'), { foo: 'bar', - })) - t.snapshot(actual) -}) + })); + t.snapshot(actual); +}); test('diffs errors', t => { - class Custom extends Error {} // eslint-disable-line unicorn/custom-error-definition - t.snapshot(diff(new Custom(), new Error())) -}) + class Custom extends Error {} + // eslint-disable-next-line unicorn/error-message + t.snapshot(diff(new Custom(), new Error())); +}); test('diffs functions', t => { - t.snapshot(diff(function foo () {}, function bar () {})) -}) + t.snapshot(diff(function foo() {}, function bar() {})); +}); test('diffs globals', t => { - t.snapshot(diff(global, global)) -}) + t.snapshot(diff(global, global)); +}); test('diffs objects without constructor', t => { - const obj = {} - Object.defineProperty(obj, 'constructor', {}) - t.snapshot(diff(obj, {})) -}) + const object = {}; + Object.defineProperty(object, 'constructor', {}); + t.snapshot(diff(object, {})); +}); test('diffs builtin subclasses', t => { class Foo extends Array {} - t.snapshot(diff(new Foo(), [])) -}) + t.snapshot(diff(new Foo(), [])); +}); test('diffs regexps', t => { - t.snapshot(diff(/foo/, /foo/g)) - t.snapshot(diff(/foo/, Object.assign(/foo/, { bar: 'baz' }))) -}) + t.snapshot(diff(/foo/, /foo/g)); + t.snapshot(diff(/foo/, Object.assign(/foo/, {bar: 'baz'}))); +}); test('diffs buffers', t => { - t.snapshot(diff(Buffer.from('decafbad', 'hex'), Buffer.from('flat white', 'utf8'))) -}) + t.snapshot(diff(Buffer.from('decafbad', 'hex'), Buffer.from('flat white', 'utf8'))); +}); test('inverted diffs', t => { t.snapshot(diff({ @@ -484,27 +516,27 @@ test('inverted diffs', t => { }, { foo: 'BAR', baz: 'qux\ncorge\nquux', - }, { invert: true })) -}) + }, {invert: true})); +}); test('inverts string diffs', t => { - t.snapshot(diff('foo', 'bar', { invert: true })) - t.snapshot(diff('foo bar baz', 'foo baz quux', { invert: true })) - t.snapshot(diff('foo\nbar\nbaz', 'foobarbaz', { invert: true })) -}) + t.snapshot(diff('foo', 'bar', {invert: true})); + t.snapshot(diff('foo bar baz', 'foo baz quux', {invert: true})); + t.snapshot(diff('foo\nbar\nbaz', 'foobarbaz', {invert: true})); +}); test('inverts string diffs in containers', t => { - const actual = 'foo\nbar\nbaz' - const expected = 'foo\nbaz\nquux' + const actual = 'foo\nbar\nbaz'; + const expected = 'foo\nbaz\nquux'; - t.snapshot(diff({ a: actual }, { a: expected }, { invert: true })) - t.snapshot(diff([actual], [expected], { invert: true })) - t.snapshot(diff(new Map().set('a', actual), new Map().set('a', expected), { invert: true })) - t.snapshot(diff(new Set().add(actual), new Set().add(expected), { invert: true })) - t.snapshot(diff(new String(actual), new String(expected), { invert: true })) // eslint-disable-line unicorn/new-for-builtins, no-new-wrappers + t.snapshot(diff({a: actual}, {a: expected}, {invert: true})); + t.snapshot(diff([actual], [expected], {invert: true})); + t.snapshot(diff(new Map().set('a', actual), new Map().set('a', expected), {invert: true})); + t.snapshot(diff(new Set().add(actual), new Set().add(expected), {invert: true})); + t.snapshot(diff(new String(actual), new String(expected), {invert: true})); // eslint-disable-line unicorn/new-for-builtins, no-new-wrappers - t.snapshot(diff({ a: { b: actual } }, { a: { b: expected } }, { invert: true })) -}) + t.snapshot(diff({a: {b: actual}}, {a: {b: expected}}, {invert: true})); +}); test('lists: effectively resets depth when formatting differences', t => { const l1 = [ @@ -517,14 +549,14 @@ test('lists: effectively resets depth when formatting differences', t => { f: 'f', }, }, - ] + ]; const l2 = [ { b: 'b', }, - ] - t.snapshot(_diff(l1, l2, { maxDepth: 1, theme })) -}) + ]; + t.snapshot(_diff(l1, l2, {maxDepth: 1, theme})); +}); test('objects: effectively resets depth when formatting differences', t => { const o1 = { @@ -537,18 +569,18 @@ test('objects: effectively resets depth when formatting differences', t => { f: 'f', }, }, - } + }; const o2 = { a: { b: 'b', }, - } - t.snapshot(_diff(o1, o2, { maxDepth: 1, theme })) -}) + }; + t.snapshot(_diff(o1, o2, {maxDepth: 1, theme})); +}); // See . test('diff pointers hidden behind maxDepth', t => { - const value = {} + const value = {}; const descriptor = concordance.describe({ // `value` is encoded in the serialization of `a.b`. `c` is encoded as a // pointer to the encoded `value`. @@ -556,13 +588,13 @@ test('diff pointers hidden behind maxDepth', t => { b: value, }, c: value, - }) - const serialized = concordance.serialize(descriptor) + }); + const serialized = concordance.serialize(descriptor); t.notThrows(() => { // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the // `c` pointer cannot be resolved, unless the resolution logic first // deserializes the descriptor in its entirety. - concordance.diffDescriptors(concordance.deserialize(serialized), concordance.describe(undefined), { maxDepth: 1 }) - }) -}) + concordance.diffDescriptors(concordance.deserialize(serialized), concordance.describe(undefined), {maxDepth: 1}); + }); +}); diff --git a/test/fixtures/customErrorPlugin.js b/test/fixtures/customErrorPlugin.js index 2c38e02..ff213bd 100644 --- a/test/fixtures/customErrorPlugin.js +++ b/test/fixtures/customErrorPlugin.js @@ -1,42 +1,43 @@ export class CustomError extends Error { - constructor (message, code) { - super(message) - this.code = code - this.name = 'CustomError' + constructor(message, code) { + super(message); + this.code = code; + this.name = 'CustomError'; } } -export const factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) { - const tag = Symbol.for('customError') +export const factory = function ({DescribedMixin, DeserializedMixin, ObjectValue}) { + const tag = Symbol.for('customError'); class DescribedErrorValue extends DescribedMixin(ObjectValue) { - createPropertyRecursor () { - let i = 0 + createPropertyRecursor() { + let i = 0; return { size: 1, next: () => { if (i === 1) { - return null + return null; } - i++ - return this.describeProperty('code', this.describeAny(this.value.code)) + + i++; + return this.describeProperty('code', this.describeAny(this.value.code)); }, - } + }; } - tag = tag + tag = tag; } - const DeserializedErrorValue = DeserializedMixin(ObjectValue) - Object.defineProperty(DeserializedErrorValue.prototype, 'tag', { value: tag }) + const DeserializedErrorValue = DeserializedMixin(ObjectValue); + Object.defineProperty(DeserializedErrorValue.prototype, 'tag', {value: tag}); return { - describe (props) { - return new DescribedErrorValue(props) + describe(props) { + return new DescribedErrorValue(props); }, - deserialize (state, recursor) { - return new DeserializedErrorValue(state, recursor) + deserialize(state, recursor) { + return new DeserializedErrorValue(state, recursor); }, tag, - } -} + }; +}; diff --git a/test/fixtures/pointerSerialization.js b/test/fixtures/pointerSerialization.js index 1ec1dd6..e7955d5 100644 --- a/test/fixtures/pointerSerialization.js +++ b/test/fixtures/pointerSerialization.js @@ -1,14 +1,15 @@ -import fs from 'node:fs' -import concordance from '../../index.js' +import fs from 'node:fs'; -const foo = {} +import concordance from '../../index.js'; + +const foo = {}; export const tree = { foo, - bar: { foo }, -} + bar: {foo}, +}; -const binFile = new URL('./pointerSerialization.bin', import.meta.url) +const binFile = new URL('pointerSerialization.bin', import.meta.url); -fs.writeFileSync(binFile, concordance.serialize(concordance.describe(tree))) +fs.writeFileSync(binFile, concordance.serialize(concordance.describe(tree))); -export const serialization = fs.readFileSync(binFile) +export const serialization = fs.readFileSync(binFile); diff --git a/test/format.js b/test/format.js index d3295c1..7b423aa 100644 --- a/test/format.js +++ b/test/format.js @@ -1,13 +1,18 @@ -import test from 'ava' -import concordance from '../index.js' -import {format as _format} from '../lib/format.js' -import {theme, normalizedTheme, checkThemeUsage} from './_instrumentedTheme.js' -import * as customErrorPlugin from './fixtures/customErrorPlugin.js' +import {Buffer} from 'node:buffer'; -const format = value => _format(value, { theme }) -// test.after(checkThemeUsage) +import test from 'ava'; + +import concordance from '../index.js'; +import {format as _format} from '../lib/format.js'; + +import {theme, normalizedTheme, checkThemeUsage} from './_instrumentedTheme.js'; +import * as customErrorPlugin from './fixtures/customErrorPlugin.js'; + +const format = value => _format(value, {theme}); +test.after(checkThemeUsage); // "Use" diff themes +// eslint-disable-next-line no-void void ( normalizedTheme.diffGutters.actual, normalizedTheme.diffGutters.expected, @@ -24,23 +29,25 @@ void ( normalizedTheme.string.diff.deleteLine.close, // Tested separately normalizedTheme.maxDepth -) +); if (typeof BigInt === 'undefined') { + // eslint-disable-next-line no-void void ( normalizedTheme.bigInt.open, normalizedTheme.bigInt.close - ) + ); } { - const formatsPrimitive = (t, value) => t.snapshot(format(value)) + const formatsPrimitive = (t, value) => t.snapshot(format(value)); formatsPrimitive.title = (valueRepresentation, value) => { - const str = Object.is(value, -0) + const string_ = Object.is(value, -0) ? '-0' - : String(value).replace(/\r/g, '\\r').replace(/\n/g, '\\n') - return `formats primitive: ${valueRepresentation || str}` - } + : String(value).replaceAll('\r', '\\r').replaceAll('\n', '\\n'); + return `formats primitive: ${valueRepresentation || string_}`; + }; + for (const value of [ null, undefined, @@ -56,9 +63,9 @@ if (typeof BigInt === 'undefined') { -42, -0, +0, - Infinity, - -Infinity, - NaN, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + Number.NaN, Symbol(), // eslint-disable-line symbol-description Symbol('foo'), Symbol('foo\nbar'), @@ -66,12 +73,12 @@ if (typeof BigInt === 'undefined') { Symbol.for('bar\nbaz'), Symbol.iterator, ]) { - test(formatsPrimitive, value) + test(formatsPrimitive, value); } if (typeof BigInt === 'function') { - test('42n', formatsPrimitive, BigInt(42)) // eslint-disable-line no-undef - test('-42n', formatsPrimitive, BigInt(-42)) // eslint-disable-line no-undef + test('42n', formatsPrimitive, BigInt(42)); + test('-42n', formatsPrimitive, BigInt(-42)); } } @@ -79,60 +86,60 @@ if (typeof BigInt === 'undefined') { const escapesQuote = (t, escapeQuote) => { const testTheme = { string: { - line: { open: '<', close: '>', escapeQuote }, - multiline: { start: '<', end: '>', escapeQuote }, + line: {open: '<', close: '>', escapeQuote}, + multiline: {start: '<', end: '>', escapeQuote}, }, - } - t.snapshot(_format(escapeQuote, { theme: testTheme })) - t.snapshot(_format(escapeQuote + '\n', { theme: testTheme })) - } - escapesQuote.title = (_, quote) => `escapes ${quote} according to theme` - test(escapesQuote, "'") - test(escapesQuote, '"') - test(escapesQuote, '`') + }; + t.snapshot(_format(escapeQuote, {theme: testTheme})); + t.snapshot(_format(escapeQuote + '\n', {theme: testTheme})); + }; + + escapesQuote.title = (_, quote) => `escapes ${quote} according to theme`; + test(escapesQuote, '\''); + test(escapesQuote, '"'); + test(escapesQuote, '`'); } test('escapes singlequotes in one-line strings with the default theme', t => { - t.snapshot(_format("'"), 'should be escaped') - t.snapshot(_format("'\n"), 'should not be escaped') -}) + t.snapshot(_format('\''), 'should be escaped'); + t.snapshot(_format('\'\n'), 'should not be escaped'); +}); // Regression test for #36 test('escapes backticks in multi-line strings with the default theme', t => { - t.snapshot(_format('`'), 'should not be escaped') - t.snapshot(_format('`\n'), 'should be escaped') -}) + t.snapshot(_format('`'), 'should not be escaped'); + t.snapshot(_format('`\n'), 'should be escaped'); +}); test('formats a simple object', t => { - const obj = { foo: 'bar', baz: 'qux' } - const actual = format(obj) - t.snapshot(actual) -}) + const object = {foo: 'bar', baz: 'qux'}; + const actual = format(object); + t.snapshot(actual); +}); test('formats a simple, nested object', t => { - const obj = { foo: { baz: 'qux' } } - const actual = format(obj) - t.snapshot(actual) -}) + const object = {foo: {baz: 'qux'}}; + const actual = format(object); + t.snapshot(actual); +}); test('formats multiline strings inside an object', t => { - const actual = format({ 'foo\nbar': 'baz\nqux' }) - t.snapshot(actual) -}) + const actual = format({'foo\nbar': 'baz\nqux'}); + t.snapshot(actual); +}); test('formats symbol keys', t => { - t.snapshot(format({ [Symbol('')]: 'bar' })) -}) + t.snapshot(format({[Symbol('')]: 'bar'})); +}); test('formats registered symbols differently from normal symbols with same description', t => { - t.true(format(Symbol('foo')) !== format(Symbol.for('foo'))) -}) + t.true(format(Symbol('foo')) !== format(Symbol.for('foo'))); +}); { - const formatsBoxedPrimitive = (t, value) => t.snapshot(format(new Object(value))) - formatsBoxedPrimitive.title = (valueRepresentation, value) => { - return `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}` - } + // eslint-disable-next-line no-new-object + const formatsBoxedPrimitive = (t, value) => t.snapshot(format(new Object(value))); + formatsBoxedPrimitive.title = (valueRepresentation, value) => `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}`; for (const value of [ false, true, @@ -140,225 +147,231 @@ test('formats registered symbols differently from normal symbols with same descr -42, -0, +0, - Infinity, - -Infinity, - NaN, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + Number.NaN, 'foo', ]) { - test(formatsBoxedPrimitive, value) + test(formatsBoxedPrimitive, value); } if (typeof BigInt === 'function') { - test('42n', formatsBoxedPrimitive, BigInt(42)) // eslint-disable-line no-undef - test('-42n', formatsBoxedPrimitive, BigInt(-42)) // eslint-disable-line no-undef + test('42n', formatsBoxedPrimitive, BigInt(42)); + test('-42n', formatsBoxedPrimitive, BigInt(-42)); } } test('formats boxed primitives with extra properties', t => { - t.snapshot(format(Object.assign(new Object('foo'), { bar: 'baz' }))) -}) + // eslint-disable-next-line no-new-object + t.snapshot(format(Object.assign(new Object('foo'), {bar: 'baz'}))); +}); test('formats a simple array', t => { - const arr = ['foo', 'bar'] - const actual = format(arr) - t.snapshot(actual) -}) + const array = ['foo', 'bar']; + const actual = format(array); + t.snapshot(actual); +}); test('formats a simple, nested array', t => { - const arr = [['foo', 'bar']] - const actual = format(arr) - t.snapshot(actual) -}) + const array = [['foo', 'bar']]; + const actual = format(array); + t.snapshot(actual); +}); test('formats an array with additional properties', t => { - const arr1 = ['foo', 'bar'] - arr1.baz = 'qux' - t.snapshot(format(arr1)) + const array1 = ['foo', 'bar']; + array1.baz = 'qux'; + t.snapshot(format(array1)); - const arr2 = [1, 2, 3] - arr2[-1] = -1 - t.snapshot(format(arr2)) -}) + const array2 = [1, 2, 3]; + array2[-1] = -1; + t.snapshot(format(array2)); +}); test('formats a multiline string inside an array', t => { - const actual = format(['bar\nbaz']) - t.snapshot(actual) -}) + const actual = format(['bar\nbaz']); + t.snapshot(actual); +}); test('formats maps', t => { - const map = new Map() - map.set('foo', 'bar') - map.set({ baz: 'qux' }, 'quux') - map.set('corge', { grault: 'garply' }) - const actual = format(map) - t.snapshot(actual) -}) + const map = new Map(); + map.set('foo', 'bar'); + map.set({baz: 'qux'}, 'quux'); + map.set('corge', {grault: 'garply'}); + const actual = format(map); + t.snapshot(actual); +}); test('formats multiline strings inside a map', t => { - const actual = format(new Map([['foo\nbar', 'baz\nqux']])) - t.snapshot(actual) -}) + const actual = format(new Map([['foo\nbar', 'baz\nqux']])); + t.snapshot(actual); +}); test('formats maps with additional properties', t => { - const map = new Map() - map.set('foo', 'bar') - map.baz = 'qux' - const actual = format(map) - t.snapshot(actual) -}) + const map = new Map(); + map.set('foo', 'bar'); + map.baz = 'qux'; + const actual = format(map); + t.snapshot(actual); +}); test('formats sets', t => { - const set = new Set() - set.add('foo') - set.add({ bar: 'baz' }) - const actual = format(set) - t.snapshot(actual) -}) + const set = new Set(); + set.add('foo'); + set.add({bar: 'baz'}); + const actual = format(set); + t.snapshot(actual); +}); test('formats a multiline string inside sets', t => { - const actual = format(new Set(['bar\nbaz'])) - t.snapshot(actual) -}) + const actual = format(new Set(['bar\nbaz'])); + t.snapshot(actual); +}); test('formats sets with additional properties', t => { - const set = new Set() - set.add('foo') - set.bar = 'baz' - const actual = format(set) - t.snapshot(actual) -}) + const set = new Set(); + set.add('foo'); + set.bar = 'baz'; + const actual = format(set); + t.snapshot(actual); +}); test('formats funky objects that are lists and have an iterator', t => { const funky = { 0: 'first', 1: 'second', foo: 'bar', - } - Object.defineProperty(funky, 'length', { value: 2 }) - Object.defineProperty(funky, Symbol.iterator, { * value () { yield 'baz' } }) + }; + Object.defineProperty(funky, 'length', {value: 2}); + Object.defineProperty(funky, Symbol.iterator, {* value() { + yield 'baz'; + }}); - const actual = format(funky) - t.snapshot(actual) -}) + const actual = format(funky); + t.snapshot(actual); +}); test('formats regular expressions', t => { - const actual = format(/foo/gim) - t.snapshot(actual) -}) + const actual = format(/foo/gim); + t.snapshot(actual); +}); test('formats regular expressions with additional properties', t => { - const actual = format(Object.assign(/foo/gim, { bar: 'baz' })) - t.snapshot(actual) -}) + const actual = format(Object.assign(/foo/gim, {bar: 'baz'})); + t.snapshot(actual); +}); test('formats anonymous functions', t => { - const actual = format(() => {}) - t.snapshot(actual) -}) + const actual = format(() => {}); + t.snapshot(actual); +}); test('formats named functions', t => { - const actual = format(function foo () {}) - t.snapshot(actual) -}) + const actual = format(function foo() {}); + t.snapshot(actual); +}); test('formats functions with additional properties', t => { - const actual = format(Object.assign(function foo () {}, { bar: 'baz' })) - t.snapshot(actual) -}) + const actual = format(Object.assign(function foo() {}, {bar: 'baz'})); + t.snapshot(actual); +}); test('formats anonymous generator functions', t => { - const actual = format(function * () {}) - // eslint-disable-next-line max-len - t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %object.openBracket#{%%object.closeBracket#}%') -}) + const actual = format(function * () {}); + + t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %object.openBracket#{%%object.closeBracket#}%'); +}); test('formats named generator functions', t => { - const actual = format(function * foo () {}) - // eslint-disable-next-line max-len - t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{%%object.closeBracket#}%') -}) + const actual = format(function * foo() {}); + + t.is(actual, '%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{%%object.closeBracket#}%'); +}); test('formats generator functions with additional properties', t => { - const actual = format(Object.assign(function * foo () {}, { bar: 'baz' })) - // eslint-disable-next-line max-len + const actual = format(Object.assign(function * foo() {}, {bar: 'baz'})); + t.is(actual, `%function.stringTag.open%GeneratorFunction%function.stringTag.close% %function.name.open%foo%function.name.close% %object.openBracket#{% bar%property.separator#: %%string.line.open#'%%string.open%baz%string.close%%string.line.close#'%%property.after#,% -%object.closeBracket#}%`) -}) +%object.closeBracket#}%`); +}); test('formats arguments', t => { - (function (a, b, c) { - const actual = format(arguments) - t.snapshot(actual) - })('foo', 'bar', 'baz') -}) + (function (_a, _b, _c) { + // eslint-disable-next-line prefer-rest-params + const actual = format(arguments); + t.snapshot(actual); + })('foo', 'bar', 'baz'); +}); test('formats simple errors', t => { - const actual = format(new TypeError('Test message')) - t.snapshot(actual) -}) + const actual = format(new TypeError('Test message')); + t.snapshot(actual); +}); test('formats simple errors with a modified name', t => { - const err = new TypeError('Test message') - err.name = 'FooError' - const actual = format(err) - t.snapshot(actual) -}) + const error = new TypeError('Test message'); + error.name = 'FooError'; + const actual = format(error); + t.snapshot(actual); +}); test('formats errors with a name that does not include Error and does not match the constructor', t => { - class Foo extends Error { // eslint-disable-line unicorn/custom-error-definition - constructor (message) { - super(message) - this.name = 'Bar' // eslint-disable-line unicorn/custom-error-definition + class Foo extends Error { + constructor(message) { + super(message); + this.name = 'Bar'; } } - const actual = format(new Foo('Test message')) - t.snapshot(actual) -}) + const actual = format(new Foo('Test message')); + t.snapshot(actual); +}); test('formats errors with additional properties', t => { - const actual = format(Object.assign(new TypeError('Test message'), { foo: 'bar' })) - t.snapshot(actual) -}) + const actual = format(Object.assign(new TypeError('Test message'), {foo: 'bar'})); + t.snapshot(actual); +}); test('formats promises', t => { - const actual = format(Promise.resolve()) - t.snapshot(actual) -}) + const actual = format(Promise.resolve()); + t.snapshot(actual); +}); test('formats promises with additional properties', t => { - const actual = format(Object.assign(Promise.resolve(), { foo: 'bar' })) - t.snapshot(actual) -}) + const actual = format(Object.assign(Promise.resolve(), {foo: 'bar'})); + t.snapshot(actual); +}); test('formats pointers', t => { - const obj = { foo: 'bar' } - const actual = format({ baz: obj, qux: { quux: obj } }) - t.snapshot(actual) -}) + const object = {foo: 'bar'}; + const actual = format({baz: object, qux: {quux: object}}); + t.snapshot(actual); +}); test('formats circular references', t => { - const obj = {} - obj.circular = obj - const actual = format(obj) - t.snapshot(actual) -}) + const object = {}; + object.circular = object; + const actual = format(object); + t.snapshot(actual); +}); { - const plain = (t, value, tag) => { - const actual = format(value) - t.snapshot(actual) - } - plain.title = (_, __, tag) => `formats ${tag}` + const plain = (t, value, _tag) => { + const actual = format(value); + t.snapshot(actual); + }; - const withProperties = (t, value, tag) => { - const actual = format(Object.assign(value, { foo: 'bar' })) - t.snapshot(actual) - } - withProperties.title = (_, __, tag) => `formats ${tag} with additional properties` + plain.title = (_, __, tag) => `formats ${tag}`; + + const withProperties = (t, value, _tag) => { + const actual = format(Object.assign(value, {foo: 'bar'})); + t.snapshot(actual); + }; + + withProperties.title = (_, __, tag) => `formats ${tag} with additional properties`; - const buffer = Buffer.from('decafbad'.repeat(12), 'hex') - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) + const buffer = Buffer.from('decafbad'.repeat(12), 'hex'); + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); for (const [tag, value, valueForProps] of [ ['ArrayBuffer', arrayBuffer], @@ -374,81 +387,81 @@ test('formats circular references', t => { ['Uint8Array', new Uint8Array(arrayBuffer)], ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], ]) { - test(plain, value, tag) - test(withProperties, valueForProps || value.slice(), tag) + test(plain, value, tag); + test(withProperties, valueForProps || [...value], tag); } } test('formats dates', t => { - const actual1 = format(new Date('1969-07-20T20:17:40.012Z')) - t.snapshot(actual1) + const actual1 = format(new Date('1969-07-20T20:17:40.012Z')); + t.snapshot(actual1); - const actual2 = format(new Date('🚀🌔🛬')) - t.snapshot(actual2) -}) + const actual2 = format(new Date('🚀🌔🛬')); + t.snapshot(actual2); +}); test('formats dates with additional properties', t => { - const actual = format(Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' })) - t.snapshot(actual) -}) + const actual = format(Object.assign(new Date('1969-07-20T20:17:40Z'), {foo: 'bar'})); + t.snapshot(actual); +}); test('shows non-Object tag if constructor name is different', t => { class Foo {} - const actual1 = format(new Foo()) - t.snapshot(actual1) + const actual1 = format(new Foo()); + t.snapshot(actual1); class Bar extends Array {} - const actual2 = format(new Bar()) - t.snapshot(actual2) + const actual2 = format(new Bar()); + t.snapshot(actual2); class Baz extends Date {} - const actual3 = format(new Baz('1969-07-20T20:17:40Z')) - t.snapshot(actual3) + const actual3 = format(new Baz('1969-07-20T20:17:40Z')); + t.snapshot(actual3); class Qux extends RegExp {} - const actual4 = format(new Qux('foo')) - t.snapshot(actual4) + const actual4 = format(new Qux('foo')); + t.snapshot(actual4); class Quux extends Int16Array {} - const actual5 = format(new Quux()) - t.snapshot(actual5) -}) + const actual5 = format(new Quux()); + t.snapshot(actual5); +}); test('shows string tag if object has no constructor', t => { - const obj = {} - Object.defineProperty(obj, 'constructor', {}) - t.snapshot(format(obj)) -}) + const object = {}; + Object.defineProperty(object, 'constructor', {}); + t.snapshot(format(object)); +}); test('formats global', t => { - t.snapshot(format(global)) -}) + t.snapshot(format(global)); +}); test('format with given plugin', t => { const plugins = [ { name: 'CustomError', apiVersion: 1, - register: props => { - const { describe } = customErrorPlugin.factory(props) + register(props) { + const {describe} = customErrorPlugin.factory(props); return function (value) { if (value.name === 'CustomError') { - return describe + return describe; } - } + }; }, }, - ] + ]; - const actual1 = _format(new customErrorPlugin.CustomError('plugin formatter', 'PLUGIN'), { plugins, theme }) - t.snapshot(actual1) - const actual2 = _format(new Error('error'), { plugins, theme }) - t.snapshot(actual2) -}) + const actual1 = _format(new customErrorPlugin.CustomError('plugin formatter', 'PLUGIN'), {plugins, theme}); + t.snapshot(actual1); + const actual2 = _format(new Error('error'), {plugins, theme}); + t.snapshot(actual2); +}); // See . test('format pointers hidden behind maxDepth', t => { - const value = {} + const value = {}; const descriptor = concordance.describe({ // `value` is encoded in the serialization of `a.b`. `c` is encoded as a // pointer to the encoded `value`. @@ -456,13 +469,13 @@ test('format pointers hidden behind maxDepth', t => { b: value, }, c: value, - }) - const serialized = concordance.serialize(descriptor) + }); + const serialized = concordance.serialize(descriptor); t.notThrows(() => { // `maxDepth: 1` means that `a.b` is not normally deserialized, and so the // `c` pointer cannot be resolved, unless the resolution logic first // deserializes the descriptor in its entirety. - concordance.formatDescriptor(concordance.deserialize(serialized), { maxDepth: 1 }) - }) -}) + concordance.formatDescriptor(concordance.deserialize(serialized), {maxDepth: 1}); + }); +}); diff --git a/test/lodash-isequal-comparison.js b/test/lodash-isequal-comparison.js index e03ade9..22127f9 100644 --- a/test/lodash-isequal-comparison.js +++ b/test/lodash-isequal-comparison.js @@ -1,3 +1,4 @@ +/* eslint-disable prefer-rest-params, no-multi-assign, no-new-object */ /* Copyright JS Foundation and other contributors @@ -34,144 +35,178 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Tests adopted from https://github.com/lodash/lodash/blob/3967c1e1197b726463246b47521a4099ab74cb35/test/test.js#L9477:L10291> */ -/* eslint-disable unicorn/consistent-function-scoping */ +import {Buffer} from 'node:buffer'; +import vm from 'node:vm'; -import vm from 'node:vm' -import test from 'ava' -import { compare } from '../lib/compare.js' +import test from 'ava'; -const isEqual = (actual, expected) => compare(actual, expected).pass +import {compare} from '../lib/compare.js'; -const realm = vm.runInNewContext('(function () { return this })()') -const symbol1 = Symbol ? Symbol('a') : true -const symbol2 = Symbol ? Symbol('b') : false +const isEqual = (actual, expected) => compare(actual, expected).pass; + +const realm = vm.runInNewContext('(function () { return this })()'); +const symbol1 = Symbol ? Symbol('a') : true; +const symbol2 = Symbol ? Symbol('b') : false; test('compare primitives', t => { const pairs = [ - [1, 1, true], [1, new Object(1), false], [1, '1', false], [1, 2, false], - [-0, -0, true], [0, 0, true], [0, new Object(0), false], [new Object(0), new Object(0), true], [-0, 0, false], [0, '0', false], [0, null, false], // eslint-disable-line max-len - [NaN, NaN, true], [NaN, new Object(NaN), false], [new Object(NaN), new Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], // eslint-disable-line max-len - ['a', 'a', true], ['a', new Object('a'), false], [new Object('a'), new Object('a'), true], ['a', 'b', false], ['a', ['a'], false], // eslint-disable-line max-len - [true, true, true], [true, new Object(true), false], [new Object(true), new Object(true), true], [true, 1, false], [true, 'a', false], // eslint-disable-line max-len - [false, false, true], [false, new Object(false), false], [new Object(false), new Object(false), true], [false, 0, false], [false, '', false], // eslint-disable-line max-len - [symbol1, symbol1, true], [symbol1, new Object(symbol1), false], [new Object(symbol1), new Object(symbol1), true], [symbol1, symbol2, false], // eslint-disable-line max-len - [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], - [undefined, undefined, true], [undefined, null, false], [undefined, '', false], - ] + [1, 1, true], + [1, new Object(1), false], + [1, '1', false], + [1, 2, false], + [-0, -0, true], + [0, 0, true], + [0, new Object(0), false], + [new Object(0), new Object(0), true], + [-0, 0, false], + [0, '0', false], + [0, null, false], + [Number.NaN, Number.NaN, true], + [Number.NaN, new Object(Number.NaN), false], + [new Object(Number.NaN), new Object(Number.NaN), true], + [Number.NaN, 'a', false], + [Number.NaN, Number.POSITIVE_INFINITY, false], + ['a', 'a', true], + ['a', new Object('a'), false], + [new Object('a'), new Object('a'), true], + ['a', 'b', false], + ['a', ['a'], false], + [true, true, true], + [true, new Object(true), false], + [new Object(true), new Object(true), true], + [true, 1, false], + [true, 'a', false], + [false, false, true], + [false, new Object(false), false], + [new Object(false), new Object(false), true], + [false, 0, false], + [false, '', false], + [symbol1, symbol1, true], + [symbol1, new Object(symbol1), false], + [new Object(symbol1), new Object(symbol1), true], + [symbol1, symbol2, false], + [null, null, true], + [null, undefined, false], + [null, {}, false], + [null, '', false], + [undefined, undefined, true], + [undefined, null, false], + [undefined, '', false], + ]; for (const [lhs, rhs, result] of pairs) { - t.is(isEqual(lhs, rhs), result) + t.is(isEqual(lhs, rhs), result); } -}) +}); test('compare arrays', t => { - let array1 = [true, null, 1, 'a', undefined] - let array2 = [true, null, 1, 'a', undefined] + let array1 = [true, null, 1, 'a', undefined]; + let array2 = [true, null, 1, 'a', undefined]; - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] - array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { e: 1 }] + array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, {e: 1}]; + array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, {e: 1}]; - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1 = [1] - array1[2] = 3 + array1 = [1]; + array1[2] = 3; - array2 = [1] - array2[1] = undefined - array2[2] = 3 + array2 = [1]; + array2[1] = undefined; + array2[2] = 3; - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1 = [new Object(1), false, new Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [new Object('c')]], { a: 1 }] - array2 = [1, new Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', new Object('b'), ['c']], { a: 1 }] + array1 = [new Object(1), false, new Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [new Object('c')]], {a: 1}]; + array2 = [1, new Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', new Object('b'), ['c']], {a: 1}]; - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)); - array1 = [1, 2, 3] - array2 = [3, 2, 1] + array1 = [1, 2, 3]; + array2 = [3, 2, 1]; - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)); - array1 = [1, 2] - array2 = [1, 2, 3] + array1 = [1, 2]; + array2 = [1, 2, 3]; - t.false(isEqual(array1, array2)) -}) + t.false(isEqual(array1, array2)); +}); test('treat arrays with identical values but different non-index properties as unequal', t => { - let array1 = [1, 2, 3] - let array2 = [1, 2, 3] + let array1 = [1, 2, 3]; + let array2 = [1, 2, 3]; - array1.every = array1.filter = array1.forEach = - array1.indexOf = array1.lastIndexOf = array1.map = - array1.some = array1.reduce = array1.reduceRight = null + array1.every = array1.filter = array1.forEach + = array1.indexOf = array1.lastIndexOf = array1.map + = array1.some = array1.reduce = array1.reduceRight = null; - array2.concat = array2.join = array2.pop = - array2.reverse = array2.shift = array2.slice = - array2.sort = array2.splice = array2.unshift = null + array2.concat = array2.join = array2.pop + = array2.reverse = array2.shift = array2.slice + = array2.sort = array2.splice = array2.unshift = null; - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)); - array1 = [1, 2, 3] - array1.a = 1 + array1 = [1, 2, 3]; + array1.a = 1; - array2 = [1, 2, 3] - array2.b = 1 + array2 = [1, 2, 3]; + array2.b = 1; - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)); - array1 = /c/.exec('abcde') - array2 = ['c'] + array1 = /c/.exec('abcde'); + array2 = ['c']; - t.false(isEqual(array1, array2)) -}) + t.false(isEqual(array1, array2)); +}); test('compare sparse arrays', t => { - const array = new Array(1) + const array = Array.from({length: 1}); - t.true(isEqual(array, new Array(1))) - t.true(isEqual(array, [undefined])) - t.false(isEqual(array, new Array(2))) -}) + t.true(isEqual(array, Array.from({length: 1}))); + t.true(isEqual(array, [undefined])); + t.false(isEqual(array, Array.from({length: 2}))); +}); test('compare plain objects', t => { - let object1 = { a: true, b: null, c: 1, d: 'a', e: undefined } - let object2 = { a: true, b: null, c: 1, d: 'a', e: undefined } + let object1 = {a: true, b: null, c: 1, d: 'a', e: undefined}; + let object2 = {a: true, b: null, c: 1, d: 'a', e: undefined}; - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)); - object1 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } - object2 = { a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: { e: 1 } } + object1 = {a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}}; + object2 = {a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}}; - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)); - object1 = { a: 1, b: 2, c: 3 } - object2 = { a: 3, b: 2, c: 1 } + object1 = {a: 1, b: 2, c: 3}; + object2 = {a: 3, b: 2, c: 1}; - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)); - object1 = { a: 1, b: 2, c: 3 } - object2 = { d: 1, e: 2, f: 3 } + object1 = {a: 1, b: 2, c: 3}; + object2 = {d: 1, e: 2, f: 3}; - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)); - object1 = { a: 1, b: 2 } - object2 = { a: 1, b: 2, c: 3 } + object1 = {a: 1, b: 2}; + object2 = {a: 1, b: 2, c: 3}; - t.false(isEqual(object1, object2)) -}) + t.false(isEqual(object1, object2)); +}); test('compare objects regardless of key order', t => { - const object1 = { a: 1, b: 2, c: 3 } - const object2 = { c: 3, a: 1, b: 2 } + const object1 = {a: 1, b: 2, c: 3}; + const object2 = {c: 3, a: 1, b: 2}; - t.true(isEqual(object1, object2)) -}) + t.true(isEqual(object1, object2)); +}); test('compare nested objects', t => { - const noop = () => {} + const noop = () => {}; const object1 = { a: [1, 2, 3], @@ -185,7 +220,7 @@ test('compare nested objects', t => { i: noop, j: 'a', }, - } + }; const object2 = { a: [1, 2, 3], @@ -199,221 +234,232 @@ test('compare nested objects', t => { i: noop, j: 'a', }, - } + }; - t.true(isEqual(object1, object2)) -}) + t.true(isEqual(object1, object2)); +}); test('compare object instances', t => { - function Foo () { - this.a = 1 + function Foo() { + this.a = 1; } - Foo.prototype.a = 1 - function Bar () { - this.a = 1 + Foo.prototype.a = 1; + + function Bar() { + this.a = 1; } - Bar.prototype.a = 2 - t.true(isEqual(new Foo(), new Foo())) - t.false(isEqual(new Foo(), new Bar())) - t.false(isEqual({ a: 1 }, new Foo())) - t.false(isEqual({ a: 2 }, new Bar())) -}) + Bar.prototype.a = 2; + + t.true(isEqual(new Foo(), new Foo())); + t.false(isEqual(new Foo(), new Bar())); + t.false(isEqual({a: 1}, new Foo())); + t.false(isEqual({a: 2}, new Bar())); +}); test('compare objects with constructor properties', t => { - t.true(isEqual({ constructor: 1 }, { constructor: 1 })) - t.false(isEqual({ constructor: 1 }, { constructor: '1' })) - t.true(isEqual({ constructor: [1] }, { constructor: [1] })) - t.false(isEqual({ constructor: [1] }, { constructor: ['1'] })) - t.false(isEqual({ constructor: Object }, {})) -}) + t.true(isEqual({constructor: 1}, {constructor: 1})); + t.false(isEqual({constructor: 1}, {constructor: '1'})); + t.true(isEqual({constructor: [1]}, {constructor: [1]})); + t.false(isEqual({constructor: [1]}, {constructor: ['1']})); + t.false(isEqual({constructor: Object}, {})); +}); test('compare arrays with circular references', t => { - let array1 = [] - let array2 = [] + let array1 = []; + let array2 = []; - array1.push(array1) - array2.push(array2) + array1.push(array1); + array2.push(array2); - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1.push('b') - array2.push('b') + array1.push('b'); + array2.push('b'); - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1.push('c') - array2.push('d') + array1.push('c'); + array2.push('d'); - t.false(isEqual(array1, array2)) + t.false(isEqual(array1, array2)); - array1 = ['a', 'b', 'c'] - array1[1] = array1 - array2 = ['a', ['a', 'b', 'c'], 'c'] + array1 = ['a', 'b', 'c']; + array1[1] = array1; + array2 = ['a', ['a', 'b', 'c'], 'c']; - t.false(isEqual(array1, array2)) -}) + t.false(isEqual(array1, array2)); +}); test('have transitive equivalence for circular references of arrays', t => { - const array1 = [] - const array2 = [array1] - const array3 = [array2] + const array1 = []; + const array2 = [array1]; + const array3 = [array2]; - array1[0] = array1 + array1[0] = array1; - t.true(isEqual(array1, array2)) - t.true(isEqual(array2, array3)) + t.true(isEqual(array1, array2)); + t.true(isEqual(array2, array3)); // Concordance detects a different circular reference in array1 before it does // in array3, making them unequal. - t.false(isEqual(array1, array3)) -}) + t.false(isEqual(array1, array3)); +}); test('compare objects with circular references', t => { - let object1 = {} - let object2 = {} + let object1 = {}; + let object2 = {}; - object1.a = object1 - object2.a = object2 + object1.a = object1; + object2.a = object2; - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)); - object1.b = 0 - object2.b = 0 + object1.b = 0; + object2.b = 0; - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)); - object1.c = new Object(1) - object2.c = new Object(2) + object1.c = new Object(1); + object2.c = new Object(2); - t.false(isEqual(object1, object2)) + t.false(isEqual(object1, object2)); - object1 = { a: 1, b: 2, c: 3 } - object1.b = object1 - object2 = { a: 1, b: { a: 1, b: 2, c: 3 }, c: 3 } + object1 = {a: 1, b: 2, c: 3}; + object1.b = object1; + object2 = {a: 1, b: {a: 1, b: 2, c: 3}, c: 3}; - t.false(isEqual(object1, object2)) -}) + t.false(isEqual(object1, object2)); +}); test('have transitive equivalence for circular references of objects', t => { - const object1 = {} - const object2 = { a: object1 } - const object3 = { a: object2 } + const object1 = {}; + const object2 = {a: object1}; + const object3 = {a: object2}; - object1.a = object1 + object1.a = object1; - t.true(isEqual(object1, object2)) - t.true(isEqual(object2, object3)) + t.true(isEqual(object1, object2)); + t.true(isEqual(object2, object3)); // Concordance detects a different circular reference in object1 before it // does in object3, making them unequal. - t.false(isEqual(object1, object3)) -}) + t.false(isEqual(object1, object3)); +}); test('compare objects with multiple circular references', t => { - const array1 = [{}] + const array1 = [{}]; const array2 = [{}]; (array1[0].a = array1).push(array1); - (array2[0].a = array2).push(array2) + (array2[0].a = array2).push(array2); - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1[0].b = 0 - array2[0].b = 0 + array1[0].b = 0; + array2[0].b = 0; - t.true(isEqual(array1, array2)) + t.true(isEqual(array1, array2)); - array1[0].c = new Object(1) - array2[0].c = new Object(2) + array1[0].c = new Object(1); + array2[0].c = new Object(2); - t.false(isEqual(array1, array2)) -}) + t.false(isEqual(array1, array2)); +}); test('compare objects with complex circular references', t => { const object1 = { - foo: { b: { c: { d: {} } } }, - bar: { a: 2 }, - } + foo: {b: {c: {d: {}}}}, + bar: {a: 2}, + }; const object2 = { - foo: { b: { c: { d: {} } } }, - bar: { a: 2 }, - } + foo: {b: {c: {d: {}}}}, + bar: {a: 2}, + }; - object1.foo.b.c.d = object1 - object1.bar.b = object1.foo.b + object1.foo.b.c.d = object1; + object1.bar.b = object1.foo.b; - object2.foo.b.c.d = object2 - object2.bar.b = object2.foo.b + object2.foo.b.c.d = object2; + object2.bar.b = object2.foo.b; - t.true(isEqual(object1, object2)) -}) + t.true(isEqual(object1, object2)); +}); test('compare objects with shared property values', t => { const object1 = { a: [1, 2], - } + }; const object2 = { a: [1, 2], b: [1, 2], - } + }; - object1.b = object1.a + object1.b = object1.a; - t.true(isEqual(object1, object2)) -}) + t.true(isEqual(object1, object2)); +}); test('treat objects created by `Object.create(null)` like plain objects', t => { - function Foo () { - this.a = 1 + function Foo() { + this.a = 1; } - Foo.prototype.constructor = null - const object1 = Object.create(null) - object1.a = 1 + Foo.prototype.constructor = null; + + const object1 = Object.create(null); + object1.a = 1; - const object2 = { a: 1 } + const object2 = {a: 1}; - t.true(isEqual(object1, object2)) - t.false(isEqual(new Foo(), object2)) -}) + t.true(isEqual(object1, object2)); + t.false(isEqual(new Foo(), object2)); +}); test('avoid common type coercions', t => { - t.false(isEqual(true, new Object(false))) - t.false(isEqual(new Object(false), new Object(0))) - t.false(isEqual(false, new Object(''))) - t.false(isEqual(new Object(36), new Object('36'))) - t.false(isEqual(0, '')) - t.false(isEqual(1, true)) - t.false(isEqual(1337756400000, new Date(2012, 4, 23))) - t.false(isEqual('36', 36)) - t.false(isEqual(36, '36')) -}) + t.false(isEqual(true, new Object(false))); + t.false(isEqual(new Object(false), new Object(0))); + t.false(isEqual(false, new Object(''))); + t.false(isEqual(new Object(36), new Object('36'))); + t.false(isEqual(0, '')); + t.false(isEqual(1, true)); + t.false(isEqual(1_337_756_400_000, new Date(2012, 4, 23))); + t.false(isEqual('36', 36)); + t.false(isEqual(36, '36')); +}); test('compare `arguments` objects', t => { - const args1 = (function () { return arguments }()) - const args2 = (function () { return arguments }()) - const args3 = (function () { return arguments }(1, 2)) - - t.true(isEqual(args1, args2)) - t.false(isEqual(args1, args3)) -}) + const args1 = (function () { + return arguments; + })(); + const args2 = (function () { + return arguments; + })(); + const args3 = (function () { + return arguments; + })(1, 2); + + t.true(isEqual(args1, args2)); + t.false(isEqual(args1, args3)); +}); test('actual `arguments` objects may be compared to expected arrays', t => { - const array = [1, 2, 3] + const array = [1, 2, 3]; - const args = (function () { return arguments })(1, 2, 3) - t.true(isEqual(args, array)) - t.false(isEqual(array, args)) -}) + const args = (function () { + return arguments; + })(1, 2, 3); + t.true(isEqual(args, array)); + t.false(isEqual(array, args)); +}); test('compare array buffers', t => { - const buffer = new Int8Array([-1]).buffer + const {buffer} = new Int8Array([-1]); - t.true(isEqual(buffer, new Uint8Array([255]).buffer)) - t.false(isEqual(buffer, new ArrayBuffer(1))) -}) + t.true(isEqual(buffer, new Uint8Array([255]).buffer)); + t.false(isEqual(buffer, new ArrayBuffer(1))); +}); test('compare array views', t => { const arrayViews = [ @@ -427,41 +473,43 @@ test('compare array views', t => { 'Uint16Array', 'Uint32Array', 'DataView', - ] + ]; - const namespaces = [global, realm] + const namespaces = [global, realm]; for (const ns of namespaces) { - arrayViews.forEach((type, viewIndex) => { - const otherType = arrayViews[(viewIndex + 1) % arrayViews.length] - const CtorA = ns[type] - const CtorB = ns[otherType] - const bufferA = new ns.ArrayBuffer(8) - const bufferB = new ns.ArrayBuffer(8) - const bufferC = new ns.ArrayBuffer(16) - - t.true(isEqual(new CtorA(bufferA), new CtorA(bufferA))) - t.false(isEqual(new CtorA(bufferA), new CtorB(bufferB))) - t.false(isEqual(new CtorB(bufferB), new CtorB(bufferC))) - }) + for (const [viewIndex, type] of arrayViews.entries()) { + const otherType = arrayViews[(viewIndex + 1) % arrayViews.length]; + const CtorA = ns[type]; + const CtorB = ns[otherType]; + const bufferA = new ns.ArrayBuffer(8); + const bufferB = new ns.ArrayBuffer(8); + const bufferC = new ns.ArrayBuffer(16); + + t.true(isEqual(new CtorA(bufferA), new CtorA(bufferA))); + t.false(isEqual(new CtorA(bufferA), new CtorB(bufferB))); + t.false(isEqual(new CtorB(bufferB), new CtorB(bufferC))); + } } -}) +}); test('compare buffers', t => { - const buffer = Buffer.from([1]) + const buffer = Buffer.from([1]); - t.true(isEqual(buffer, Buffer.from([1]))) - t.false(isEqual(buffer, Buffer.from([2]))) - t.false(isEqual(buffer, new Uint8Array([1]))) -}) + t.true(isEqual(buffer, Buffer.from([1]))); + t.false(isEqual(buffer, Buffer.from([2]))); + t.false(isEqual(buffer, new Uint8Array([1]))); +}); test('compare date objects', t => { - const date = new Date(2012, 4, 23) + const date = new Date(2012, 4, 23); - t.true(isEqual(date, new Date(2012, 4, 23))) - t.true(isEqual(new Date('a'), new Date('b'))) - t.false(isEqual(date, new Date(2013, 3, 25))) - t.false(isEqual(date, { getTime () { return +date } })) -}) + t.true(isEqual(date, new Date(2012, 4, 23))); + t.true(isEqual(new Date('a'), new Date('b'))); + t.false(isEqual(date, new Date(2013, 3, 25))); + t.false(isEqual(date, {getTime() { + return Number(date); + }})); +}); test('compare error objects', t => { const errorTypes = [ @@ -472,156 +520,163 @@ test('compare error objects', t => { 'SyntaxError', 'TypeError', 'URIError', - ] + ]; - errorTypes.forEach((type, index) => { - const otherType = errorTypes[++index % errorTypes.length] - const CtorA = global[type] - const CtorB = global[otherType] + for (let [index, type] of errorTypes.entries()) { + const otherType = errorTypes[++index % errorTypes.length]; + const CtorA = global[type]; + const CtorB = global[otherType]; - t.true(isEqual(new CtorA('a'), new CtorA('a'))) - t.false(isEqual(new CtorA('a'), new CtorB('a'))) - t.false(isEqual(new CtorB('a'), new CtorB('b'))) - }) -}) + t.true(isEqual(new CtorA('a'), new CtorA('a'))); + t.false(isEqual(new CtorA('a'), new CtorB('a'))); + t.false(isEqual(new CtorB('a'), new CtorB('b'))); + } +}); test('compare functions', t => { - function a () { return 1 + 2 } - function b () { return 1 + 2 } + function a() { + return 1 + 2; + } + + function b() { + return 1 + 2; + } - t.true(isEqual(a, a)) - t.false(isEqual(a, b)) -}) + t.true(isEqual(a, a)); + t.false(isEqual(a, b)); +}); test('compare maps', t => { - const map1 = new Map() + const map1 = new Map(); for (const map2 of [new Map(), new realm.Map()]) { - map1.set('a', 1) - map2.set('b', 2) - t.false(isEqual(map1, map2)) + map1.set('a', 1); + map2.set('b', 2); + t.false(isEqual(map1, map2)); - map1.set('b', 2) - map2.set('a', 1) - t.false(isEqual(map1, map2)) + map1.set('b', 2); + map2.set('a', 1); + t.false(isEqual(map1, map2)); - map1.delete('a') - map1.set('a', 1) - t.true(isEqual(map1, map2)) + map1.delete('a'); + map1.set('a', 1); + t.true(isEqual(map1, map2)); - map2.delete('a') - t.false(isEqual(map1, map2)) + map2.delete('a'); + t.false(isEqual(map1, map2)); - map1.clear() - map2.clear() + map1.clear(); + map2.clear(); } -}) +}); test('compare maps with circular references', t => { - const map1 = new Map() - const map2 = new Map() + const map1 = new Map(); + const map2 = new Map(); - map1.set('a', map1) - map2.set('a', map2) - t.true(isEqual(map1, map2)) + map1.set('a', map1); + map2.set('a', map2); + t.true(isEqual(map1, map2)); - map1.set('b', 1) - map2.set('b', 2) - t.false(isEqual(map1, map2)) -}) + map1.set('b', 1); + map2.set('b', 2); + t.false(isEqual(map1, map2)); +}); test('compare promises by reference', t => { - const promise1 = Promise.resolve(1) + const promise1 = Promise.resolve(1); for (const promise2 of [Promise.resolve(1), realm.Promise.resolve(1)]) { - t.false(isEqual(promise1, promise2)) - t.true(isEqual(promise1, promise1)) + t.false(isEqual(promise1, promise2)); + t.true(isEqual(promise1, promise1)); } -}) +}); test('compare regexes', t => { - t.true(isEqual(/x/gim, /x/gim)) - t.true(isEqual(/x/gim, /x/gim)) - t.false(isEqual(/x/gi, /x/g)) - t.false(isEqual(/x/, /y/)) - t.false(isEqual(/x/g, { global: true, ignoreCase: false, multiline: false, source: 'x' })) -}) + t.true(isEqual(/x/gim, /x/gim)); + t.true(isEqual(/x/gim, /x/gim)); + t.false(isEqual(/x/gi, /x/g)); + t.false(isEqual(/x/, /y/)); + t.false(isEqual(/x/g, {global: true, ignoreCase: false, multiline: false, source: 'x'})); +}); test('compare sets', t => { - const set1 = new Set() + const set1 = new Set(); for (const set2 of [new Set(), new realm.Set()]) { - set1.add(1) - set2.add(2) - t.false(isEqual(set1, set2)) + set1.add(1); + set2.add(2); + t.false(isEqual(set1, set2)); - set1.add(2) - set2.add(1) - t.false(isEqual(set1, set2)) + set1.add(2); + set2.add(1); + t.false(isEqual(set1, set2)); - set1.delete(1) - set1.add(1) - t.true(isEqual(set1, set2)) + set1.delete(1); + set1.add(1); + t.true(isEqual(set1, set2)); - set2.delete(1) - t.false(isEqual(set1, set2)) + set2.delete(1); + t.false(isEqual(set1, set2)); - set1.clear() - set2.clear() + set1.clear(); + set2.clear(); } -}) +}); test('compare sets with circular references', t => { - const set1 = new Set() - const set2 = new Set() + const set1 = new Set(); + const set2 = new Set(); - set1.add(set1) - set2.add(set2) - t.true(isEqual(set1, set2)) + set1.add(set1); + set2.add(set2); + t.true(isEqual(set1, set2)); - set1.add(1) - set2.add(2) - t.false(isEqual(set1, set2)) -}) + set1.add(1); + set2.add(2); + t.false(isEqual(set1, set2)); +}); test('compare symbol properties', t => { - const object1 = { a: 1 } - const object2 = { a: 1 } + const object1 = {a: 1}; + const object2 = {a: 1}; - object1[symbol1] = { a: { b: 2 } } - object2[symbol1] = { a: { b: 2 } } + object1[symbol1] = {a: {b: 2}}; + object2[symbol1] = {a: {b: 2}}; Object.defineProperty(object2, symbol2, { configurable: true, enumerable: false, writable: true, value: 2, - }) + }); - t.true(isEqual(object1, object2)) + t.true(isEqual(object1, object2)); - object2[symbol1] = { a: 1 } - t.false(isEqual(object1, object2)) + object2[symbol1] = {a: 1}; + t.false(isEqual(object1, object2)); - delete object2[symbol1] - object2[Symbol('a')] = { a: { b: 2 } } - t.false(isEqual(object1, object2)) -}) + delete object2[symbol1]; + object2[Symbol('a')] = {a: {b: 2}}; + t.false(isEqual(object1, object2)); +}); test('return `true` for like-objects from different realms', t => { - const array = new realm.Array() - array.push(1) - t.true(isEqual([1], array)) - t.false(isEqual([2], array)) + const array = new realm.Array(); + array.push(1); + t.true(isEqual([1], array)); + t.false(isEqual([2], array)); - const object = new realm.Object() - object.a = 1 - t.true(isEqual({ a: 1 }, object)) - t.false(isEqual({ a: 2 }, object)) -}) + const object = new realm.Object(); + object.a = 1; + t.true(isEqual({a: 1}, object)); + t.false(isEqual({a: 2}, object)); +}); test('return `false` for objects with custom `toString` methods', t => { - let primitive - const object = { 'toString' () { return primitive } } + let primitive; + const object = {'toString'() { + return primitive; + }}; for (const value of [true, null, 1, 'a', undefined]) { - primitive = value - t.false(isEqual(object, value)) + primitive = value; + t.false(isEqual(object, value)); } -}) +}); diff --git a/test/max-depth.js b/test/max-depth.js index 2258765..045975e 100644 --- a/test/max-depth.js +++ b/test/max-depth.js @@ -1,5 +1,6 @@ -import test from 'ava' -import { format, diff } from '../index.js' +import test from 'ava'; + +import {format, diff} from '../index.js'; const deep = { one: { @@ -12,32 +13,33 @@ const deep = { arr: [], arr2: [[]], date: new Date('1969-07-20T20:17:40Z'), - date2: Object.assign(new Date('1969-07-20T20:17:40Z'), { foo: 'bar' }), + date2: Object.assign(new Date('1969-07-20T20:17:40Z'), {foo: 'bar'}), + // eslint-disable-next-line unicorn/error-message error: new Error(), - fn () {}, - fn2: Object.assign(() => {}, { foo: 'bar' }), + fn() {}, + fn2: Object.assign(() => {}, {foo: 'bar'}), map: new Map(), map2: new Map([['foo', 'bar']]), obj: {}, regexp: /foo/, - regexp2: Object.assign(/foo/, { foo: 'bar' }), + regexp2: Object.assign(/foo/, {foo: 'bar'}), set: new Set(), set2: new Set(['foo']), }, - arr: [{ three: { four: {} } }], - map: new Map([[{ three: { four: {} } }, { three: { four: {} } }]]), - set: new Set([{ three: { four: {} } }]), + arr: [{three: {four: {}}}], + map: new Map([[{three: {four: {}}}, {three: {four: {}}}]]), + set: new Set([{three: {four: {}}}]), }, -} +}; test('format() respects maxDepth option', t => { - t.snapshot(format(deep, { maxDepth: 3 })) -}) + t.snapshot(format(deep, {maxDepth: 3})); +}); test('diff() respects maxDepth option for equal parts', t => { - t.snapshot(diff(Object.assign({ unequal: 1 }, deep), Object.assign({ unequal: 2 }, deep), { maxDepth: 3 })) - t.snapshot(diff({ one: { two: { three: 'baz', three2: ['quux'] } } }, { one: { two: { three: 'qux', three2: ['quux'] } } }, { maxDepth: 1 })) // eslint-disable-line max-len -}) + t.snapshot(diff({unequal: 1, ...deep}, {unequal: 2, ...deep}, {maxDepth: 3})); + t.snapshot(diff({one: {two: {three: 'baz', three2: ['quux']}}}, {one: {two: {three: 'qux', three2: ['quux']}}}, {maxDepth: 1})); +}); test('properties with increased indentation respect the maxDepth when formatted', t => { t.snapshot(format({ @@ -51,5 +53,5 @@ test('properties with increased indentation respect the maxDepth when formatted' increaseValueIndent: true, }, }, - })) -}) + })); +}); diff --git a/test/odd-properties.js b/test/odd-properties.js index bab952d..9fa917e 100644 --- a/test/odd-properties.js +++ b/test/odd-properties.js @@ -1,9 +1,10 @@ -import test from 'ava' -import { compare } from '../index.js' +import test from 'ava'; + +import {compare} from '../index.js'; test('ignores undescribed own properties', t => { - const a = new Proxy({ a: 1 }, { - getOwnPropertyDescriptor (target, prop) {}, - }) - t.true(compare(a, {}).pass) -}) + const a = new Proxy({a: 1}, { + getOwnPropertyDescriptor(_target, _prop) {}, + }); + t.true(compare(a, {}).pass); +}); diff --git a/test/pluginRegistry.js b/test/pluginRegistry.js index 9daa098..b6bc50b 100644 --- a/test/pluginRegistry.js +++ b/test/pluginRegistry.js @@ -1,61 +1,61 @@ -import test from 'ava' -import esmock from 'esmock' +import test from 'ava'; +import esmock from 'esmock'; const pluginRegistry = await esmock('../lib/pluginRegistry', { - import: { JSON: { parse: () => ({ version: '1.0.0' }) } }, -}) + import: {JSON: {parse: () => ({version: '1.0.0'})}}, +}); test('registration should fail when plugin name invalid', t => { - t.throws(() => pluginRegistry.add({ name: { for: 'complex' } }), { name: 'PluginTypeError' }) -}) + t.throws(() => pluginRegistry.add({name: {for: 'complex'}}), {name: 'PluginTypeError'}); +}); test('registration should fail when api version unsupported', t => { - t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 2 }), { name: 'UnsupportedApiError' }) -}) + t.throws(() => pluginRegistry.add({name: 'complex', apiVersion: 2}), {name: 'UnsupportedApiError'}); +}); test('registration should fail when installed concordance version below minimal version required by plugin', t => { - t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 1, minimalConcordanceVersion: '2.0.0' }), - { name: 'UnsupportedError' }) -}) + t.throws(() => pluginRegistry.add({name: 'complex', apiVersion: 1, minimalConcordanceVersion: '2.0.0'}), + {name: 'UnsupportedError'}); +}); test('registration should fail when descriptor id used twice', t => { const plugin = { name: 'complex', apiVersion: 1, - register: concordance => { - concordance.addDescriptor(1, 'complexCustomValue') - concordance.addDescriptor(1, 'complexCustomValue') + register(concordance) { + concordance.addDescriptor(1, 'complexCustomValue'); + concordance.addDescriptor(1, 'complexCustomValue'); }, - } - t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorIdError' }) -}) + }; + t.throws(() => pluginRegistry.add(plugin), {name: 'DuplicateDescriptorIdError'}); +}); test('registration should fail when descriptor tag used twice', t => { const plugin = { name: 'complex', apiVersion: 1, - register: concordance => { - concordance.addDescriptor(1, 'complexCustomValue') - concordance.addDescriptor(2, 'complexCustomValue') + register(concordance) { + concordance.addDescriptor(1, 'complexCustomValue'); + concordance.addDescriptor(2, 'complexCustomValue'); }, - } - t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorTagError' }) -}) + }; + t.throws(() => pluginRegistry.add(plugin), {name: 'DuplicateDescriptorTagError'}); +}); test('registration should be successful', t => { - t.plan(2) - const tryDescribeValue = () => { } // eslint-disable-line unicorn/consistent-function-scoping + t.plan(2); + const tryDescribeValue = () => {}; const plugin = { name: 'complex', apiVersion: 1, serializerVersion: 1, - register: concordance => { - t.pass() - concordance.addDescriptor(1, 'complexCustomObject', 'objectDeserializer') - concordance.addDescriptor(2, 'complexCustomArray', 'arrayDeserializer') - return tryDescribeValue + register(concordance) { + t.pass(); + concordance.addDescriptor(1, 'complexCustomObject', 'objectDeserializer'); + concordance.addDescriptor(2, 'complexCustomArray', 'arrayDeserializer'); + return tryDescribeValue; }, - } + }; - t.snapshot(pluginRegistry.add(plugin)) -}) + t.snapshot(pluginRegistry.add(plugin)); +}); diff --git a/test/serialization-fixtures.js b/test/serialization-fixtures.js index 7fbc5c8..b18c970 100644 --- a/test/serialization-fixtures.js +++ b/test/serialization-fixtures.js @@ -1,8 +1,9 @@ -import test from 'ava' +import test from 'ava'; -import { compareDescriptors, deserialize, describe } from '../index.js' -import { serialization, tree } from './fixtures/pointerSerialization.js' +import {compareDescriptors, deserialize, describe} from '../index.js'; + +import {serialization, tree} from './fixtures/pointerSerialization.js'; test('pointer serialization equals the same tree', t => { - t.true(compareDescriptors(deserialize(serialization), describe(tree))) -}) + t.true(compareDescriptors(deserialize(serialization), describe(tree))); +}); diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index fdfc410..3f106d7 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -1,163 +1,174 @@ -import test from 'ava' +/* eslint-disable prefer-rest-params, require-yield */ +import {Buffer} from 'node:buffer'; -import { compareDescriptors, describe, diffDescriptors, formatDescriptor } from '../index.js' -import { deserialize, serialize } from '../lib/serialize.js' -import * as customErrorPlugin from './fixtures/customErrorPlugin.js' +import test from 'ava'; + +import {compareDescriptors, describe, diffDescriptors, formatDescriptor} from '../index.js'; +import {deserialize, serialize} from '../lib/serialize.js'; + +import * as customErrorPlugin from './fixtures/customErrorPlugin.js'; test('serializes a descriptor into a buffer', t => { - const result = serialize(describe({ foo: 'bar' })) - t.true(Buffer.isBuffer(result)) -}) + const result = serialize(describe({foo: 'bar'})); + t.true(Buffer.isBuffer(result)); +}); const plugins = [ { name: 'CustomError', apiVersion: 1, serializerVersion: 1, - register: props => { - const custom = customErrorPlugin.factory(props) - props.addDescriptor(1, custom.tag, custom.deserialize) + register(props) { + const custom = customErrorPlugin.factory(props); + props.addDescriptor(1, custom.tag, custom.deserialize); return function (value) { if (value.name === 'CustomError') { - return custom.describe + return custom.describe; } - } + }; }, }, -] +]; const useDeserialized = (t, value, options) => { - const original = describe(value, options) + const original = describe(value, options); - const buffer = serialize(original) - const deserialized = deserialize(buffer, options) + const buffer = serialize(original); + const deserialized = deserialize(buffer, options); t.true( compareDescriptors(deserialized, original), - 'the deserialized descriptor equals the original') + 'the deserialized descriptor equals the original'); t.is( formatDescriptor(deserialized), formatDescriptor(original), - 'the deserialized descriptor is formatted like the original') + 'the deserialized descriptor is formatted like the original'); - const redeserialized = deserialize(serialize(deserialized), options) + const redeserialized = deserialize(serialize(deserialized), options); t.true( compareDescriptors(redeserialized, original), - 'after serializing and deserializing it again, the deserialized descriptor equals the original') + 'after serializing and deserializing it again, the deserialized descriptor equals the original'); t.is( formatDescriptor(redeserialized), formatDescriptor(original), - 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original') + 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original'); t.true( compareDescriptors(redeserialized, deserialized), - 'deserialized descriptors equal each other') -} -useDeserialized.title = (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original` + 'deserialized descriptors equal each other'); +}; + +useDeserialized.title = (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original`; // Primitives -test(useDeserialized, true) -test(useDeserialized, false) -test(useDeserialized, null) -test(useDeserialized, 0) -test('-0', useDeserialized, -0) -test(useDeserialized, NaN) -test(useDeserialized, Infinity) -test(useDeserialized, -Infinity) -test('-0x80 (int8)', useDeserialized, -0x80) -test('0x7F (int8)', useDeserialized, 0x7F) -test('-0x8000 (int16)', useDeserialized, -0x8000) -test('0x7FFF (int16)', useDeserialized, 0x7FFF) -test('-0x800000 (int24)', useDeserialized, -0x800000) -test('0x7FFFFF (int24)', useDeserialized, 0x7FFFFF) -test('-0x80000000 (int32)', useDeserialized, -0x80000000) -test('0x7FFFFFFF (int32)', useDeserialized, 0x7FFFFFFF) -test('-0x8000000000 (int40)', useDeserialized, -0x8000000000) -test('0x7FFFFFFFFF (int40)', useDeserialized, 0x7FFFFFFFFF) -test('-0x800000000000 (int48)', useDeserialized, -0x800000000000) -test('0x7FFFFFFFFFFF (int48)', useDeserialized, 0x7FFFFFFFFFFF) -test('-0x800000000001 (larger than int48)', useDeserialized, -0x80000000001) -test('0x800000000000 (larger than int48)', useDeserialized, 0x800000000000) -test('Number.MIN_VALUE', useDeserialized, Number.MIN_VALUE) -test('Number.MAX_VALUE', useDeserialized, Number.MAX_VALUE) -test('0.1 + 0.2 (float)', useDeserialized, 0.1 + 0.2) -test('\'foo\' (ascii string)', useDeserialized, 'foo') -test('\'🚀\' (unicode string)', useDeserialized, '🚀') -test('Symbol.iterator', useDeserialized, Symbol.iterator) -test('Symbol.for(\'foo\')', useDeserialized, Symbol.for('foo')) -test('Symbol(\'foo\')', useDeserialized, Symbol('foo')) -test(useDeserialized, undefined) +test(useDeserialized, true); +test(useDeserialized, false); +test(useDeserialized, null); +test(useDeserialized, 0); +test('-0', useDeserialized, -0); +test(useDeserialized, Number.NaN); +test(useDeserialized, Number.POSITIVE_INFINITY); +test(useDeserialized, Number.NEGATIVE_INFINITY); +test('-0x80 (int8)', useDeserialized, -0x80); +test('0x7F (int8)', useDeserialized, 0x7F); +test('-0x8000 (int16)', useDeserialized, -0x80_00); +test('0x7FFF (int16)', useDeserialized, 0x7F_FF); +test('-0x800000 (int24)', useDeserialized, -0x80_00_00); +test('0x7FFFFF (int24)', useDeserialized, 0x7F_FF_FF); +test('-0x80000000 (int32)', useDeserialized, -0x80_00_00_00); +test('0x7FFFFFFF (int32)', useDeserialized, 0x7F_FF_FF_FF); +test('-0x8000000000 (int40)', useDeserialized, -0x80_00_00_00_00); +test('0x7FFFFFFFFF (int40)', useDeserialized, 0x7F_FF_FF_FF_FF); +test('-0x800000000000 (int48)', useDeserialized, -0x80_00_00_00_00_00); +test('0x7FFFFFFFFFFF (int48)', useDeserialized, 0x7F_FF_FF_FF_FF_FF); +test('-0x800000000001 (larger than int48)', useDeserialized, -0x8_00_00_00_00_01); +test('0x800000000000 (larger than int48)', useDeserialized, 0x80_00_00_00_00_00); +test('Number.MIN_VALUE', useDeserialized, Number.MIN_VALUE); +test('Number.MAX_VALUE', useDeserialized, Number.MAX_VALUE); +test('0.1 + 0.2 (float)', useDeserialized, 0.1 + 0.2); +test('\'foo\' (ascii string)', useDeserialized, 'foo'); +test('\'🚀\' (unicode string)', useDeserialized, '🚀'); +test('Symbol.iterator', useDeserialized, Symbol.iterator); +test('Symbol.for(\'foo\')', useDeserialized, Symbol.for('foo')); +test('Symbol(\'foo\')', useDeserialized, Symbol('foo')); +test(useDeserialized, undefined); if (typeof BigInt === 'function') { - test('42n', useDeserialized, BigInt(42)) // eslint-disable-line no-undef + test('42n', useDeserialized, BigInt(42)); } // Objects -test('object with primitive property', useDeserialized, { foo: 'bar' }) -test('object with complex property', useDeserialized, { foo: {} }) -test('object with well known symbol key', useDeserialized, { [Symbol.unscopables]: 'bar' }) -test('object with registered symbol key', useDeserialized, { [Symbol.for('foo')]: 'bar' }) -test('object with arbitrary symbol key', useDeserialized, { [Symbol('foo')]: 'bar' }) -test('object with length property', useDeserialized, { length: 12345678 }) -test('object with negative length property', useDeserialized, { length: -12345678 }) -test('object with NaN length property', useDeserialized, { length: NaN }) -test('object with infinite length property', useDeserialized, { length: Infinity }) -test('object with fractional length property', useDeserialized, { length: 1.5 }) +test('object with primitive property', useDeserialized, {foo: 'bar'}); +test('object with complex property', useDeserialized, {foo: {}}); +test('object with well known symbol key', useDeserialized, {[Symbol.unscopables]: 'bar'}); +test('object with registered symbol key', useDeserialized, {[Symbol.for('foo')]: 'bar'}); +test('object with arbitrary symbol key', useDeserialized, {[Symbol('foo')]: 'bar'}); +test('object with length property', useDeserialized, {length: 12_345_678}); +test('object with negative length property', useDeserialized, {length: -12_345_678}); +test('object with NaN length property', useDeserialized, {length: Number.NaN}); +test('object with infinite length property', useDeserialized, {length: Number.POSITIVE_INFINITY}); +test('object with fractional length property', useDeserialized, {length: 1.5}); test('symbol properties are reordered despite serialization', t => { - const s1 = Symbol('s1') - const s2 = Symbol('s2') - const original = describe({ [s1]: 1, [s2]: 2 }) - const expected = describe({ [s2]: 2, [s1]: 1 }) + const s1 = Symbol('s1'); + const s2 = Symbol('s2'); + const original = describe({[s1]: 1, [s2]: 2}); + const expected = describe({[s2]: 2, [s1]: 1}); - t.true(compareDescriptors(deserialize(serialize(original)), expected)) - t.snapshot(diffDescriptors(deserialize(serialize(original)), expected)) + t.true(compareDescriptors(deserialize(serialize(original)), expected)); + t.snapshot(diffDescriptors(deserialize(serialize(original)), expected)); - t.true(compareDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) - t.snapshot(diffDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))) -}) + t.true(compareDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))); + t.snapshot(diffDescriptors(deserialize(serialize(original)), deserialize(serialize(expected)))); +}); // Arrays -test('array with primitive item', useDeserialized, ['bar']) -test('array with complex item', useDeserialized, [{}]) +test('array with primitive item', useDeserialized, ['bar']); +test('array with complex item', useDeserialized, [{}]); // Iterators test('iterator with primitive item', useDeserialized, Object.create({}, { [Symbol.iterator]: { enumerable: false, - * value () { return 'bar' }, + * value() { + return 'bar'; + }, }, - })) + })); test('iterator with complex item', useDeserialized, Object.create({}, { [Symbol.iterator]: { enumerable: false, - * value () { return {} }, + * value() { + return {}; + }, }, - })) + })); // Maps -test('map with primitive key and value', useDeserialized, new Map([['foo', 'bar']])) -test('map with complex key and primitive value', useDeserialized, new Map([[{}, 'bar']])) -test('map with complex key and value', useDeserialized, new Map([[{}, {}]])) -test('map with primitive key and complex value', useDeserialized, new Map([['foo', {}]])) +test('map with primitive key and value', useDeserialized, new Map([['foo', 'bar']])); +test('map with complex key and primitive value', useDeserialized, new Map([[{}, 'bar']])); +test('map with complex key and value', useDeserialized, new Map([[{}, {}]])); +test('map with primitive key and complex value', useDeserialized, new Map([['foo', {}]])); // Sets -test('set with primitive value', useDeserialized, new Set(['foo'])) -test('set with complex value', useDeserialized, new Set([{}])) +test('set with primitive value', useDeserialized, new Set(['foo'])); +test('set with complex value', useDeserialized, new Set([{}])); // Pointers { - const obj = {} - obj.self = obj - test('object with pointer to itself', useDeserialized, obj) + const object = {}; + object.self = object; + test('object with pointer to itself', useDeserialized, object); } // Other complex values -test('arguments', useDeserialized, (function () { return arguments })('foo', {})) +test('arguments', useDeserialized, (function () { + return arguments; +})('foo', {})); { - const buffer = Buffer.from('decafbad'.repeat(12), 'hex') - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) + const buffer = Buffer.from('decafbad'.repeat(12), 'hex'); + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); for (const [tag, value] of [ ['ArrayBuffer', arrayBuffer], @@ -173,56 +184,65 @@ test('arguments', useDeserialized, (function () { return arguments })('foo', {}) ['Uint8Array', new Uint8Array(arrayBuffer)], ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], ]) { - test(tag, useDeserialized, value) + test(tag, useDeserialized, value); } } -test('date', useDeserialized, new Date('1969-07-20T20:17:40Z')) -test('error', useDeserialized, new Error('foo')) -test('function', useDeserialized, function foo () {}) + +test('date', useDeserialized, new Date('1969-07-20T20:17:40Z')); +test('error', useDeserialized, new Error('foo')); +test('function', useDeserialized, function foo() {}); test('compare functions with different names', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - function b () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - - const original = describe(a) - const deserialized = deserialize(serialize(original)) - t.false(compareDescriptors(deserialized, describe(b))) - t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) -}) + function a() { + return 1 + 2; + } + + function b() { + return 1 + 2; + } + + const original = describe(a); + const deserialized = deserialize(serialize(original)); + t.false(compareDescriptors(deserialized, describe(b))); + t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))); +}); test('compare deserialized function with object', t => { - function a () { return 1 + 2 } // eslint-disable-line unicorn/consistent-function-scoping - const b = { bar: 'b' } - - const original = describe(a) - const deserialized = deserialize(serialize(original)) - t.false(compareDescriptors(deserialized, describe(b))) - t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))) -}) -test('generator function', useDeserialized, function * foo () {}) -test('global', useDeserialized, global) -test('promise', useDeserialized, Promise.resolve()) -test('regexp', useDeserialized, /foo/gi) - -test('plugin', useDeserialized, new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins }) + function a() { + return 1 + 2; + } + + const b = {bar: 'b'}; + + const original = describe(a); + const deserialized = deserialize(serialize(original)); + t.false(compareDescriptors(deserialized, describe(b))); + t.not(formatDescriptor(deserialized), formatDescriptor(describe(b))); +}); +test('generator function', useDeserialized, function * foo() {}); +test('global', useDeserialized, global); +test('promise', useDeserialized, Promise.resolve()); +test('regexp', useDeserialized, /foo/gi); + +test('plugin', useDeserialized, new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), {plugins}); test('should fail when plugin for deserialization missing', t => { const deserializationPlugins = [ { name: 'CustomError_v2', apiVersion: 1, serializerVersion: 2, - register: props => { - const custom = customErrorPlugin.factory(props) - props.addDescriptor(1, Symbol('CustomError_v2'), custom.deserialize) + register(props) { + const custom = customErrorPlugin.factory(props); + props.addDescriptor(1, Symbol('CustomError_v2'), custom.deserialize); return function (value) { if (value.name === 'CustomError') { - return custom.describe + return custom.describe; } - } + }; }, }, - ] + ]; t.throws(() => { - const serialized = serialize(describe(new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins })) - deserialize(serialized, { plugins: deserializationPlugins }) - }, { name: 'MissingPluginError' }) -}) + const serialized = serialize(describe(new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), {plugins})); + deserialize(serialized, {plugins: deserializationPlugins}); + }, {name: 'MissingPluginError'}); +}); From 54cfb071d2b8bd459defee4e41c76230ed2b2be4 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Mon, 21 Aug 2023 10:42:06 -0500 Subject: [PATCH 05/13] update `AVA` --- package.json | 6 +++--- test/format.js | 2 +- test/serialization-fixtures.js | 3 ++- test/serialize-and-encode.js | 19 ++++++++++++++----- test/snapshots/diff.js.md | 2 +- test/snapshots/diff.js.snap | Bin 5492 -> 4882 bytes test/snapshots/format.js.md | 2 +- test/snapshots/format.js.snap | Bin 4650 -> 3438 bytes test/snapshots/max-depth.js.snap | Bin 536 -> 605 bytes test/snapshots/pluginRegistry.js.snap | Bin 407 -> 446 bytes test/snapshots/serialize-and-encode.js.snap | Bin 130 -> 202 bytes 11 files changed, 22 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index ca85e2f..557a1a3 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@types/node": "16.9", - "ava": "^3.15.0", + "ava": "^5.3.1", "c8": "^8.0.1", "esmock": "^2.3.8", "xo": "^0.56.0" @@ -66,8 +66,8 @@ }, "ava": { "nodeArguments": [ - "--loader=esmock", - "--no-warnings=ExperimentalWarning" + "--loader=esmock", + "--no-warnings=ExperimentalWarning" ] } } diff --git a/test/format.js b/test/format.js index 7b423aa..c954f3e 100644 --- a/test/format.js +++ b/test/format.js @@ -388,7 +388,7 @@ test('formats circular references', t => { ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], ]) { test(plain, value, tag); - test(withProperties, valueForProps || [...value], tag); + test(withProperties, valueForProps || value.slice(), tag); // eslint-disable-line unicorn/prefer-spread } } diff --git a/test/serialization-fixtures.js b/test/serialization-fixtures.js index b18c970..df1d7b0 100644 --- a/test/serialization-fixtures.js +++ b/test/serialization-fixtures.js @@ -1,9 +1,10 @@ import test from 'ava'; -import {compareDescriptors, deserialize, describe} from '../index.js'; +import {compareDescriptors, deserialize, describe, diff} from '../index.js'; import {serialization, tree} from './fixtures/pointerSerialization.js'; test('pointer serialization equals the same tree', t => { + t.log(diff(deserialize(serialization), describe(tree))); t.true(compareDescriptors(deserialize(serialization), describe(tree))); }); diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index 3f106d7..1d04554 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -35,26 +35,35 @@ const useDeserialized = (t, value, options) => { const buffer = serialize(original); const deserialized = deserialize(buffer, options); + t.true( compareDescriptors(deserialized, original), - 'the deserialized descriptor equals the original'); + 'the deserialized descriptor equals the original', + ); + t.is( formatDescriptor(deserialized), formatDescriptor(original), - 'the deserialized descriptor is formatted like the original'); + 'the deserialized descriptor is formatted like the original', + ); const redeserialized = deserialize(serialize(deserialized), options); + t.true( compareDescriptors(redeserialized, original), - 'after serializing and deserializing it again, the deserialized descriptor equals the original'); + 'after serializing and deserializing it again, the deserialized descriptor equals the original', + ); + t.is( formatDescriptor(redeserialized), formatDescriptor(original), - 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original'); + 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original', + ); t.true( compareDescriptors(redeserialized, deserialized), - 'deserialized descriptors equal each other'); + 'deserialized descriptors equal each other', + ); }; useDeserialized.title = (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original`; diff --git a/test/snapshots/diff.js.md b/test/snapshots/diff.js.md index 8df31a4..08d7feb 100644 --- a/test/snapshots/diff.js.md +++ b/test/snapshots/diff.js.md @@ -25,7 +25,7 @@ Generated by [AVA](https://avajs.dev). `%diffGutters.actual#- %%null.open%null%null.close%␊ %diffGutters.expected#+ %%boolean.open%true%boolean.close%` -## diffs primitives: null versus +## diffs primitives: null versus > Snapshot 1 diff --git a/test/snapshots/diff.js.snap b/test/snapshots/diff.js.snap index 42c8b924281743acd3975b6b98968517d67c6355..e03a942737c5fbb1ef85bf1f34729b197367a297 100644 GIT binary patch literal 4882 zcmV+t6YcClRzVsM|XQpPakDl(m?w-BfMUc0VMC1{IMhSAk3qe98YKZamK|@S@d=LpA2#Gm}i3Vfh zBN|^=Jv}|s|L*GQs_vS8%oJa^o$jjo*Z=XWUse69`pH&ZHygLuU)gyAIhv!RmCa49 z)v}c(OKWS6wv6oEiqX+^Wf@s^$5uK<6SXu0H8tB%m+T{^W8e8?v#C1jfqSMVPMdK5 ztF50nv$j0rR&-6rad5#owc&JBeR@`znQ?2IGnbIj{g?M=LpNIt0mY z1(LUiC%M~vjNtF53LcgDiJ;7r4^9Xb+IB3>Se(T&;3__kV|@z4-#@&8kp?cx`u! z?X}d#Ey$U^wf}3kwEy#M{r+r93I-$EhZWF=qhi5HTl~1;_|ahae9;|Hu>iqWvyE;GF#W*3_45H_37(S`0q~UH_EfR*7mTCH0tg9A5jgJF0 zKEUCX`?`ai5H(VUSGUYu6Y0o7*ZPlVaIfN?Q$}E_J(5Jw3>#U_Km@GKxaZ6wuv?aZ zli1x18crUpy#tu`zZ?;=w+nk>@Fsw$vk^$8qYVv=(`xc!Pm^_X1vLZuRE}%T5e2O{ zmWqGHO30iinfoQ;-LOU1HI&(6+L3%CK%)7)yH z*lq^)Tvyi^q#e|*ws8B?7pL}tb3Grh@!L95+(s0y!GOW<@(q4EF!)=s^NOM|EGGo> z)p9dX%cp8-)q;-UH+_K!PoO9PO?hQ3(v#unFNLI@O1&~`q$kPq#p9l@wmZ6`kv;W` zzDa%sO!DI-lk}^c!=Y|D(>F8wYr`}g%hYesaGh4~@u>&zk9izx!GNnJnWOwVj}-fK*`wB1x55d4cv~8;he4IRi!5 z0?AI96E4KKM(rEGH6DuRA|vh^VW`6477&C5ahPIwEo}_fP5?taGWv#!4Hg0k37bj; z+@?3x8Zgx@qi-r2G2p_%AgF~czy)j41kvFutWZG%Seyx70w(y`n42KW$Wl7np7tcL z?Zc;um?rqPP3}k7KFQv|Y|*m1PtVHyx)~15t%5#N&j7tv8p(rCNTc9DBrje2wO|Vt}A{a;21;jmB(3lVIxBR$c~l8 zU+I3Dals%fOolQAo7yt67V(Qp!)!0P=@8E95^)drMS!a>#BP*u?sdDMntBJck7^lq zK%=6EHb5zc(KQ?P^ib-237$P&%|Y#$-bBR%y*cdLU-!(fT9&#Ru=c&awLuc%q!GWC zk*ET=2OrGf*#;AMXx)mhDSIvP-PxY15~7j(Z7h(_J=uxh#>&SEuoBKd zFF~k74{)dcLfUFimc% z)~c7|c9ZHUboz>!{hHzI+~W?-lz08w2yzk?kj2xY0)Y;R5P{8p2mS)g_j-JKW_5T; zQqOyg&GZ@DVyBG^heX<*1^P>*^9)kZ{a`V3Ix*LaQq zq11<}N~6M(@=`KL`lI{vz+@*lM)#skCRypIvr@X}{t8DAwM9Tp>{8+#)#_PfT6OtGI?KCg)!{Mh!+s2j-a^tQYexB380y~o$=4xrgB zrQP=y!WzY|2-Q9Y^tY>2`s2B4rz{Gc3~hK6odS@o&{7lYjNFBLUI7Y79?#|aQ%?ie z|LRnwU4LMiThMB+h-YZb6bN^j+1o<5nGq}S?0$G=tfPuswexwXc8mgcaBU`uZuJ&H zV<}e)g!!jOWr4M<3=Q0iIeDbY>aHT8n+okG#E)tf)xYF_lK+W`lvhBc{Cun;Mbbq{ z7e_U|eY*HQ0$sF`6H64E01x($!m4MHB$2+v+yTmNRaM!grHEARPlXovIflOSYhMyX zNf1TF$;%*4UL2b^k@Qf~!_kdypCG>1Cx~s$cJG}|*t^{Yz~G{y_a29x^EZUG!A}4U zURE*8dPoT7?AYEGp3O`zHg;$Z?O>G7iIHzJ;RFVuzGMI0?yawXs z*JBqik~>Q7IJ!|j_*7hoJJNP_)2IIxy@X#<#z^1SO`rZ(GIf`hFVc6cW`O?RU7;N- z$rdGB%sX0M1<~@$v5FSS6(v_3@u z6|&5T#@z=+HMkBo~ZB`lYr9S2M+s;bXe)IWgBJaINiH+ zxQ&r`fX8?H?)?C8@6U7G1A3jhH2mdbEcI1}V+9qdT>g;+KkgUeJZc)o5T?ds3uWFB zWokaQ5bwfe_uG9EcP-U`t0dU0C-V5`dunoJb6CwjI+nkGvo}4ku|*?xXQoAVFooer>x3I zaO6CytSrPwgr5LJ`1Ux=qvT1l(F7Ygn;JtL^Ji1aAa6-It~p1%Z7F(o>4gCM-jfe; z4jtAg*8pids$&P_n4O(Xc%LpK;|G#sT}Ke)37cw#uBXb!W5A(0=`U6A7ax_j^iZjz zJDS^s;x(r%t9l37ie@NYc~Y+B3h*^8Qz~)Lg_5T;eR1coeJyAD=Kd46&bcPik%O-F zbqthhVzrt24H|CG>ODU7;QcX=p$WoudrxWLnYkyLVdJuco&-ZAYfl1olX^moi*7-5 z44cZ=>>A+_Y;4d)WHj9lippi5`Vw%!+Y=WHn5kN3y8#thi7Lu$%RqavjZt8C~`;@4#-H&!;i{25S1G-y=uP~`X~#tW1ALc|LNT;VvA=zlhH zNZzLb@B0kLlrzJPUD8oU+EM9Hd0C>XdaG1%QErmA|37Seqgy|n24 z4~X7B6&St4UKE#WYSmm*Fy$PG2e#SUcxm*CvH=r zWrKW>We5k$#)Vwum}$zU(jbiGr&6($C2M3};LSw`X&hd1hx;qCkm2+~laMd}JP5xN z!nRMl4JKUKGYI9Yaaafl<%DKI(iP|3RxD>{xVClp6toxnl#ooCA*zTiB~IAgvwsDi z`$nd_XQk(g^4u(v7IVv|w7n?Xmze?y8Lx$5*PFn9UlWF1>CRxJnb>AXmd+rgH|g=D zbmt+YhxAFb@V@cfz^(OiZ{1lDGew)K183P+zzivA=>>Nu)6&a`B5SH8iTsp2I-F8i z;__1<)E+Hh6HbQO2!tB7x5C!sL*G4@!ztA)$l}gEKJhQ*-?RWp`VU27^B zyHWI<;DJX0nBO~!z{aUPhk*5KvUc12IRovDBD@tvSY|EtA- z5O0UN%QxPO+jcGNn%%l%c7CfezjgPv9lN)0RrcR>W$-;}*u``@-s42bx-Ffo;`0{h zi`A*qDCnM~dy7`cvP_HQG)IBc9GZ-Cnr;PihT86__bT`A;IFcwe3RPi&(*!(NiX<1?mrsX!wqZrvtTq6EU$|t+2!q-rR|wzQ8(+VP8csc zL7UVTV~0zx0#Cqey8rfn${^gzCQmx=C2vSHJC4%8{)4%c3o22Ge*?VerxOWr3~e%f z#mx2H-=mL*GsJPJ;~Y;N^^T@H?o9}tdP7%jn?wt0>wp^mo}>omeKi|l?Kf3xbzfL< zd)$jbD6jby5mph2OKlY8u~q?{+(L`Emgo(a2mTCn^}ASIc@@mrX2)vuAoY?ie82}D zcwW+fzon~-b`NsFPf0u80vcQ-waC3N9dVKy(c)Drf)+RO&?>n_%6*LC>qo8h%rEA2 z(r}VY+df3NS*0Xg;5{`F*cdt8-q<>t5U*s-v4VHa=;i?_GZkX005+pWUQ2G2_BUq zMVA=01Y05BP{H6qwby|M{Wf;xhm9))O@%c^j;@66({ABRwk79PLs-bb$i_Q(B_XS* zsx#hE>MvrPPXb%_&JcG*SMmG7Y0G^+Gd%%39t z*zcJhmYxON>?7clkC*q3cL?+U(A^y3?(slDwGwqf1Y{+y zT!G~fT#2CTvLdiiKs-?t1b#L@a`}UNf`B5fAo_Q@k}y5fS4~&X^vv{r`##C*sp{%? z)vJ21UNveAKtDiqc=CzC8y8n7-)*;{@5hOG zbE7%z*=PvM;~-Qt1)y<v`>E^NcmKY9G>2{00>X;c5I$(j{&LvG;fY&* z{$lU)uMXXF`O#d0!+z2ZfF^IA%dI)OocyI(dFKh+-cD=6VV8G+@amlqhTa9?;@uD| z_d+<;8N!=gAdKw+fldaX)z;q5#jCUC*(-8g*2ybZ#&Fmzy&(LU0^w2`gjE>;bUZNG zvFCrA&uy{)+I`KLoYOHJmdJ!q+8;vY{SZpC0O&-t`P0fB-#jp|YD(jj?iEJ~4m&g( zfV+q6ykMKt!P=!XG41Mc%1m(Bi8%n=+w7^!_BpLKPp+((Hp|>2jo`4u9|oZFxsp#d zt$X-N`vvEBj9K%{1cJjR4`ZL)C>Xl3)73c#r{DWZ?ASx|2@boRg`O=t?|JQ|KJR2# z-W+)8V7G1rhaEZ`fV98Pb6i+kGjzzb+?5ku^Do74*m)x$d^8fmu2B%od2EZzCvzI_ zTJ_tK*D7b4u0=mYaM-U{=s))7`(wvm*!JiB(bHxep=U*LSo>oTnvVxyz}_vdZlBbp zZPwy{9 zq^&0oBwily`PR&FU6{qcCphdB3V>1jvd=cn>hi<5)~1ek{-wwD7!F%f1YwyK!fHE& ze41^s-+m_J;){>xq?CQKW^Dg$1cyDz!i4WWJicmF>9=u%ADQr%Bma1o;IM}n04C)w z*te`}o76F5uYdl+noiFX9QGkM0OY01ldAe$xSm$?{IA^(UYkyE*yc|FVC&fNo$6ht z*(KYX>}q*@xILD`E-Z!6Vitr?=0GU_BLwD20374GBvCtyZmzSP|1Nd$y{!oj`!fs9 zGdH(gPs`ug=)$7T?XosJO>kKEJoan*#x=WQuQt!F&g;=={@S@Q9QNs_AZ&aF!scfo zOj!cJ6F1h4+@701=DB01PPh0&+u~Rb+jc1g^9vA?D#7cYyM3OGuKIA%u!8-WXJa_*p4TBzZ$kL=pAg>O z$$sH`*)=;q-)LFAb{aG2`-&q`9Cq@*AhdrMfS30;(^n3(o;JB(y2)~);ESV z%G}s%+q^~`w(JaqpUy#Od=bK%S0D`j5yIRXtkzdN@btL1myh3Xf4sGgR)#Yz3p`&x?I|&Z^?60isevpu}*?e;JeLGW+Z>jkABLs(S^cw&N z##I)7ytL!FmZq-zhvkoMAEgEpXkNbyZTNd=35W``6G>5Rh1%!`UL)g@g0EedyK0fRp?`E6= zEx%vsocneZhaK4wLfl;hIDYWC|Fr2;@VF&yVbw>!O^Aiql6zR~zdAFqqWbF@FRl4> zaDLxK&0{!h*LVo+x zuikuDi)lp57oUSzTMq)9e`EcO@*OSGH#Ny$m^*IY0Ej)y!qwNiu6w%tG=F2f8);KU0%l zyGX0`jVKPAmkJ@i4*{Y<95>?=v7mL-Enq6NS}YH_8HS==$;D)0q19285Fc+cISZyy zW+vIpIO$|(G3792TZ?iX3=eO%IbD<~z8+Wmvuv6)Pp6oKS*G9dx+cwxo3te)#hcj9 z3%IUew@H0c9rXysla76l6z%mU#(&}(g zG;{kS3&@$+KGLIa8R=sG@7a(lVHsRM9$MfL|7Ev7k#ZE)eqaMlNDKR>gr4fedQ)^j z#9ELX;@tBQNghem@Q(X2zgr0f^laq8ETtR@b=3^Y=Nn2ZtF)JbsI<0v#w7efp}N`{ z$X(k+rF0-NLbb$ryifFH@&-guuW<^tj9x1qQ;EA&x?g`KT-dS*D!j)Sv{rb8QF(An zxaR=rzE#!_Rq9^WDr_;${+ebywXwh76P4!_5zvWB^_K)u1QpIXGi6PkkK8p-1dH6w zm7Q}GPbI3^WlRD(odje=E`lckyvo>Fl``@KpuH;H(q;G2Fkq zyL$JiN7sF^PzTW4n`jD?`9;q}GNvwBZTS(1h`;Y@X$U(tNvxJ!6ic*1k}ey=4SXyK z*FFgYO<6QemP!1qz9XB}#aB*Nf;b%S113s{qv9@jG^i%TXb@7H5+SvRfO7|d$INK) zH2|^$<-tgOI#A+NlpVK+bip>X&=YCG%gds_1A~GD+X%T8C=&5!B2pznz)A2Jh!Xpv zNMq3_F&=-Gg+G5pRm0a9`)~+{O;yRE>EX{IsYxHn*m+tm;U$qldF8fCn2wkxCrQe` z7vYpwGi&ISr7y(c@bl|gDnER0w#W;CVn*s!YU-GaP8)3;)=;3Q-%B|77PI^eY zzJ)HL(BBg()b{z>A{zZ;{aDzrOb!pCV)8-tX3VtNIP_yjM{uc7MAF5!GHkVz)xTa=2dg^$lC zELdvfRa#C}ZU$hrj)~$cQh~6CR5(g1t=P&?c4Z-I&tB4$_aZ)&RKGfrkM9i78Q}!O z&?3P)eNpm)cyL8Ol$2_rB*8{Bi&Hesm!HLnmgu3D?WhSx@$t1&shto{cy-!lh7|QQ+dEx9+Daag}8oE^0tplcj z?ClZGw}b-O4R6ix*03wdfrwHP!?iP9yNFTkeR2uQkPsf}$B%G$-^Y@QE;1B}eLs|L zcwZEQ;7DaVoi>Ve;3*{m`+^-aw3}+c$nA7{H@1*Amvn1HCZCGIcA!dr{!|`Q(*0(; z%;6<2HWR2oCc=>_U7V@X<)JDb$AtU#mpEw0U4>>ML2hPejaJ4?6>flv;R+<&DkHDI z6RQ$)cUaZAWuCbs#R%gwmGGxU`I#i%WG71pQN_&EgfmZWGKu;N2x4cJ8LZN&EIz(4 zxLzuMFjOe#{8=ixDesr6${9oj){r;6RUwqBAi5Ysu(DbwmGsdpy0adk zl60^+h3stTY~kV^MmAOweh6$$U<6jsFIHNaDIhYbu*9vl{=Z1J!0qrUt2llV%2!)x zJ*lrcbx|VeM*=g6N=tgS+hU<4c_?0nEYIp-`r)ocrbZfl2gLgz9790lajOV(ln}`? zQM6E;#qBUNR;R-&`@}S)4lneBdV)1Pa*%e93UYij=42Jjc`8YbyQ&P6j3gU zqQ%)2HB#-UD|)?XBef2bqPL4S!lHb4M4&(*?HNS8gxm~_*u`b2h zrKV(Lr1wkDL~WPRC%vz-;Uk6Hi$t3i*_;LSXA&Ob{#}n!z07}0bV~(suQ2Fdt-#d@ zinn8A1zY&YfW#NgRPsd%_b%l#svNq?#SE{gsVwo`!A{^b0-@m^2$hw=ttw>Dh;16N zO)X=avcmg{irLEuS85fmls~v2ewZh8oDL)p{RuILQ(#-bYg0ff+fKGIZx9acvT}va zk@Hv%A|VE(_&8R?2YgyboH!T(K@|D876}2t2sl2c$8Gx1SR_XJUV7B4kq`_w(U;juo82~&PRP%x``1J)>WQ>fgn4|3JR69wj*pI+ z=Dk~}Zm8b9X+B&WM=sU(p+uZ^V~eUGZDX>(7o@Y|twSX*^kqAym-@HcsIImAUghCn ztVHFeb9TZ~GM$S~hB!y=C4gEFT~OAL67E8bz5@Cd5;T@`4{^AdcuEwA-(9DjhNCYm z*wuj8)j zOoM2RPkmqSGSyDW92GUyjJY54yOsD{Mca2iWr~AwB2F1eMYAY1C8=<#Ctji=>ds5p zG7NoGO{)sHnpNL3Dh=bVG>mJFofi(p3v_#Y^rUMTu9j{h8kY~*i+)YpG&Y& zoN2NHusU2U|8Eb#Bf{y>_8-yzs8WoH(cXF;`gX~B-ivFJ!G0dQ029=pXzm7l{rZBLk5O1(xHNpiG*s4z$ zCd)8chUXS^{^-ebQ(&r|LNQg`Xbfv*SSvkQE5knN&OWKKNQttmN%gz!ew=)Wq>X#S zl%WwQSey5Tfs-|GI@rJ$&#J>41i+V~=53+^o}%WR*W*Wu+9Bjh5<$D$;%Ug6IsDyCHO0JsgO!#Nv#^6Y!*2}qD9p$RT;JT z6SfsOkT@<^RDoP}l$UZ+OM_1U5_M-wv!lks%ekLMjI7nNsO+GC~Q*Lg6wk zzYUSsN#Z67EpNaGnuc4@RBkton1(ggw7^=F>tO1q6G#2uupRHcR;=%pn#Opl(kU=? z|Gn!7>MDXGUj|W&%8atbI@CrH@YVq682GES4KWElF)3H&W+^-EsA3=1%MNLMgQYq6 zxAiRx3x;U4`>P8Mof19gMpH#BeUe>HH*K!d@m`$S;6H$>+^gaD78_aQs#~P-P_k}= q`WF@ny^;61yAg7wMpH$DOEDGL3Is8Q-xyBymH!{VsFF!0JOKbkIi8yU diff --git a/test/snapshots/format.js.md b/test/snapshots/format.js.md index a5dc13f..c0f726e 100644 --- a/test/snapshots/format.js.md +++ b/test/snapshots/format.js.md @@ -28,7 +28,7 @@ Generated by [AVA](https://avajs.dev). '%boolean.open%true%boolean.close%' -## formats primitive: +## formats primitive: > Snapshot 1 diff --git a/test/snapshots/format.js.snap b/test/snapshots/format.js.snap index 41ff492056c066aa92ffe204567e41f042716d4d..108457c5e0e2fa15db926663445d843a76df2bff 100644 GIT binary patch literal 3438 zcmV-!4UzIeRzV~Pki7@B@iHlgai`&1w8M} zotd4pbMCx$*Y?g%KQ!K%d+s^scV73Nc|EC>Wwmlo|3U33F(gAK>orwth=wjSHK`#P z(i%A_C@oo*bVY3HE2^Qt{iIqI4RP_%#Mm=q=6|^zW1q_HDVU?C)h1D_zu3=;tm>p- zPu<>&%-vF|q$Vk(>Su5qFgRRrhcYhiPtOU+Z#TlPCdxYT^O^y?CJSX%m5Hb@P8N-O z2=Kt*GPD-L;V9s60CF%%a0Z&6fq(8d!QAHyx}ix*eOjiNSo7zL1?QN>&iTPOf#KF6 zI^Jf#hC!&Rei3d05iW&_KqrYVMSDLY#*$Df2}SdNlYVi&48*w>D$bH;wit39z~Na^ z%A&SZ7Vj4k(f;5SZTvT54ueKZHYAISZit$ZUycY^MO6$XETvjFqbM(a2tfXIRNvbykb6X~&)c3vGKeM`YC_E&YLq(`7V~pTcvzIB`ens%vZ~_z4qZN%(AmNA zAol{8y~LZoy_e_}u}O5gvJ)#6RjbnKAsDJ)tdNFhjs6Z}0+-Pr`P@?RG&^w%ocJg` zK}-J5(>^YfiMUMixJ=?)mJ@MV=5bjDTwZgy=yZCSthQ8x{*V+wRY=J!xdN-fy09)8 zD<*S+ZoWiXkbQzY#RMrX6^ld`%S2wKqgrxRC=-G4tTF<)lXzy?!g`s}v}_thHN14T z?57>s%VOo8A<=EEDY&&*NF@3jK$3~#axqW}4Bll1?=n~At~d}W?v18Q1hxDXQZbNq zGT3&HKc6eGkya!uXjE}xU+|ppXA?|t)Y=Szo zi#3`-@>3>PbDNToE6sw*xH=G6LmUhqx=G-LZg8grh3E#U@-I+J~d+3Zds!r~PrXSTZ=X1h&KC+^y_thQ+m z3GXd_2cY;h7sU$Igo(PqI)C57?ifJ4nhs24;rS$9jVu3DS7cq#<-55mOX%M~AOFMJco|DgZ!`+5|~@yA*i1INF+4-zK+^IY)} z>Aw!7-{`;eF@-Ji%7{;MLQ9pwpy?{5izS^P_ra?A;)_ukAMbm^RI4{bGdEhf!0h^J4`8;4{dUB{BpoeE^Za`HMyea5ZUceQq26wO%QXja?Q-Ww8pGSZQ=J$b{+%Qd&TOXUoS8N)gPzhFM>Gz%y|Febi3Sa=Szm1DE1}8uvi%SOB%7=tmsYpk=BfECH*Dv zvnR;jF|MC&QR3vRW`?&q1>4-M^ExpwyZZJ5{+pZ&WQVG%Pw ze|^ib+-tycGkvsN+Lpl)lcI@pyrg&qnBY_&Ot3|sJm91l%N{2jd(>LWy$$;=30*K& zM1$`0h+uAN%+5zuSP|E(-Jf%F9%7+?01N#wd8%)Q>Kk$OuOHG#C78qswc(f%l2Tmh~AFBK>e9Y3wBEv;fpeAIGuc!CLbwBQ`B z$zol%Hx*I?9%Xtt;vEYRFJAru_W_PyMDov@q<*0tbNxRs0KAiL|0aLOjYLINHX3Tn zN=X$1cO$Tn%1H%h=rj}NhGT6m+@S1VD;Nt~u*aqv<9!*BCar znz>It*;g8grl}ed*8c?d`O{dz8tC!V8yih>!933smR=W;&GE~+XQGIq#y|NKE8!X5w59~xqeZ#x)6a7{4S zs=TTa-MZ6XQYvzb?pQ4ltR=d8icU~r4;0YlE|sfQ!58dzfJv_SO|l?Hv<9_ZpdHx4 zThunLgF=u$Q(!ja4;%KNIfNQCVnM9{1Ksc&C{do-nmx-lH&nCp=$G1%bi^FK&5N%n zUt^@vcK{*2bEI3QINr1PXW%@)Mec!%E$_B`pr&IvRZ=Jg5=i6V(W&u;@qh&*w^7b- ziEdF7Ao2q=g82-7e6_60l(DI{3XXVy^zG>*cjH=-w2IYX&`6DFM5$mg`7THy>s%O} z$#^(A=ks^Y*?-;b;i;Rm<{cdits0dZxjW%G5Ig@vu6lat<7`I^TD+3$ZbDaV2vPM`YpK4uBQZsx%)tt z9pPtg(naR+v-mxb6JG=&{dpv$1EM)}uiRlBVZ)r|h7{7J--5x>_zFK7yJ}PwSw_wCa-yGMES7Uz&Lh2Dx zW3!MNHM;a$aER)n`!?2#vML%c&+&G(p9FzCh6J*Af-IOvg)aRT46ctyvG|EsBYy%y z>)TmqWptwwTEki=kIna3C+!KcU>+5^^jk1aowVJ5Aaybetr4S3zXgY=PP!k5x~v$p z$9PrpSrE$qMLMk=@+^=?g)aRT46czSf9%AokRO1sdJn0PSy+u8UHUCJr1g>CZH-hP zvxd-!(WT#l(d%QPPHUw4n1$7d(WT#lLsTDEJu%L`#kT7sFnD=9o`vy9(WT#l!PRlf z7di2YoZnmxe^}E)pM~LZCn>jiA>dE;TVRo)Tlg*8D-oXxiocC|r(!K>= z)~m!7R#K=0QZ;Y?8&d`+i5>)y#(RDIZUFbkkk5$p1a};yx8<9|+pkc(*3EAwD5ck} zfr25{1*zu!ZUX!Efs|*@3YURzx#(1b$;>Q3si!yK?i=<*UW1oeyp5BY=8ehrs@72&J(; Ql46qlABJW_8EB>e03-&9Bme*a literal 4650 zcmV+_64mWNRzViss_4bV%pE1eZ|qw6ZV#7+(Ls_BC`xgS{xWgkQ1piiVU8Xl-Y3|(A+XY14Yp*#FqwJOd zbg*`N`=`$PEmqf_7)Ep|PlFhJg+j+=ebe1KOs|}jI^}QLqVl;Aqh5LdbYA?)p&Q>L z)aYDpywRZbIuN7pP%v)ie&j`(<^0o~ir;K8zxoHnXuH+`nDje5^Qf)=QTv={touuE znnH})w*i2WV0gkLn={_V$)r!#p>;1IMu)dWF`wKnchj|4uybC{I$kNKImBoh3RX^| zTNoa`o$+C0Wb)Cy>xV#$=7?ezTx@l4d2&vw&fWu-klhMm)TJGYIrlMj<$z8Rr5#iI z^bwrD2{D?3g0=5lz7HeaH0|w^z^JUIsMaF1WqSa+W!~*maH6DNs^HnD?jwu3Hp3`S z5;_}*12hzemL0?)AB7%|Lk6%uvgcl_Y+mU1>*n7fMu&6+!0~OxhoK8CO}5<{dpPAf zvopl#FDN)Y`29#ptM_?(qTIggZk6H;G5W7g060%K)cdX@Ex%vJ*-KM;9`S(~{mTe| zJ^^VD@-!d zUeGR0y1RU(0mSH8V*vVDUETInZ-uT)`hj=l6Jq@#M#q={(0|7g{j;lH8+CrT&)Dpb zrKrb>&~0V_4DdUaBG(HX_WrWreB%vlhlW_D=Q8}QnV ziru^+b#88Hzh3z*Ax3Q+0SL11T{JI#+O@PD!_T*5UTqICddmsL95Tp>&JWtTEDKED zwvDL?lzj{NAK1Lz>x?hN6 zz}=+z0(XHiFmr$yecKlRuKuJ&-4^I%yA7J36wyo15n|M`9{|b8LvA-qi*N5&W~wvh zjZr1UsPjP72LnTTHJxR!;x5s7!L% zcjNU?Fu~|;J z@x3_&ci|*qka?SF5Tgmc04!f^pQs-*f4oKWh`og%bqd62-Y5W8B|AB;IGCT1Z-1wB zSf}SmPl-@{KLD~gu^pKC4~W7{*1BQK#}0=WHSz~wecs`T9q2PH=n*qk9P{4Z24d8D z3;-M9Mw;XEGg15Zuecwfe|j0jXd0SsermICm%jT6{jv^rvwJv?7zi=CY#abvMn`2< z_>baD-u=`q;C-795TiYU0od9sYv$qn;;W-7M;zDRv2q~|qbx~Sgu?cjTUME^xswpT z-pRYqR^$t}sJdXFs9iyX;= z7_|ulVE4b%;N@Xq@$B)9rE+JoH{A5BX{4dCHo&ij8>ws@4Dp* zdr#M4wvoFoX8QMD3o+U@5`cq{X*TVzJlF3YIY%#hU&@CVbrZ$RFjy@-ng0BQPu4KU zbJuP_jNW1c@SEqeSYAoW#$(~HGUH4SU4j^W#6dAz4U1R#oJy$_w0`ybfg;pW5$YQQ zz{z343=r+xdegmYF_m8X21AU_L*dU*_}GZP^vZRQ@quL)F`*Entzwb(ZDHf%=;~3F zU+zEaX7;9M5TiSVX#OU8pZ0#@@BKWt)Iaaa;v|UChjA$8SayX=_Cxn6BeHe34X{`a zG1~ci)RP~1>6aYPd1;XJ*!s%rSC?rR?I8*7D4eJ3KO6V{(A*Hqt-Z7IM(?L#G(ZyA zC|sPh^Ms%syp?Ew+;Y3gP&5~a(DZl!uDqG^-`otdi>ABT>*0t$_dtwpO+s2fp&N78 zh2!gp$2KPh#PmN5FP68=Wv;kt_7I+O&Lk8*L!)ywrXf*4&g8%cH9 z)V+a8!!O)%swgX^_1X_H`f?7^fhjKR|9j@U_2s*kzx=1tl!4bjH z@erdwq43(u(sIS3+v5XDe-3htO8*&Rv>1gqS)ZJr(thh-w!ZBTE6d!rK#Vq7fb6cR zw_2Ml_hz}ebI+Mh_dz{WggT?}Y0W{GE{m;y80OW|aIN9LQLRPj`NfD1G{@E|YzEpw zGe#IY%9|^+OAuSM6wrqi}6iQpvgux4&N`#|K zggm}D>p(VF*vFmEXC+F-iA$j~IBbEq4jz0~_%uRjF_EE5r!$0!F+>EWvI|QT5(05v z5kxpEGK>`=8(o#1mhM}iQ-2AHS||{*gaSJO5yRrMP?xr_wY3%DkvtwFhL3XL3lpow z_N6lr1)t50vg5G11TMyc`5D8dhOzine~XKeqQH=d0_Ba(npz=Z0EJetg+%n17Es8SB6mpgC6!Yc zD@j#3#l|JnlbmPA20+t#uh=UH5Zd z)hm)Btt335Y)wWJQ9~1Al&cA!h$0eV>;$|xez=62_IS>hju11=o>2uya#&Fk8Aq|B zrO_{Q*4j)Bv2la!joon~GAEbx8Wb5SEZ2t#Aa2u=}3H ziIYr+j;_63Z5>=}ogC;+4t*V6`u2372aXwBJzY(0ZIEF~fiL=yLGbyg?Oay0q_v(r z-cS)#J))|4V(2pqEvy-1kjAQ>{0k#3x+&mCG$9bMq6k%aGKLTcKj%?z%+Z64$T)7e zkj>-TiL)KUl2pJ`f|DhvV%F!VFT53X18KOXj`NM`0N9-o$BiJ+f{KU`m-hM3Y7r#6 zDkjpVv4i}@7}+G^ixVrSWu(gM`PI6BQd`-z>IS40qf+cBMihq^#^Q*J^1{DYLAB02 zNS3*1;8W);mGP5BGEaE06pBwkpan++i=P-E#b^sRhLllHl1zb#U-Mex25C)`RI6$A zc|}1*>w1=TPi{x0l zGW$i*teBywtm?v~4;V-%A&|2nCdWFe=LX8{O!6D3lwmeOwu|`jdC_bE`C3P11Hy_S zNQ@5SNvx9q{JS;kHQlOkk}*AiWEB=bD7Pul5C*aQ?U(vF7ofubq`IFFzP83G=_C)D z0#V6Tx$^aNL#&jQ(bIIgXap1dFTW*1MQUoP&@bM|?(W(3ipH2+qlnxXTdcA%_Eo7=Z851< zWsoc#Yqgi`=oBre>!m*ADqBf57nRJ8u#o($P1)T^Y(qO_;^4VUfqe)_j&waaJeII` zPpvN3C_43*AO&6C1=&0t$siK_CjOIT+$sgOrp7z zJ!@#7GnabatF7tap|-kIwSE64%uuHEYn4#(Yn4zbu@+KYlK*1|Kwq;cI2d&srn&M9 zb7(BJbEx2I32hjO!R!$i8L4>pT>km5?0X;O&VSWkv2RPiN9YJ0HGPTFOVM$xIi1Su?oQps+H*7`s#lEo3I zbfPw;4sOuY+g_5Q%XbZOX-Cez1m!Q=m@2+FDV26ejZLD^9tC&i6>9I>sy|?6^990s z+3FK7g;dP?o7wBF#lAxQ>~+$vY8SCuI_-?F-Umo4<$0GG%wa`WHBoDmYYLtEOR%wx zP?#t?Kx=yuTa|m*WbQDuJ6;+{r~VRbY$}50M7CrZZ}YXeR~`~A&h^%f2w$1qIIUEfpqFGK??eMgsfK-k>3JJ z4pBs26co8ak-z^UcB7*DbNWW%Q-$n~oz`2b=FzFY1S#klGS|W0T7f4k0LqzXgl&c$Q%NxBP9o4p+zPNDvdYv{3VnytL9HTt=rzl2d0Z!vMO z-WQ%I5f|CHm)`VuNdn?#{MO?h|Ev=fnr(W$=#DX9J~a$j(g!}a%`w;sL2k#Rxk z_m3Y)^u`dDkQKxx;wUPX*f(>)v^{pCM g<~2LwqIOK8{UnKo(W$=#8-oS)|LYRcQj(Ye0LNt?GXMYp diff --git a/test/snapshots/max-depth.js.snap b/test/snapshots/max-depth.js.snap index b107df412a35f7f4b7f80a2daedefa6efe42037c..f6f700f47399f4cfa40a283fe6251657ea497850 100644 GIT binary patch literal 605 zcmV-j0;2svRzVmCbGwF%W>$AcWKl;sKC`Q$TH$WQC||2_!^|!~uc$k%}sW zoa}6~C9$`*qb!Xg@pIud%7GJaz}xU7%sQK{z1eIEd+^VAW<2(Mv%ZM>BRTk}zx_ZH zn-QjWBB{pQ+`R`1b%FzrNzP#}|_QD?B+&GZ%K*cT}Xp6$QD>*EK_hbg65TMa_H(XD5uKs0K|ScmdBQ zd;|$sMi;1lU84HiL-kh^ats_?OTbox1O*i<*j^P}sJgKYyB7E6BD?}|Eyn){@_(UR z4|5&P8-T7vx(4bMtk-~jMYJp7uEDz&aBxU(Q#TP7UIxA0?HzX>*h*M1eDvK#cWCh6mpFrjY1TL+eGG7 rOB-NOxYHrpvZXi2V7T(O9NqQ~dow#9C52^C(U0LTk1@uBzXkvR5iJ)D literal 536 zcmV+z0_XifRzV3!0`C)2L3ALk|ny5>2gY8&!;njMfbCU%w-3g!^p}Y$h3w@L7|#U0SNN*Qmvp& z1%L^sfIWi?k2E+k(GjDQBh*0LNwS6B*~P-5}|7^(7fasldR-8=XK(7f6-nr52VZ=2$5h>Tqcz^Nm2tYLSyJV-?nv z3r!WesCKI-C040Jj6@bKEUi#Sb0@AOgK#IBJD38PKz1WJ0wwcc^EK2^jBG<(rh!rz z83vD9l&pf5QSf9Fk}?SySp;7O!JR$uW)3V_182rS%NAHO1yNZ7ONPLi9q?oZNZQij aLQUrUpm+n?X$4XWlmq~i1EO~u1^@sWTkHM+ diff --git a/test/snapshots/pluginRegistry.js.snap b/test/snapshots/pluginRegistry.js.snap index d321bb3613d40873557e6c97055a01df9bfd63ab..cbf0958103eb414a74b53646f43b3611a6adf74b 100644 GIT binary patch literal 446 zcmV;v0YUyjRzV>=i;!D7%`X4T{5xKAtax=c( zB<|BVm>-J>00000000ARQ9Vw>FckK4(zGDaHZ2QV5fdBg4GI-vL2Q+P$w}PSke|wS zq_z|6T%w$S1C+voD1)U`x>A)w%ct2I|Lj8O#lZ7*#(P0&4s22`Tp(_=trm zI$W@x(D8zJg=}03)XZ$1vl-BQH`C(r9UUKtufI;K$-qzfEHjC(W1KRXaH6`tOos7U&KNNd>G6H zV2x_9Wz-z;P%ItWkHYa#On+&-ELnDijDu*TBPODL?4azaM0iFuE<>hgHqQANS$gYf$$TZn8{zA((kLjM^484q z);3k@KfUN2=VUVS6B=2yn>jjf1&{&Ok(u;;t4w!Lt7&GNyxpA1lx^a!N=i=NJZDT$ zORa#1^+^H7E@I0Ub001(~ BxG4Yt diff --git a/test/snapshots/serialize-and-encode.js.snap b/test/snapshots/serialize-and-encode.js.snap index 262d793ed7ac1b7cbc3e6cc425036a80133bd891..0fb0d6b3427f6a2336562618d8dbaac86303b5b4 100644 GIT binary patch literal 202 zcmV;*05$(XRzV1|N$E00000000B6%smPMK@33QSwsXoZ;(>KW)^I0_7FCLSj;*RgX3mMQuu>~ z-ef(gj-9=){EFA_+r+!0K3-^K3C|0?oLWwhg)@o~Dg;3gWQiykA);n71Vy2c=o*Z; zBke-g1Dihk7=wj%GjJnUs)lY-d4Ss(K5bUt{Z##Iy97V~#kyc!@cyUG8_a{@+28;G E0I9H9E&u=k literal 130 zcmZ<^b5sbuq9pSa;?%09bMn28S>p63}C=~IROY#3U(D< zds_2<{qBj`>m%*GqomFsVPN_e5W{}t49}YcL$@$CM>l8I)+{|%g$}-TXM9hczo=n$ frDto9!4*eQ6DCfnMwV>ND|`%UrbdFxfCd8q6Vfg$ From 349e996454bd1b575a3c0227eb9acc451df0bd52 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Mon, 21 Aug 2023 10:45:09 -0500 Subject: [PATCH 06/13] update CI matrix, add `cross-env` for Node.js 20 loader support --- .github/workflows/ci.yml | 2 +- package.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d63a6ec..b865562 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [^10.18.0, ^12.14.0, ^14] + node-version: [^16.9, 18, 20] steps: - uses: actions/checkout@v1 with: diff --git a/package.json b/package.json index 557a1a3..f51c925 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "node": ">=16.9" }, "scripts": { - "test": "xo && c8 ava" + "test": "xo && c8 npm run ava", + "ava": "cross-env NODE_OPTIONS='--loader=esmock --no-warnings=ExperimentalWarning' ava" }, "repository": { "type": "git", @@ -39,6 +40,7 @@ "@types/node": "16.9", "ava": "^5.3.1", "c8": "^8.0.1", + "cross-env": "^7.0.3", "esmock": "^2.3.8", "xo": "^0.56.0" }, From a7231f10c34819c45fcb026d0f65b7493f879fd2 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Mon, 21 Aug 2023 11:02:40 -0500 Subject: [PATCH 07/13] use native `flat(Infinity)` --- lib/encoder.js | 4 +--- lib/lodash/_baseFlatten.js | 38 ------------------------------------ lib/lodash/_isFlattenable.js | 20 ------------------- lib/lodash/array.default.js | 5 ----- lib/lodash/array.js | 2 -- lib/lodash/cloneDeep.js | 8 -------- lib/lodash/flattenDeep.js | 33 ------------------------------- lib/lodash/index.js | 10 +++++++++- lib/lodash/isLength.js | 9 --------- lib/lodash/merge.js | 8 -------- 10 files changed, 10 insertions(+), 127 deletions(-) delete mode 100644 lib/lodash/_baseFlatten.js delete mode 100644 lib/lodash/_isFlattenable.js delete mode 100644 lib/lodash/array.default.js delete mode 100644 lib/lodash/array.js delete mode 100644 lib/lodash/flattenDeep.js diff --git a/lib/encoder.js b/lib/encoder.js index 662f17b..a152fcf 100644 --- a/lib/encoder.js +++ b/lib/encoder.js @@ -1,7 +1,5 @@ import {Buffer} from 'node:buffer'; -import {flattenDeep} from './lodash/index.js'; - // Indexes are hexadecimal to make reading the binary output easier. const valueTypes = { zero: 0x00, @@ -237,7 +235,7 @@ function buildBuffer(numberOrArray) { return byte; } - const array = flattenDeep(numberOrArray); + const array = numberOrArray.flat(Number.POSITIVE_INFINITY); const buffers = Array.from({length: array.length}); let byteLength = 0; for (const [index, element] of array.entries()) { diff --git a/lib/lodash/_baseFlatten.js b/lib/lodash/_baseFlatten.js deleted file mode 100644 index b42dee6..0000000 --- a/lib/lodash/_baseFlatten.js +++ /dev/null @@ -1,38 +0,0 @@ -import arrayPush from './_arrayPush.js'; -import isFlattenable from './_isFlattenable.js'; - -/** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ -function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; -} - -export default baseFlatten; diff --git a/lib/lodash/_isFlattenable.js b/lib/lodash/_isFlattenable.js deleted file mode 100644 index 3bdef96..0000000 --- a/lib/lodash/_isFlattenable.js +++ /dev/null @@ -1,20 +0,0 @@ -import Symbol from './_Symbol.js'; -import isArguments from './isArguments.js'; -import isArray from './isArray.js'; - -/** Built-in value references. */ -var spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined; - -/** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ -function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); -} - -export default isFlattenable; diff --git a/lib/lodash/array.default.js b/lib/lodash/array.default.js deleted file mode 100644 index 9fa851b..0000000 --- a/lib/lodash/array.default.js +++ /dev/null @@ -1,5 +0,0 @@ -import flattenDeep from './flattenDeep.js'; - -export default { - flattenDeep -}; diff --git a/lib/lodash/array.js b/lib/lodash/array.js deleted file mode 100644 index 5d1c67c..0000000 --- a/lib/lodash/array.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default as flattenDeep } from './flattenDeep.js'; -export { default } from './array.default.js'; diff --git a/lib/lodash/cloneDeep.js b/lib/lodash/cloneDeep.js index 6c6932b..44d403d 100644 --- a/lib/lodash/cloneDeep.js +++ b/lib/lodash/cloneDeep.js @@ -1,11 +1,3 @@ -/** - * Lodash (Custom Build) - * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ import baseClone from './_baseClone.js'; /** Used to compose bitmasks for cloning. */ diff --git a/lib/lodash/flattenDeep.js b/lib/lodash/flattenDeep.js deleted file mode 100644 index 88f9e0f..0000000 --- a/lib/lodash/flattenDeep.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Lodash (Custom Build) - * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -import baseFlatten from './_baseFlatten.js'; - -/** Used as references for various `Number` constants. */ -var INFINITY = 1 / 0; - -/** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ -function flattenDeep(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, INFINITY) : []; -} - -export default flattenDeep; diff --git a/lib/lodash/index.js b/lib/lodash/index.js index 2a3d7c2..00411d2 100644 --- a/lib/lodash/index.js +++ b/lib/lodash/index.js @@ -1,4 +1,12 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" include="isLength,cloneDeep,merge" -o lib/lodash -p` + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + export {default as isLength} from './isLength.js'; -export {default as flattenDeep} from './flattenDeep.js'; export {default as cloneDeep} from './cloneDeep.js'; export {default as merge} from './merge.js'; diff --git a/lib/lodash/isLength.js b/lib/lodash/isLength.js index b4bf1d5..2acf24e 100644 --- a/lib/lodash/isLength.js +++ b/lib/lodash/isLength.js @@ -1,12 +1,3 @@ -/** - * Lodash (Custom Build) - * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - /** Used as references for various `Number` constants. */ var MAX_SAFE_INTEGER = 9007199254740991; diff --git a/lib/lodash/merge.js b/lib/lodash/merge.js index f56f822..9aab628 100644 --- a/lib/lodash/merge.js +++ b/lib/lodash/merge.js @@ -1,11 +1,3 @@ -/** - * Lodash (Custom Build) - * Build: `lodash modularize exports="es" include="isLength,flattenDeep,cloneDeep,merge" -o lodash.min.js -p` - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ import baseMerge from './_baseMerge.js'; import createAssigner from './_createAssigner.js'; From c9153bbb13b28ac9d0424ec6294da41aecc1096e Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Mon, 21 Aug 2023 11:29:09 -0500 Subject: [PATCH 08/13] use `test.macro` --- test/diff.js | 64 ++++++------ test/format.js | 191 ++++++++++++++++++----------------- test/serialize-and-encode.js | 75 +++++++------- 3 files changed, 167 insertions(+), 163 deletions(-) diff --git a/test/diff.js b/test/diff.js index 89d7864..95bc629 100644 --- a/test/diff.js +++ b/test/diff.js @@ -25,42 +25,44 @@ if (typeof BigInt === 'undefined') { ); } -{ - const diffsPrimitives = (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)); - diffsPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`; - for (const [lhs, rhs] of [ - [null, undefined], - [null, false], - [null, true], - [null, ''], - [null, 42], - [null, Symbol()], // eslint-disable-line symbol-description - [Symbol(), Symbol()], // eslint-disable-line symbol-description - [null, {}], - ]) { - test(diffsPrimitives, lhs, rhs); - } +const diffsPrimitives = test.macro({ + exec: (t, lhs, rhs) => t.snapshot(diff(lhs, rhs)), + title: (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`, +}); + +for (const [lhs, rhs] of [ + [null, undefined], + [null, false], + [null, true], + [null, ''], + [null, 42], + [null, Symbol()], // eslint-disable-line symbol-description + [Symbol(), Symbol()], // eslint-disable-line symbol-description + [null, {}], +]) { + test(diffsPrimitives, lhs, rhs); +} - if (typeof BigInt === 'function') { - test(diffsPrimitives, null, BigInt(42), 'null', '42n'); - } +if (typeof BigInt === 'function') { + test(diffsPrimitives, null, BigInt(42), 'null', '42n'); } -{ +const diffsBoxedPrimitives = test.macro({ // eslint-disable-next-line no-new-object - const diffsBoxedPrimitives = (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))); - diffsBoxedPrimitives.title = (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`; - for (const [lhs, rhs] of [ - [true, false], - [-42, 42], - ['foo', 'bar'], - ]) { - test(diffsBoxedPrimitives, lhs, rhs); - } + exec: (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))), + title: (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`, +}); - if (typeof BigInt === 'function') { - test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n'); - } +for (const [lhs, rhs] of [ + [true, false], + [-42, 42], + ['foo', 'bar'], +]) { + test(diffsBoxedPrimitives, lhs, rhs); +} + +if (typeof BigInt === 'function') { + test(diffsBoxedPrimitives, BigInt(-42), BigInt(42), '-42n', '42n'); } test('diffs boxed primitives with extra properties', t => { diff --git a/test/format.js b/test/format.js index c954f3e..8d20749 100644 --- a/test/format.js +++ b/test/format.js @@ -39,51 +39,51 @@ if (typeof BigInt === 'undefined') { ); } -{ - const formatsPrimitive = (t, value) => t.snapshot(format(value)); - formatsPrimitive.title = (valueRepresentation, value) => { +const formatsPrimitive = test.macro({ + exec: (t, value) => t.snapshot(format(value)), + title(valueRepresentation, value) { const string_ = Object.is(value, -0) ? '-0' : String(value).replaceAll('\r', '\\r').replaceAll('\n', '\\n'); return `formats primitive: ${valueRepresentation || string_}`; - }; - - for (const value of [ - null, - undefined, - false, - true, - '', - 'foo', - '\\ -- \' -- "', - 'foo\nbar\\baz\'"', - 'qux\r\nquux', - 'qux\rquux', - 42, - -42, - -0, - +0, - Number.POSITIVE_INFINITY, - Number.NEGATIVE_INFINITY, - Number.NaN, - Symbol(), // eslint-disable-line symbol-description - Symbol('foo'), - Symbol('foo\nbar'), - Symbol.for('bar'), - Symbol.for('bar\nbaz'), - Symbol.iterator, - ]) { - test(formatsPrimitive, value); - } + }, +}); + +for (const value of [ + null, + undefined, + false, + true, + '', + 'foo', + '\\ -- \' -- "', + 'foo\nbar\\baz\'"', + 'qux\r\nquux', + 'qux\rquux', + 42, + -42, + -0, + +0, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + Number.NaN, + Symbol(), // eslint-disable-line symbol-description + Symbol('foo'), + Symbol('foo\nbar'), + Symbol.for('bar'), + Symbol.for('bar\nbaz'), + Symbol.iterator, +]) { + test(formatsPrimitive, value); +} - if (typeof BigInt === 'function') { - test('42n', formatsPrimitive, BigInt(42)); - test('-42n', formatsPrimitive, BigInt(-42)); - } +if (typeof BigInt === 'function') { + test('42n', formatsPrimitive, BigInt(42)); + test('-42n', formatsPrimitive, BigInt(-42)); } -{ - const escapesQuote = (t, escapeQuote) => { +const escapesQuote = test.macro({ + exec(t, escapeQuote) { const testTheme = { string: { line: {open: '<', close: '>', escapeQuote}, @@ -92,13 +92,13 @@ if (typeof BigInt === 'undefined') { }; t.snapshot(_format(escapeQuote, {theme: testTheme})); t.snapshot(_format(escapeQuote + '\n', {theme: testTheme})); - }; + }, + title: (_, quote) => `escapes ${quote} according to theme`, +}); - escapesQuote.title = (_, quote) => `escapes ${quote} according to theme`; - test(escapesQuote, '\''); - test(escapesQuote, '"'); - test(escapesQuote, '`'); -} +test(escapesQuote, '\''); +test(escapesQuote, '"'); +test(escapesQuote, '`'); test('escapes singlequotes in one-line strings with the default theme', t => { t.snapshot(_format('\''), 'should be escaped'); @@ -136,29 +136,30 @@ test('formats registered symbols differently from normal symbols with same descr t.true(format(Symbol('foo')) !== format(Symbol.for('foo'))); }); -{ +const formatsBoxedPrimitive = test.macro({ // eslint-disable-next-line no-new-object - const formatsBoxedPrimitive = (t, value) => t.snapshot(format(new Object(value))); - formatsBoxedPrimitive.title = (valueRepresentation, value) => `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}`; - for (const value of [ - false, - true, - 42, - -42, - -0, - +0, - Number.POSITIVE_INFINITY, - Number.NEGATIVE_INFINITY, - Number.NaN, - 'foo', - ]) { - test(formatsBoxedPrimitive, value); - } + exec: (t, value) => t.snapshot(format(new Object(value))), + title: (valueRepresentation, value) => `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}`, +}); + +for (const value of [ + false, + true, + 42, + -42, + -0, + +0, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + Number.NaN, + 'foo', +]) { + test(formatsBoxedPrimitive, value); +} - if (typeof BigInt === 'function') { - test('42n', formatsBoxedPrimitive, BigInt(42)); - test('-42n', formatsBoxedPrimitive, BigInt(-42)); - } +if (typeof BigInt === 'function') { + test('42n', formatsBoxedPrimitive, BigInt(42)); + test('-42n', formatsBoxedPrimitive, BigInt(-42)); } test('formats boxed primitives with extra properties', t => { @@ -355,41 +356,41 @@ test('formats circular references', t => { t.snapshot(actual); }); -{ - const plain = (t, value, _tag) => { +const plain = test.macro({ + exec(t, value, _tag) { const actual = format(value); t.snapshot(actual); - }; - - plain.title = (_, __, tag) => `formats ${tag}`; + }, + title: (_, __, tag) => `formats ${tag}`, +}); - const withProperties = (t, value, _tag) => { +const withProperties = test.macro({ + exec(t, value, _tag) { const actual = format(Object.assign(value, {foo: 'bar'})); t.snapshot(actual); - }; - - withProperties.title = (_, __, tag) => `formats ${tag} with additional properties`; - - const buffer = Buffer.from('decafbad'.repeat(12), 'hex'); - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); - - for (const [tag, value, valueForProps] of [ - ['ArrayBuffer', arrayBuffer], - ['Buffer @Uint8Array', buffer], - ['DataView', new DataView(arrayBuffer), new DataView(arrayBuffer)], - ['Float32Array', new Float32Array(arrayBuffer)], - ['Float64Array', new Float64Array(arrayBuffer)], - ['Int16Array', new Int16Array(arrayBuffer)], - ['Int32Array', new Int32Array(arrayBuffer)], - ['Int8Array', new Int8Array(arrayBuffer)], - ['Uint16Array', new Uint16Array(arrayBuffer)], - ['Uint32Array', new Uint32Array(arrayBuffer)], - ['Uint8Array', new Uint8Array(arrayBuffer)], - ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], - ]) { - test(plain, value, tag); - test(withProperties, valueForProps || value.slice(), tag); // eslint-disable-line unicorn/prefer-spread - } + }, + title: (_, __, tag) => `formats ${tag} with additional properties`, +}); + +const buffer = Buffer.from('decafbad'.repeat(12), 'hex'); +const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + +for (const [tag, value, valueForProps] of [ + ['ArrayBuffer', arrayBuffer], + ['Buffer @Uint8Array', buffer], + ['DataView', new DataView(arrayBuffer), new DataView(arrayBuffer)], + ['Float32Array', new Float32Array(arrayBuffer)], + ['Float64Array', new Float64Array(arrayBuffer)], + ['Int16Array', new Int16Array(arrayBuffer)], + ['Int32Array', new Int32Array(arrayBuffer)], + ['Int8Array', new Int8Array(arrayBuffer)], + ['Uint16Array', new Uint16Array(arrayBuffer)], + ['Uint32Array', new Uint32Array(arrayBuffer)], + ['Uint8Array', new Uint8Array(arrayBuffer)], + ['Uint8ClampedArray', new Uint8ClampedArray(arrayBuffer)], +]) { + test(plain, value, tag); + test(withProperties, valueForProps || value.slice(), tag); // eslint-disable-line unicorn/prefer-spread } test('formats dates', t => { diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index 1d04554..5d7de2f 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -30,43 +30,44 @@ const plugins = [ }, ]; -const useDeserialized = (t, value, options) => { - const original = describe(value, options); - - const buffer = serialize(original); - const deserialized = deserialize(buffer, options); - - t.true( - compareDescriptors(deserialized, original), - 'the deserialized descriptor equals the original', - ); - - t.is( - formatDescriptor(deserialized), - formatDescriptor(original), - 'the deserialized descriptor is formatted like the original', - ); - - const redeserialized = deserialize(serialize(deserialized), options); - - t.true( - compareDescriptors(redeserialized, original), - 'after serializing and deserializing it again, the deserialized descriptor equals the original', - ); - - t.is( - formatDescriptor(redeserialized), - formatDescriptor(original), - 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original', - ); - - t.true( - compareDescriptors(redeserialized, deserialized), - 'deserialized descriptors equal each other', - ); -}; - -useDeserialized.title = (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original`; +const useDeserialized = test.macro({ + exec(t, value, options) { + const original = describe(value, options); + + const buffer = serialize(original); + const deserialized = deserialize(buffer, options); + + t.true( + compareDescriptors(deserialized, original), + 'the deserialized descriptor equals the original', + ); + + t.is( + formatDescriptor(deserialized), + formatDescriptor(original), + 'the deserialized descriptor is formatted like the original', + ); + + const redeserialized = deserialize(serialize(deserialized), options); + + t.true( + compareDescriptors(redeserialized, original), + 'after serializing and deserializing it again, the deserialized descriptor equals the original', + ); + + t.is( + formatDescriptor(redeserialized), + formatDescriptor(original), + 'after serializing and deserializing it again, the deserialized descriptor is formatted like the original', + ); + + t.true( + compareDescriptors(redeserialized, deserialized), + 'deserialized descriptors equal each other', + ); + }, + title: (desc, value) => `deserialized ${desc || String(value)} is equivalent to the original`, +}); // Primitives test(useDeserialized, true); From 14d3b6a16c223d3c6cd26258db4d3cf2467372b6 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 21 Jul 2024 15:58:51 -0500 Subject: [PATCH 09/13] update deps, Node versions, fix lints --- .github/workflows/ci.yml | 6 ++--- lib/complexValues/arrayBuffer.js | 6 +++-- lib/complexValues/global.js | 1 - lib/complexValues/map.js | 4 +--- lib/complexValues/object.js | 1 - lib/complexValues/set.js | 4 +--- lib/diff.js | 8 +++---- lib/encoder.js | 4 +++- lib/metaDescriptors/item.js | 2 -- lib/metaDescriptors/mapEntry.js | 1 - lib/metaDescriptors/pointer.js | 1 - lib/primitiveValues/bigInt.js | 1 - lib/primitiveValues/boolean.js | 1 - lib/primitiveValues/null.js | 1 - lib/primitiveValues/number.js | 1 - lib/primitiveValues/string.js | 1 - lib/primitiveValues/symbol.js | 1 - lib/primitiveValues/undefined.js | 1 - lib/recursorUtils.js | 6 +++-- lib/themeUtils.js | 4 +--- package.json | 28 +++++++++-------------- test/diff.js | 2 -- test/format.js | 10 ++++---- test/lodash-isequal-comparison.js | 38 +++++++++++++++++++++---------- test/serialization-fixtures.js | 4 +++- test/serialize-and-encode.js | 4 +++- 26 files changed, 69 insertions(+), 72 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b865562..33dae39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,12 +13,12 @@ jobs: strategy: fail-fast: false matrix: - node-version: [^16.9, 18, 20] + node-version: [18, 20, 21] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install --no-audit diff --git a/lib/complexValues/arrayBuffer.js b/lib/complexValues/arrayBuffer.js index 9dd9797..6525dd4 100644 --- a/lib/complexValues/arrayBuffer.js +++ b/lib/complexValues/arrayBuffer.js @@ -3,10 +3,12 @@ import {Buffer} from 'node:buffer'; import * as typedArray from './typedArray.js'; export function describe(props) { - return new DescribedArrayBufferValue({buffer: Buffer.from(props.value), + return new DescribedArrayBufferValue({ + buffer: Buffer.from(props.value), // Set isArray and isList so the property recursor excludes the byte accessors isArray: true, - isList: true, ...props}); + isList: true, ...props, + }); } export function deserialize(state, recursor) { diff --git a/lib/complexValues/global.js b/lib/complexValues/global.js index 3ec93f9..41169d3 100644 --- a/lib/complexValues/global.js +++ b/lib/complexValues/global.js @@ -24,6 +24,5 @@ class GlobalValue { } isComplex = true; - tag = tag; } diff --git a/lib/complexValues/map.js b/lib/complexValues/map.js index 62bd59b..f24c9b4 100644 --- a/lib/complexValues/map.js +++ b/lib/complexValues/map.js @@ -56,9 +56,7 @@ class DescribedMapValue extends object.DescribedMixin(MapValue) { return null; } - if (!entries) { - entries = [...this.value]; - } + entries ||= [...this.value]; const entry = entries[index++]; return this.describeMapEntry(this.describeAny(entry[0]), this.describeAny(entry[1])); diff --git a/lib/complexValues/object.js b/lib/complexValues/object.js index 240248b..0e27b1a 100644 --- a/lib/complexValues/object.js +++ b/lib/complexValues/object.js @@ -65,7 +65,6 @@ export class ObjectValue { } isComplex = true; - tag = tag; } diff --git a/lib/complexValues/set.js b/lib/complexValues/set.js index 7875d28..593f1df 100644 --- a/lib/complexValues/set.js +++ b/lib/complexValues/set.js @@ -56,9 +56,7 @@ class DescribedSetValue extends object.DescribedMixin(SetValue) { return null; } - if (!members) { - members = [...this.value]; - } + members ||= [...this.value]; const value = members[index]; return this.describeItem(index++, this.describeAny(value)); diff --git a/lib/diff.js b/lib/diff.js index 9a31a20..5be4db2 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -1,6 +1,8 @@ import Circular from './Circular.js'; import Indenter from './Indenter.js'; -import {AMBIGUOUS, DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL} from './constants.js'; +import { + AMBIGUOUS, DEEP_EQUAL, UNEQUAL, SHALLOW_EQUAL, +} from './constants.js'; import describe from './describe.js'; import lineBuilder from './lineBuilder.js'; import * as recursorUtils from './recursorUtils.js'; @@ -279,9 +281,7 @@ export function diffDescriptors(lhs, rhs, options) { compareResult = lhs.compare(rhs); } - if (!mustRecurse) { - mustRecurse = shouldCompareDeep(compareResult, lhs, rhs); - } + mustRecurse ||= shouldCompareDeep(compareResult, lhs, rhs); if (compareResult === DEEP_EQUAL) { format(lineBuilder, lhs, lhsCircular); diff --git a/lib/encoder.js b/lib/encoder.js index a152fcf..50ee4ca 100644 --- a/lib/encoder.js +++ b/lib/encoder.js @@ -352,7 +352,9 @@ export function decodeRecord(buffer, byteOffset) { } const state = decodeValue(buffer, byteOffset).value; - return {id, pluginIndex, state, pointerAddresses}; + return { + id, pluginIndex, state, pointerAddresses, + }; } export function extractVersion(buffer) { diff --git a/lib/metaDescriptors/item.js b/lib/metaDescriptors/item.js index 2964cc6..f8ad681 100644 --- a/lib/metaDescriptors/item.js +++ b/lib/metaDescriptors/item.js @@ -143,7 +143,6 @@ class ComplexItem { } isItem = true; - tag = complexTag; } @@ -260,6 +259,5 @@ class PrimitiveItem { } isItem = true; - tag = primitiveTag; } diff --git a/lib/metaDescriptors/mapEntry.js b/lib/metaDescriptors/mapEntry.js index b7d6ae9..ac9f59a 100644 --- a/lib/metaDescriptors/mapEntry.js +++ b/lib/metaDescriptors/mapEntry.js @@ -236,6 +236,5 @@ class MapEntry { } isMapEntry = true; - tag = tag; } diff --git a/lib/metaDescriptors/pointer.js b/lib/metaDescriptors/pointer.js index 1ba65b0..79e691f 100644 --- a/lib/metaDescriptors/pointer.js +++ b/lib/metaDescriptors/pointer.js @@ -24,6 +24,5 @@ class Pointer { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/bigInt.js b/lib/primitiveValues/bigInt.js index 7e7a00d..d60155b 100644 --- a/lib/primitiveValues/bigInt.js +++ b/lib/primitiveValues/bigInt.js @@ -30,6 +30,5 @@ class BigIntValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/boolean.js b/lib/primitiveValues/boolean.js index 628ba4a..4bfdf90 100644 --- a/lib/primitiveValues/boolean.js +++ b/lib/primitiveValues/boolean.js @@ -30,6 +30,5 @@ class BooleanValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/null.js b/lib/primitiveValues/null.js index 50f0e68..5251abb 100644 --- a/lib/primitiveValues/null.js +++ b/lib/primitiveValues/null.js @@ -22,6 +22,5 @@ class NullValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/number.js b/lib/primitiveValues/number.js index 203b11c..c1ea708 100644 --- a/lib/primitiveValues/number.js +++ b/lib/primitiveValues/number.js @@ -31,6 +31,5 @@ class NumberValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/string.js b/lib/primitiveValues/string.js index 27a9a65..80eb04c 100644 --- a/lib/primitiveValues/string.js +++ b/lib/primitiveValues/string.js @@ -332,6 +332,5 @@ class StringValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/symbol.js b/lib/primitiveValues/symbol.js index 6d08b64..8a2f636 100644 --- a/lib/primitiveValues/symbol.js +++ b/lib/primitiveValues/symbol.js @@ -80,7 +80,6 @@ class SymbolValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/primitiveValues/undefined.js b/lib/primitiveValues/undefined.js index 7d9f0b7..562dc7c 100644 --- a/lib/primitiveValues/undefined.js +++ b/lib/primitiveValues/undefined.js @@ -22,6 +22,5 @@ class UndefinedValue { } isPrimitive = true; - tag = tag; } diff --git a/lib/recursorUtils.js b/lib/recursorUtils.js index 3aa41c5..4389e52 100644 --- a/lib/recursorUtils.js +++ b/lib/recursorUtils.js @@ -60,8 +60,10 @@ export function replay(state, create) { if (recursor === NOOP_RECURSOR) { state = recursor; } else { - state = {buffer: [], - done: false, ...recursor}; + state = { + buffer: [], + done: false, ...recursor, + }; } } diff --git a/lib/themeUtils.js b/lib/themeUtils.js index 3adf7ff..c00bf40 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -151,9 +151,7 @@ export function normalize(options) { return theme; } - if (!entry.theme) { - entry.theme = freezeTheme(merge(cloneDeep(defaultTheme), options.theme)); - } + entry.theme ||= freezeTheme(merge(cloneDeep(defaultTheme), options.theme)); return entry.theme; } diff --git a/package.json b/package.json index f51c925..d611d1a 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,10 @@ "index.js" ], "engines": { - "node": ">=16.9" + "node": "^18.18 || ^20.8 || ^21 || ^22" }, "scripts": { - "test": "xo && c8 npm run ava", - "ava": "cross-env NODE_OPTIONS='--loader=esmock --no-warnings=ExperimentalWarning' ava" + "test": "xo && c8 ava" }, "repository": { "type": "git", @@ -32,17 +31,16 @@ "esutils": "^2.0.3", "fast-diff": "^1.3.0", "js-string-escape": "^1.0.1", - "md5-hex": "^4.0.0", - "semver": "^7.5.4", + "md5-hex": "^5.0.0", + "semver": "^7.6.3", "well-known-symbols": "^2.0.0" }, "devDependencies": { - "@types/node": "16.9", - "ava": "^5.3.1", - "c8": "^8.0.1", - "cross-env": "^7.0.3", - "esmock": "^2.3.8", - "xo": "^0.56.0" + "@types/node": "18.18", + "ava": "^6.1.3", + "c8": "^10.1.2", + "esmock": "^2.6.7", + "xo": "^0.59.0" }, "xo": { "ignores": [ @@ -62,14 +60,10 @@ "unicorn/require-post-message-target-origin": "off", "unicorn/filename-case": "off", "import/no-anonymous-default-export": "off", + "unicorn/prefer-event-target": "off", + "unicorn/prevent-abbreviations": "off", "new-cap": "off", "func-names": "off" } - }, - "ava": { - "nodeArguments": [ - "--loader=esmock", - "--no-warnings=ExperimentalWarning" - ] } } diff --git a/test/diff.js b/test/diff.js index 95bc629..2d9b915 100644 --- a/test/diff.js +++ b/test/diff.js @@ -48,7 +48,6 @@ if (typeof BigInt === 'function') { } const diffsBoxedPrimitives = test.macro({ - // eslint-disable-next-line no-new-object exec: (t, lhs, rhs) => t.snapshot(diff(new Object(lhs), new Object(rhs))), title: (_, lhs, rhs, lhsRepresentation = String(lhs), rhsRepresentation = String(rhs)) => `diffs primitives: ${lhsRepresentation} versus ${rhsRepresentation}`, }); @@ -66,7 +65,6 @@ if (typeof BigInt === 'function') { } test('diffs boxed primitives with extra properties', t => { - // eslint-disable-next-line no-new-object t.snapshot(diff(new Object('foo'), Object.assign(new Object('foo'), {bar: 'baz'}))); }); diff --git a/test/format.js b/test/format.js index 8d20749..8c7879f 100644 --- a/test/format.js +++ b/test/format.js @@ -137,7 +137,6 @@ test('formats registered symbols differently from normal symbols with same descr }); const formatsBoxedPrimitive = test.macro({ - // eslint-disable-next-line no-new-object exec: (t, value) => t.snapshot(format(new Object(value))), title: (valueRepresentation, value) => `formats boxed primitive: ${valueRepresentation || (Object.is(value, -0) ? '-0' : String(value))}`, }); @@ -163,7 +162,6 @@ if (typeof BigInt === 'function') { } test('formats boxed primitives with extra properties', t => { - // eslint-disable-next-line no-new-object t.snapshot(format(Object.assign(new Object('foo'), {bar: 'baz'}))); }); @@ -244,9 +242,11 @@ test('formats funky objects that are lists and have an iterator', t => { foo: 'bar', }; Object.defineProperty(funky, 'length', {value: 2}); - Object.defineProperty(funky, Symbol.iterator, {* value() { - yield 'baz'; - }}); + Object.defineProperty(funky, Symbol.iterator, { + * value() { + yield 'baz'; + }, + }); const actual = format(funky); t.snapshot(actual); diff --git a/test/lodash-isequal-comparison.js b/test/lodash-isequal-comparison.js index 22127f9..3f5b3ae 100644 --- a/test/lodash-isequal-comparison.js +++ b/test/lodash-isequal-comparison.js @@ -1,4 +1,4 @@ -/* eslint-disable prefer-rest-params, no-multi-assign, no-new-object */ +/* eslint-disable prefer-rest-params, no-multi-assign */ /* Copyright JS Foundation and other contributors @@ -172,13 +172,21 @@ test('compare sparse arrays', t => { }); test('compare plain objects', t => { - let object1 = {a: true, b: null, c: 1, d: 'a', e: undefined}; - let object2 = {a: true, b: null, c: 1, d: 'a', e: undefined}; + let object1 = { + a: true, b: null, c: 1, d: 'a', e: undefined, + }; + let object2 = { + a: true, b: null, c: 1, d: 'a', e: undefined, + }; t.true(isEqual(object1, object2)); - object1 = {a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}}; - object2 = {a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}}; + object1 = { + a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}, + }; + object2 = { + a: [1, 2, 3], b: new Date(2012, 4, 23), c: /x/, d: {e: 1}, + }; t.true(isEqual(object1, object2)); @@ -506,9 +514,11 @@ test('compare date objects', t => { t.true(isEqual(date, new Date(2012, 4, 23))); t.true(isEqual(new Date('a'), new Date('b'))); t.false(isEqual(date, new Date(2013, 3, 25))); - t.false(isEqual(date, {getTime() { - return Number(date); - }})); + t.false(isEqual(date, { + getTime() { + return Number(date); + }, + })); }); test('compare error objects', t => { @@ -595,7 +605,9 @@ test('compare regexes', t => { t.true(isEqual(/x/gim, /x/gim)); t.false(isEqual(/x/gi, /x/g)); t.false(isEqual(/x/, /y/)); - t.false(isEqual(/x/g, {global: true, ignoreCase: false, multiline: false, source: 'x'})); + t.false(isEqual(/x/g, { + global: true, ignoreCase: false, multiline: false, source: 'x', + })); }); test('compare sets', t => { @@ -672,9 +684,11 @@ test('return `true` for like-objects from different realms', t => { test('return `false` for objects with custom `toString` methods', t => { let primitive; - const object = {'toString'() { - return primitive; - }}; + const object = { + 'toString'() { + return primitive; + }, + }; for (const value of [true, null, 1, 'a', undefined]) { primitive = value; t.false(isEqual(object, value)); diff --git a/test/serialization-fixtures.js b/test/serialization-fixtures.js index df1d7b0..270c912 100644 --- a/test/serialization-fixtures.js +++ b/test/serialization-fixtures.js @@ -1,6 +1,8 @@ import test from 'ava'; -import {compareDescriptors, deserialize, describe, diff} from '../index.js'; +import { + compareDescriptors, deserialize, describe, diff, +} from '../index.js'; import {serialization, tree} from './fixtures/pointerSerialization.js'; diff --git a/test/serialize-and-encode.js b/test/serialize-and-encode.js index 5d7de2f..31a5ce4 100644 --- a/test/serialize-and-encode.js +++ b/test/serialize-and-encode.js @@ -3,7 +3,9 @@ import {Buffer} from 'node:buffer'; import test from 'ava'; -import {compareDescriptors, describe, diffDescriptors, formatDescriptor} from '../index.js'; +import { + compareDescriptors, describe, diffDescriptors, formatDescriptor, +} from '../index.js'; import {deserialize, serialize} from '../lib/serialize.js'; import * as customErrorPlugin from './fixtures/customErrorPlugin.js'; From ce5d595e880c881270f4797d415576d2d105aeef Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 21 Jul 2024 16:17:07 -0500 Subject: [PATCH 10/13] remove lodash --- lib/hasLength.js | 9 +- lib/lodash/_DataView.js | 7 -- lib/lodash/_Hash.js | 32 ------ lib/lodash/_ListCache.js | 32 ------ lib/lodash/_Map.js | 7 -- lib/lodash/_MapCache.js | 32 ------ lib/lodash/_Promise.js | 7 -- lib/lodash/_Set.js | 7 -- lib/lodash/_Stack.js | 27 ----- lib/lodash/_Symbol.js | 6 -- lib/lodash/_Uint8Array.js | 6 -- lib/lodash/_WeakMap.js | 7 -- lib/lodash/_apply.js | 21 ---- lib/lodash/_arrayEach.js | 22 ---- lib/lodash/_arrayFilter.js | 25 ----- lib/lodash/_arrayLikeKeys.js | 49 --------- lib/lodash/_arrayPush.js | 20 ---- lib/lodash/_assignMergeValue.js | 20 ---- lib/lodash/_assignValue.js | 28 ------ lib/lodash/_assocIndexOf.js | 21 ---- lib/lodash/_baseAssign.js | 17 ---- lib/lodash/_baseAssignIn.js | 17 ---- lib/lodash/_baseAssignValue.js | 25 ----- lib/lodash/_baseClone.js | 171 -------------------------------- lib/lodash/_baseCreate.js | 30 ------ lib/lodash/_baseFor.js | 16 --- lib/lodash/_baseGetAllKeys.js | 20 ---- lib/lodash/_baseGetTag.js | 28 ------ lib/lodash/_baseIsArguments.js | 18 ---- lib/lodash/_baseIsMap.js | 18 ---- lib/lodash/_baseIsNative.js | 47 --------- lib/lodash/_baseIsSet.js | 18 ---- lib/lodash/_baseIsTypedArray.js | 60 ----------- lib/lodash/_baseKeys.js | 30 ------ lib/lodash/_baseKeysIn.js | 33 ------ lib/lodash/_baseMerge.js | 42 -------- lib/lodash/_baseMergeDeep.js | 94 ------------------ lib/lodash/_baseRest.js | 17 ---- lib/lodash/_baseSetToString.js | 22 ---- lib/lodash/_baseTimes.js | 20 ---- lib/lodash/_baseUnary.js | 14 --- lib/lodash/_cloneArrayBuffer.js | 16 --- lib/lodash/_cloneBuffer.js | 35 ------- lib/lodash/_cloneDataView.js | 16 --- lib/lodash/_cloneRegExp.js | 17 ---- lib/lodash/_cloneSymbol.js | 18 ---- lib/lodash/_cloneTypedArray.js | 16 --- lib/lodash/_copyArray.js | 20 ---- lib/lodash/_copyObject.js | 40 -------- lib/lodash/_copySymbols.js | 16 --- lib/lodash/_copySymbolsIn.js | 16 --- lib/lodash/_coreJsData.js | 6 -- lib/lodash/_createAssigner.js | 37 ------- lib/lodash/_createBaseFor.js | 25 ----- lib/lodash/_defineProperty.js | 11 -- lib/lodash/_freeGlobal.js | 4 - lib/lodash/_getAllKeys.js | 16 --- lib/lodash/_getAllKeysIn.js | 17 ---- lib/lodash/_getMapData.js | 18 ---- lib/lodash/_getNative.js | 17 ---- lib/lodash/_getPrototype.js | 6 -- lib/lodash/_getRawTag.js | 46 --------- lib/lodash/_getSymbols.js | 30 ------ lib/lodash/_getSymbolsIn.js | 25 ----- lib/lodash/_getTag.js | 58 ----------- lib/lodash/_getValue.js | 13 --- lib/lodash/_hashClear.js | 15 --- lib/lodash/_hashDelete.js | 17 ---- lib/lodash/_hashGet.js | 30 ------ lib/lodash/_hashHas.js | 23 ----- lib/lodash/_hashSet.js | 23 ----- lib/lodash/_initCloneArray.js | 26 ----- lib/lodash/_initCloneByTag.js | 77 -------------- lib/lodash/_initCloneObject.js | 18 ---- lib/lodash/_isIndex.js | 25 ----- lib/lodash/_isIterateeCall.js | 30 ------ lib/lodash/_isKeyable.js | 15 --- lib/lodash/_isMasked.js | 20 ---- lib/lodash/_isPrototype.js | 18 ---- lib/lodash/_listCacheClear.js | 13 --- lib/lodash/_listCacheDelete.js | 35 ------- lib/lodash/_listCacheGet.js | 19 ---- lib/lodash/_listCacheHas.js | 16 --- lib/lodash/_listCacheSet.js | 26 ----- lib/lodash/_mapCacheClear.js | 21 ---- lib/lodash/_mapCacheDelete.js | 18 ---- lib/lodash/_mapCacheGet.js | 16 --- lib/lodash/_mapCacheHas.js | 16 --- lib/lodash/_mapCacheSet.js | 22 ---- lib/lodash/_nativeCreate.js | 6 -- lib/lodash/_nativeKeys.js | 6 -- lib/lodash/_nativeKeysIn.js | 20 ---- lib/lodash/_nodeUtil.js | 22 ---- lib/lodash/_objectToString.js | 22 ---- lib/lodash/_overArg.js | 15 --- lib/lodash/_overRest.js | 36 ------- lib/lodash/_root.js | 9 -- lib/lodash/_safeGet.js | 15 --- lib/lodash/_setToString.js | 14 --- lib/lodash/_shortOut.js | 37 ------- lib/lodash/_stackClear.js | 15 --- lib/lodash/_stackDelete.js | 18 ---- lib/lodash/_stackGet.js | 14 --- lib/lodash/_stackHas.js | 14 --- lib/lodash/_stackSet.js | 34 ------- lib/lodash/_toSource.js | 26 ----- lib/lodash/cloneDeep.js | 29 ------ lib/lodash/constant.js | 26 ----- lib/lodash/eq.js | 37 ------- lib/lodash/identity.js | 21 ---- lib/lodash/index.js | 12 --- lib/lodash/isArguments.js | 36 ------- lib/lodash/isArray.js | 26 ----- lib/lodash/isArrayLike.js | 33 ------ lib/lodash/isArrayLikeObject.js | 33 ------ lib/lodash/isBuffer.js | 38 ------- lib/lodash/isFunction.js | 37 ------- lib/lodash/isLength.js | 35 ------- lib/lodash/isMap.js | 27 ----- lib/lodash/isObject.js | 31 ------ lib/lodash/isObjectLike.js | 29 ------ lib/lodash/isPlainObject.js | 62 ------------ lib/lodash/isSet.js | 27 ----- lib/lodash/isTypedArray.js | 27 ----- lib/lodash/keys.js | 37 ------- lib/lodash/keysIn.js | 32 ------ lib/lodash/lang.default.js | 23 ----- lib/lodash/lang.js | 17 ---- lib/lodash/merge.js | 39 -------- lib/lodash/object.default.js | 7 -- lib/lodash/object.js | 4 - lib/lodash/stubArray.js | 23 ----- lib/lodash/stubFalse.js | 18 ---- lib/lodash/toPlainObject.js | 32 ------ lib/lodash/util.default.js | 8 -- lib/lodash/util.js | 5 - lib/themeUtils.js | 13 +-- package.json | 3 - 138 files changed, 15 insertions(+), 3355 deletions(-) delete mode 100644 lib/lodash/_DataView.js delete mode 100644 lib/lodash/_Hash.js delete mode 100644 lib/lodash/_ListCache.js delete mode 100644 lib/lodash/_Map.js delete mode 100644 lib/lodash/_MapCache.js delete mode 100644 lib/lodash/_Promise.js delete mode 100644 lib/lodash/_Set.js delete mode 100644 lib/lodash/_Stack.js delete mode 100644 lib/lodash/_Symbol.js delete mode 100644 lib/lodash/_Uint8Array.js delete mode 100644 lib/lodash/_WeakMap.js delete mode 100644 lib/lodash/_apply.js delete mode 100644 lib/lodash/_arrayEach.js delete mode 100644 lib/lodash/_arrayFilter.js delete mode 100644 lib/lodash/_arrayLikeKeys.js delete mode 100644 lib/lodash/_arrayPush.js delete mode 100644 lib/lodash/_assignMergeValue.js delete mode 100644 lib/lodash/_assignValue.js delete mode 100644 lib/lodash/_assocIndexOf.js delete mode 100644 lib/lodash/_baseAssign.js delete mode 100644 lib/lodash/_baseAssignIn.js delete mode 100644 lib/lodash/_baseAssignValue.js delete mode 100644 lib/lodash/_baseClone.js delete mode 100644 lib/lodash/_baseCreate.js delete mode 100644 lib/lodash/_baseFor.js delete mode 100644 lib/lodash/_baseGetAllKeys.js delete mode 100644 lib/lodash/_baseGetTag.js delete mode 100644 lib/lodash/_baseIsArguments.js delete mode 100644 lib/lodash/_baseIsMap.js delete mode 100644 lib/lodash/_baseIsNative.js delete mode 100644 lib/lodash/_baseIsSet.js delete mode 100644 lib/lodash/_baseIsTypedArray.js delete mode 100644 lib/lodash/_baseKeys.js delete mode 100644 lib/lodash/_baseKeysIn.js delete mode 100644 lib/lodash/_baseMerge.js delete mode 100644 lib/lodash/_baseMergeDeep.js delete mode 100644 lib/lodash/_baseRest.js delete mode 100644 lib/lodash/_baseSetToString.js delete mode 100644 lib/lodash/_baseTimes.js delete mode 100644 lib/lodash/_baseUnary.js delete mode 100644 lib/lodash/_cloneArrayBuffer.js delete mode 100644 lib/lodash/_cloneBuffer.js delete mode 100644 lib/lodash/_cloneDataView.js delete mode 100644 lib/lodash/_cloneRegExp.js delete mode 100644 lib/lodash/_cloneSymbol.js delete mode 100644 lib/lodash/_cloneTypedArray.js delete mode 100644 lib/lodash/_copyArray.js delete mode 100644 lib/lodash/_copyObject.js delete mode 100644 lib/lodash/_copySymbols.js delete mode 100644 lib/lodash/_copySymbolsIn.js delete mode 100644 lib/lodash/_coreJsData.js delete mode 100644 lib/lodash/_createAssigner.js delete mode 100644 lib/lodash/_createBaseFor.js delete mode 100644 lib/lodash/_defineProperty.js delete mode 100644 lib/lodash/_freeGlobal.js delete mode 100644 lib/lodash/_getAllKeys.js delete mode 100644 lib/lodash/_getAllKeysIn.js delete mode 100644 lib/lodash/_getMapData.js delete mode 100644 lib/lodash/_getNative.js delete mode 100644 lib/lodash/_getPrototype.js delete mode 100644 lib/lodash/_getRawTag.js delete mode 100644 lib/lodash/_getSymbols.js delete mode 100644 lib/lodash/_getSymbolsIn.js delete mode 100644 lib/lodash/_getTag.js delete mode 100644 lib/lodash/_getValue.js delete mode 100644 lib/lodash/_hashClear.js delete mode 100644 lib/lodash/_hashDelete.js delete mode 100644 lib/lodash/_hashGet.js delete mode 100644 lib/lodash/_hashHas.js delete mode 100644 lib/lodash/_hashSet.js delete mode 100644 lib/lodash/_initCloneArray.js delete mode 100644 lib/lodash/_initCloneByTag.js delete mode 100644 lib/lodash/_initCloneObject.js delete mode 100644 lib/lodash/_isIndex.js delete mode 100644 lib/lodash/_isIterateeCall.js delete mode 100644 lib/lodash/_isKeyable.js delete mode 100644 lib/lodash/_isMasked.js delete mode 100644 lib/lodash/_isPrototype.js delete mode 100644 lib/lodash/_listCacheClear.js delete mode 100644 lib/lodash/_listCacheDelete.js delete mode 100644 lib/lodash/_listCacheGet.js delete mode 100644 lib/lodash/_listCacheHas.js delete mode 100644 lib/lodash/_listCacheSet.js delete mode 100644 lib/lodash/_mapCacheClear.js delete mode 100644 lib/lodash/_mapCacheDelete.js delete mode 100644 lib/lodash/_mapCacheGet.js delete mode 100644 lib/lodash/_mapCacheHas.js delete mode 100644 lib/lodash/_mapCacheSet.js delete mode 100644 lib/lodash/_nativeCreate.js delete mode 100644 lib/lodash/_nativeKeys.js delete mode 100644 lib/lodash/_nativeKeysIn.js delete mode 100644 lib/lodash/_nodeUtil.js delete mode 100644 lib/lodash/_objectToString.js delete mode 100644 lib/lodash/_overArg.js delete mode 100644 lib/lodash/_overRest.js delete mode 100644 lib/lodash/_root.js delete mode 100644 lib/lodash/_safeGet.js delete mode 100644 lib/lodash/_setToString.js delete mode 100644 lib/lodash/_shortOut.js delete mode 100644 lib/lodash/_stackClear.js delete mode 100644 lib/lodash/_stackDelete.js delete mode 100644 lib/lodash/_stackGet.js delete mode 100644 lib/lodash/_stackHas.js delete mode 100644 lib/lodash/_stackSet.js delete mode 100644 lib/lodash/_toSource.js delete mode 100644 lib/lodash/cloneDeep.js delete mode 100644 lib/lodash/constant.js delete mode 100644 lib/lodash/eq.js delete mode 100644 lib/lodash/identity.js delete mode 100644 lib/lodash/index.js delete mode 100644 lib/lodash/isArguments.js delete mode 100644 lib/lodash/isArray.js delete mode 100644 lib/lodash/isArrayLike.js delete mode 100644 lib/lodash/isArrayLikeObject.js delete mode 100644 lib/lodash/isBuffer.js delete mode 100644 lib/lodash/isFunction.js delete mode 100644 lib/lodash/isLength.js delete mode 100644 lib/lodash/isMap.js delete mode 100644 lib/lodash/isObject.js delete mode 100644 lib/lodash/isObjectLike.js delete mode 100644 lib/lodash/isPlainObject.js delete mode 100644 lib/lodash/isSet.js delete mode 100644 lib/lodash/isTypedArray.js delete mode 100644 lib/lodash/keys.js delete mode 100644 lib/lodash/keysIn.js delete mode 100644 lib/lodash/lang.default.js delete mode 100644 lib/lodash/lang.js delete mode 100644 lib/lodash/merge.js delete mode 100644 lib/lodash/object.default.js delete mode 100644 lib/lodash/object.js delete mode 100644 lib/lodash/stubArray.js delete mode 100644 lib/lodash/stubFalse.js delete mode 100644 lib/lodash/toPlainObject.js delete mode 100644 lib/lodash/util.default.js delete mode 100644 lib/lodash/util.js diff --git a/lib/hasLength.js b/lib/hasLength.js index ab4594f..24aef9c 100644 --- a/lib/hasLength.js +++ b/lib/hasLength.js @@ -1,4 +1,11 @@ -import {isLength} from './lodash/index.js'; +const MAX_SAFE_INTEGER = 9_007_199_254_740_991; + +/** Checks if `value` is a valid array-like length. @see https://lodash.com/docs/4.17.15#isLength */ +function isLength(value) { + return ( + typeof value === 'number' && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER + ); +} export default function hasLength(object) { return ( diff --git a/lib/lodash/_DataView.js b/lib/lodash/_DataView.js deleted file mode 100644 index 1bbaaa1..0000000 --- a/lib/lodash/_DataView.js +++ /dev/null @@ -1,7 +0,0 @@ -import getNative from './_getNative.js'; -import root from './_root.js'; - -/* Built-in method references that are verified to be native. */ -var DataView = getNative(root, 'DataView'); - -export default DataView; diff --git a/lib/lodash/_Hash.js b/lib/lodash/_Hash.js deleted file mode 100644 index 8ecacb0..0000000 --- a/lib/lodash/_Hash.js +++ /dev/null @@ -1,32 +0,0 @@ -import hashClear from './_hashClear.js'; -import hashDelete from './_hashDelete.js'; -import hashGet from './_hashGet.js'; -import hashHas from './_hashHas.js'; -import hashSet from './_hashSet.js'; - -/** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `Hash`. -Hash.prototype.clear = hashClear; -Hash.prototype['delete'] = hashDelete; -Hash.prototype.get = hashGet; -Hash.prototype.has = hashHas; -Hash.prototype.set = hashSet; - -export default Hash; diff --git a/lib/lodash/_ListCache.js b/lib/lodash/_ListCache.js deleted file mode 100644 index bafa2af..0000000 --- a/lib/lodash/_ListCache.js +++ /dev/null @@ -1,32 +0,0 @@ -import listCacheClear from './_listCacheClear.js'; -import listCacheDelete from './_listCacheDelete.js'; -import listCacheGet from './_listCacheGet.js'; -import listCacheHas from './_listCacheHas.js'; -import listCacheSet from './_listCacheSet.js'; - -/** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `ListCache`. -ListCache.prototype.clear = listCacheClear; -ListCache.prototype['delete'] = listCacheDelete; -ListCache.prototype.get = listCacheGet; -ListCache.prototype.has = listCacheHas; -ListCache.prototype.set = listCacheSet; - -export default ListCache; diff --git a/lib/lodash/_Map.js b/lib/lodash/_Map.js deleted file mode 100644 index 2055850..0000000 --- a/lib/lodash/_Map.js +++ /dev/null @@ -1,7 +0,0 @@ -import getNative from './_getNative.js'; -import root from './_root.js'; - -/* Built-in method references that are verified to be native. */ -var Map = getNative(root, 'Map'); - -export default Map; diff --git a/lib/lodash/_MapCache.js b/lib/lodash/_MapCache.js deleted file mode 100644 index deef22e..0000000 --- a/lib/lodash/_MapCache.js +++ /dev/null @@ -1,32 +0,0 @@ -import mapCacheClear from './_mapCacheClear.js'; -import mapCacheDelete from './_mapCacheDelete.js'; -import mapCacheGet from './_mapCacheGet.js'; -import mapCacheHas from './_mapCacheHas.js'; -import mapCacheSet from './_mapCacheSet.js'; - -/** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `MapCache`. -MapCache.prototype.clear = mapCacheClear; -MapCache.prototype['delete'] = mapCacheDelete; -MapCache.prototype.get = mapCacheGet; -MapCache.prototype.has = mapCacheHas; -MapCache.prototype.set = mapCacheSet; - -export default MapCache; diff --git a/lib/lodash/_Promise.js b/lib/lodash/_Promise.js deleted file mode 100644 index ce54b58..0000000 --- a/lib/lodash/_Promise.js +++ /dev/null @@ -1,7 +0,0 @@ -import getNative from './_getNative.js'; -import root from './_root.js'; - -/* Built-in method references that are verified to be native. */ -var Promise = getNative(root, 'Promise'); - -export default Promise; diff --git a/lib/lodash/_Set.js b/lib/lodash/_Set.js deleted file mode 100644 index 2f95209..0000000 --- a/lib/lodash/_Set.js +++ /dev/null @@ -1,7 +0,0 @@ -import getNative from './_getNative.js'; -import root from './_root.js'; - -/* Built-in method references that are verified to be native. */ -var Set = getNative(root, 'Set'); - -export default Set; diff --git a/lib/lodash/_Stack.js b/lib/lodash/_Stack.js deleted file mode 100644 index 77c3cf3..0000000 --- a/lib/lodash/_Stack.js +++ /dev/null @@ -1,27 +0,0 @@ -import ListCache from './_ListCache.js'; -import stackClear from './_stackClear.js'; -import stackDelete from './_stackDelete.js'; -import stackGet from './_stackGet.js'; -import stackHas from './_stackHas.js'; -import stackSet from './_stackSet.js'; - -/** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; -} - -// Add methods to `Stack`. -Stack.prototype.clear = stackClear; -Stack.prototype['delete'] = stackDelete; -Stack.prototype.get = stackGet; -Stack.prototype.has = stackHas; -Stack.prototype.set = stackSet; - -export default Stack; diff --git a/lib/lodash/_Symbol.js b/lib/lodash/_Symbol.js deleted file mode 100644 index 2b9341c..0000000 --- a/lib/lodash/_Symbol.js +++ /dev/null @@ -1,6 +0,0 @@ -import root from './_root.js'; - -/** Built-in value references. */ -var Symbol = root.Symbol; - -export default Symbol; diff --git a/lib/lodash/_Uint8Array.js b/lib/lodash/_Uint8Array.js deleted file mode 100644 index f463674..0000000 --- a/lib/lodash/_Uint8Array.js +++ /dev/null @@ -1,6 +0,0 @@ -import root from './_root.js'; - -/** Built-in value references. */ -var Uint8Array = root.Uint8Array; - -export default Uint8Array; diff --git a/lib/lodash/_WeakMap.js b/lib/lodash/_WeakMap.js deleted file mode 100644 index 6f97de5..0000000 --- a/lib/lodash/_WeakMap.js +++ /dev/null @@ -1,7 +0,0 @@ -import getNative from './_getNative.js'; -import root from './_root.js'; - -/* Built-in method references that are verified to be native. */ -var WeakMap = getNative(root, 'WeakMap'); - -export default WeakMap; diff --git a/lib/lodash/_apply.js b/lib/lodash/_apply.js deleted file mode 100644 index a92f5a8..0000000 --- a/lib/lodash/_apply.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ -function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); -} - -export default apply; diff --git a/lib/lodash/_arrayEach.js b/lib/lodash/_arrayEach.js deleted file mode 100644 index 2a570bf..0000000 --- a/lib/lodash/_arrayEach.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ -function arrayEach(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; -} - -export default arrayEach; diff --git a/lib/lodash/_arrayFilter.js b/lib/lodash/_arrayFilter.js deleted file mode 100644 index 20d3769..0000000 --- a/lib/lodash/_arrayFilter.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ -function arrayFilter(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; -} - -export default arrayFilter; diff --git a/lib/lodash/_arrayLikeKeys.js b/lib/lodash/_arrayLikeKeys.js deleted file mode 100644 index de5d551..0000000 --- a/lib/lodash/_arrayLikeKeys.js +++ /dev/null @@ -1,49 +0,0 @@ -import baseTimes from './_baseTimes.js'; -import isArguments from './isArguments.js'; -import isArray from './isArray.js'; -import isBuffer from './isBuffer.js'; -import isIndex from './_isIndex.js'; -import isTypedArray from './isTypedArray.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ -function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), - isArg = !isArr && isArguments(value), - isBuff = !isArr && !isArg && isBuffer(value), - isType = !isArr && !isArg && !isBuff && isTypedArray(value), - skipIndexes = isArr || isArg || isBuff || isType, - result = skipIndexes ? baseTimes(value.length, String) : [], - length = result.length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && ( - // Safari 9 has enumerable `arguments.length` in strict mode. - key == 'length' || - // Node.js 0.10 has enumerable non-index properties on buffers. - (isBuff && (key == 'offset' || key == 'parent')) || - // PhantomJS 2 has enumerable non-index properties on typed arrays. - (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || - // Skip index properties. - isIndex(key, length) - ))) { - result.push(key); - } - } - return result; -} - -export default arrayLikeKeys; diff --git a/lib/lodash/_arrayPush.js b/lib/lodash/_arrayPush.js deleted file mode 100644 index 3660a7d..0000000 --- a/lib/lodash/_arrayPush.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ -function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; -} - -export default arrayPush; diff --git a/lib/lodash/_assignMergeValue.js b/lib/lodash/_assignMergeValue.js deleted file mode 100644 index 92d0916..0000000 --- a/lib/lodash/_assignMergeValue.js +++ /dev/null @@ -1,20 +0,0 @@ -import baseAssignValue from './_baseAssignValue.js'; -import eq from './eq.js'; - -/** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ -function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } -} - -export default assignMergeValue; diff --git a/lib/lodash/_assignValue.js b/lib/lodash/_assignValue.js deleted file mode 100644 index c858e92..0000000 --- a/lib/lodash/_assignValue.js +++ /dev/null @@ -1,28 +0,0 @@ -import baseAssignValue from './_baseAssignValue.js'; -import eq from './eq.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ -function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } -} - -export default assignValue; diff --git a/lib/lodash/_assocIndexOf.js b/lib/lodash/_assocIndexOf.js deleted file mode 100644 index 88afb39..0000000 --- a/lib/lodash/_assocIndexOf.js +++ /dev/null @@ -1,21 +0,0 @@ -import eq from './eq.js'; - -/** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ -function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; -} - -export default assocIndexOf; diff --git a/lib/lodash/_baseAssign.js b/lib/lodash/_baseAssign.js deleted file mode 100644 index 81ae5a5..0000000 --- a/lib/lodash/_baseAssign.js +++ /dev/null @@ -1,17 +0,0 @@ -import copyObject from './_copyObject.js'; -import keys from './keys.js'; - -/** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ -function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); -} - -export default baseAssign; diff --git a/lib/lodash/_baseAssignIn.js b/lib/lodash/_baseAssignIn.js deleted file mode 100644 index 83c6e83..0000000 --- a/lib/lodash/_baseAssignIn.js +++ /dev/null @@ -1,17 +0,0 @@ -import copyObject from './_copyObject.js'; -import keysIn from './keysIn.js'; - -/** - * The base implementation of `_.assignIn` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ -function baseAssignIn(object, source) { - return object && copyObject(source, keysIn(source), object); -} - -export default baseAssignIn; diff --git a/lib/lodash/_baseAssignValue.js b/lib/lodash/_baseAssignValue.js deleted file mode 100644 index 8d55996..0000000 --- a/lib/lodash/_baseAssignValue.js +++ /dev/null @@ -1,25 +0,0 @@ -import defineProperty from './_defineProperty.js'; - -/** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ -function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; - } -} - -export default baseAssignValue; diff --git a/lib/lodash/_baseClone.js b/lib/lodash/_baseClone.js deleted file mode 100644 index ad29619..0000000 --- a/lib/lodash/_baseClone.js +++ /dev/null @@ -1,171 +0,0 @@ -import Stack from './_Stack.js'; -import arrayEach from './_arrayEach.js'; -import assignValue from './_assignValue.js'; -import baseAssign from './_baseAssign.js'; -import baseAssignIn from './_baseAssignIn.js'; -import cloneBuffer from './_cloneBuffer.js'; -import copyArray from './_copyArray.js'; -import copySymbols from './_copySymbols.js'; -import copySymbolsIn from './_copySymbolsIn.js'; -import getAllKeys from './_getAllKeys.js'; -import getAllKeysIn from './_getAllKeysIn.js'; -import getTag from './_getTag.js'; -import initCloneArray from './_initCloneArray.js'; -import initCloneByTag from './_initCloneByTag.js'; -import initCloneObject from './_initCloneObject.js'; -import isArray from './isArray.js'; -import isBuffer from './isBuffer.js'; -import isMap from './isMap.js'; -import isObject from './isObject.js'; -import isSet from './isSet.js'; -import keys from './keys.js'; - -/** Used to compose bitmasks for cloning. */ -var CLONE_DEEP_FLAG = 1, - CLONE_FLAT_FLAG = 2, - CLONE_SYMBOLS_FLAG = 4; - -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - weakMapTag = '[object WeakMap]'; - -var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - -/** Used to identify `toStringTag` values supported by `_.clone`. */ -var cloneableTags = {}; -cloneableTags[argsTag] = cloneableTags[arrayTag] = -cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = -cloneableTags[boolTag] = cloneableTags[dateTag] = -cloneableTags[float32Tag] = cloneableTags[float64Tag] = -cloneableTags[int8Tag] = cloneableTags[int16Tag] = -cloneableTags[int32Tag] = cloneableTags[mapTag] = -cloneableTags[numberTag] = cloneableTags[objectTag] = -cloneableTags[regexpTag] = cloneableTags[setTag] = -cloneableTags[stringTag] = cloneableTags[symbolTag] = -cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = -cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; -cloneableTags[errorTag] = cloneableTags[funcTag] = -cloneableTags[weakMapTag] = false; - -/** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} bitmask The bitmask flags. - * 1 - Deep clone - * 2 - Flatten inherited properties - * 4 - Clone symbols - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ -function baseClone(value, bitmask, customizer, key, object, stack) { - var result, - isDeep = bitmask & CLONE_DEEP_FLAG, - isFlat = bitmask & CLONE_FLAT_FLAG, - isFull = bitmask & CLONE_SYMBOLS_FLAG; - - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = (isFlat || isFunc) ? {} : initCloneObject(value); - if (!isDeep) { - return isFlat - ? copySymbolsIn(value, baseAssignIn(result, value)) - : copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); - - if (isSet(value)) { - value.forEach(function(subValue) { - result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); - }); - - return result; - } - - if (isMap(value)) { - value.forEach(function(subValue, key) { - result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - - return result; - } - - var keysFunc = isFull - ? (isFlat ? getAllKeysIn : getAllKeys) - : (isFlat ? keysIn : keys); - - var props = isArr ? undefined : keysFunc(value); - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - return result; -} - -export default baseClone; diff --git a/lib/lodash/_baseCreate.js b/lib/lodash/_baseCreate.js deleted file mode 100644 index ad1da38..0000000 --- a/lib/lodash/_baseCreate.js +++ /dev/null @@ -1,30 +0,0 @@ -import isObject from './isObject.js'; - -/** Built-in value references. */ -var objectCreate = Object.create; - -/** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} proto The object to inherit from. - * @returns {Object} Returns the new object. - */ -var baseCreate = (function() { - function object() {} - return function(proto) { - if (!isObject(proto)) { - return {}; - } - if (objectCreate) { - return objectCreate(proto); - } - object.prototype = proto; - var result = new object; - object.prototype = undefined; - return result; - }; -}()); - -export default baseCreate; diff --git a/lib/lodash/_baseFor.js b/lib/lodash/_baseFor.js deleted file mode 100644 index debbcf8..0000000 --- a/lib/lodash/_baseFor.js +++ /dev/null @@ -1,16 +0,0 @@ -import createBaseFor from './_createBaseFor.js'; - -/** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ -var baseFor = createBaseFor(); - -export default baseFor; diff --git a/lib/lodash/_baseGetAllKeys.js b/lib/lodash/_baseGetAllKeys.js deleted file mode 100644 index af5533b..0000000 --- a/lib/lodash/_baseGetAllKeys.js +++ /dev/null @@ -1,20 +0,0 @@ -import arrayPush from './_arrayPush.js'; -import isArray from './isArray.js'; - -/** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ -function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); -} - -export default baseGetAllKeys; diff --git a/lib/lodash/_baseGetTag.js b/lib/lodash/_baseGetTag.js deleted file mode 100644 index 61b440a..0000000 --- a/lib/lodash/_baseGetTag.js +++ /dev/null @@ -1,28 +0,0 @@ -import Symbol from './_Symbol.js'; -import getRawTag from './_getRawTag.js'; -import objectToString from './_objectToString.js'; - -/** `Object#toString` result references. */ -var nullTag = '[object Null]', - undefinedTag = '[object Undefined]'; - -/** Built-in value references. */ -var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - -/** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ -function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); -} - -export default baseGetTag; diff --git a/lib/lodash/_baseIsArguments.js b/lib/lodash/_baseIsArguments.js deleted file mode 100644 index cbf4ca6..0000000 --- a/lib/lodash/_baseIsArguments.js +++ /dev/null @@ -1,18 +0,0 @@ -import baseGetTag from './_baseGetTag.js'; -import isObjectLike from './isObjectLike.js'; - -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]'; - -/** - * The base implementation of `_.isArguments`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - */ -function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; -} - -export default baseIsArguments; diff --git a/lib/lodash/_baseIsMap.js b/lib/lodash/_baseIsMap.js deleted file mode 100644 index 6438d2b..0000000 --- a/lib/lodash/_baseIsMap.js +++ /dev/null @@ -1,18 +0,0 @@ -import getTag from './_getTag.js'; -import isObjectLike from './isObjectLike.js'; - -/** `Object#toString` result references. */ -var mapTag = '[object Map]'; - -/** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ -function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; -} - -export default baseIsMap; diff --git a/lib/lodash/_baseIsNative.js b/lib/lodash/_baseIsNative.js deleted file mode 100644 index 04c1854..0000000 --- a/lib/lodash/_baseIsNative.js +++ /dev/null @@ -1,47 +0,0 @@ -import isFunction from './isFunction.js'; -import isMasked from './_isMasked.js'; -import isObject from './isObject.js'; -import toSource from './_toSource.js'; - -/** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ -var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - -/** Used to detect host constructors (Safari). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; - -/** Used for built-in method references. */ -var funcProto = Function.prototype, - objectProto = Object.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); - -/** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ -function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); -} - -export default baseIsNative; diff --git a/lib/lodash/_baseIsSet.js b/lib/lodash/_baseIsSet.js deleted file mode 100644 index bee4a8e..0000000 --- a/lib/lodash/_baseIsSet.js +++ /dev/null @@ -1,18 +0,0 @@ -import getTag from './_getTag.js'; -import isObjectLike from './isObjectLike.js'; - -/** `Object#toString` result references. */ -var setTag = '[object Set]'; - -/** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ -function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; -} - -export default baseIsSet; diff --git a/lib/lodash/_baseIsTypedArray.js b/lib/lodash/_baseIsTypedArray.js deleted file mode 100644 index 0a18d1c..0000000 --- a/lib/lodash/_baseIsTypedArray.js +++ /dev/null @@ -1,60 +0,0 @@ -import baseGetTag from './_baseGetTag.js'; -import isLength from './isLength.js'; -import isObjectLike from './isObjectLike.js'; - -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - weakMapTag = '[object WeakMap]'; - -var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - -/** Used to identify `toStringTag` values of typed arrays. */ -var typedArrayTags = {}; -typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = -typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = -typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = -typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = -typedArrayTags[uint32Tag] = true; -typedArrayTags[argsTag] = typedArrayTags[arrayTag] = -typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = -typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = -typedArrayTags[errorTag] = typedArrayTags[funcTag] = -typedArrayTags[mapTag] = typedArrayTags[numberTag] = -typedArrayTags[objectTag] = typedArrayTags[regexpTag] = -typedArrayTags[setTag] = typedArrayTags[stringTag] = -typedArrayTags[weakMapTag] = false; - -/** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ -function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; -} - -export default baseIsTypedArray; diff --git a/lib/lodash/_baseKeys.js b/lib/lodash/_baseKeys.js deleted file mode 100644 index 5a76224..0000000 --- a/lib/lodash/_baseKeys.js +++ /dev/null @@ -1,30 +0,0 @@ -import isPrototype from './_isPrototype.js'; -import nativeKeys from './_nativeKeys.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; -} - -export default baseKeys; diff --git a/lib/lodash/_baseKeysIn.js b/lib/lodash/_baseKeysIn.js deleted file mode 100644 index 84c1395..0000000 --- a/lib/lodash/_baseKeysIn.js +++ /dev/null @@ -1,33 +0,0 @@ -import isObject from './isObject.js'; -import isPrototype from './_isPrototype.js'; -import nativeKeysIn from './_nativeKeysIn.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; -} - -export default baseKeysIn; diff --git a/lib/lodash/_baseMerge.js b/lib/lodash/_baseMerge.js deleted file mode 100644 index 1511498..0000000 --- a/lib/lodash/_baseMerge.js +++ /dev/null @@ -1,42 +0,0 @@ -import Stack from './_Stack.js'; -import assignMergeValue from './_assignMergeValue.js'; -import baseFor from './_baseFor.js'; -import baseMergeDeep from './_baseMergeDeep.js'; -import isObject from './isObject.js'; -import keysIn from './keysIn.js'; -import safeGet from './_safeGet.js'; - -/** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ -function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - baseFor(source, function(srcValue, key) { - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) - : undefined; - - if (newValue === undefined) { - newValue = srcValue; - } - assignMergeValue(object, key, newValue); - } - }, keysIn); -} - -export default baseMerge; diff --git a/lib/lodash/_baseMergeDeep.js b/lib/lodash/_baseMergeDeep.js deleted file mode 100644 index 2c2c657..0000000 --- a/lib/lodash/_baseMergeDeep.js +++ /dev/null @@ -1,94 +0,0 @@ -import assignMergeValue from './_assignMergeValue.js'; -import cloneBuffer from './_cloneBuffer.js'; -import cloneTypedArray from './_cloneTypedArray.js'; -import copyArray from './_copyArray.js'; -import initCloneObject from './_initCloneObject.js'; -import isArguments from './isArguments.js'; -import isArray from './isArray.js'; -import isArrayLikeObject from './isArrayLikeObject.js'; -import isBuffer from './isBuffer.js'; -import isFunction from './isFunction.js'; -import isObject from './isObject.js'; -import isPlainObject from './isPlainObject.js'; -import isTypedArray from './isTypedArray.js'; -import safeGet from './_safeGet.js'; -import toPlainObject from './toPlainObject.js'; - -/** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ -function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = safeGet(object, key), - srcValue = safeGet(source, key), - stacked = stack.get(srcValue); - - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; - - if (isCommon) { - var isArr = isArray(srcValue), - isBuff = !isArr && isBuffer(srcValue), - isTyped = !isArr && !isBuff && isTypedArray(srcValue); - - newValue = srcValue; - if (isArr || isBuff || isTyped) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else if (isBuff) { - isCommon = false; - newValue = cloneBuffer(srcValue, true); - } - else if (isTyped) { - isCommon = false; - newValue = cloneTypedArray(srcValue, true); - } - else { - newValue = []; - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - newValue = objValue; - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - newValue = initCloneObject(srcValue); - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); -} - -export default baseMergeDeep; diff --git a/lib/lodash/_baseRest.js b/lib/lodash/_baseRest.js deleted file mode 100644 index a315371..0000000 --- a/lib/lodash/_baseRest.js +++ /dev/null @@ -1,17 +0,0 @@ -import identity from './identity.js'; -import overRest from './_overRest.js'; -import setToString from './_setToString.js'; - -/** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ -function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); -} - -export default baseRest; diff --git a/lib/lodash/_baseSetToString.js b/lib/lodash/_baseSetToString.js deleted file mode 100644 index e712c11..0000000 --- a/lib/lodash/_baseSetToString.js +++ /dev/null @@ -1,22 +0,0 @@ -import constant from './constant.js'; -import defineProperty from './_defineProperty.js'; -import identity from './identity.js'; - -/** - * The base implementation of `setToString` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ -var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); -}; - -export default baseSetToString; diff --git a/lib/lodash/_baseTimes.js b/lib/lodash/_baseTimes.js deleted file mode 100644 index d5d0e27..0000000 --- a/lib/lodash/_baseTimes.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ -function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; -} - -export default baseTimes; diff --git a/lib/lodash/_baseUnary.js b/lib/lodash/_baseUnary.js deleted file mode 100644 index e756a32..0000000 --- a/lib/lodash/_baseUnary.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ -function baseUnary(func) { - return function(value) { - return func(value); - }; -} - -export default baseUnary; diff --git a/lib/lodash/_cloneArrayBuffer.js b/lib/lodash/_cloneArrayBuffer.js deleted file mode 100644 index 9f33e7a..0000000 --- a/lib/lodash/_cloneArrayBuffer.js +++ /dev/null @@ -1,16 +0,0 @@ -import Uint8Array from './_Uint8Array.js'; - -/** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ -function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; -} - -export default cloneArrayBuffer; diff --git a/lib/lodash/_cloneBuffer.js b/lib/lodash/_cloneBuffer.js deleted file mode 100644 index 21b192e..0000000 --- a/lib/lodash/_cloneBuffer.js +++ /dev/null @@ -1,35 +0,0 @@ -import root from './_root.js'; - -/** Detect free variable `exports`. */ -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - -/** Detect free variable `module`. */ -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - -/** Detect the popular CommonJS extension `module.exports`. */ -var moduleExports = freeModule && freeModule.exports === freeExports; - -/** Built-in value references. */ -var Buffer = moduleExports ? root.Buffer : undefined, - allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined; - -/** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ -function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var length = buffer.length, - result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); - - buffer.copy(result); - return result; -} - -export default cloneBuffer; diff --git a/lib/lodash/_cloneDataView.js b/lib/lodash/_cloneDataView.js deleted file mode 100644 index f9b9a6f..0000000 --- a/lib/lodash/_cloneDataView.js +++ /dev/null @@ -1,16 +0,0 @@ -import cloneArrayBuffer from './_cloneArrayBuffer.js'; - -/** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ -function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); -} - -export default cloneDataView; diff --git a/lib/lodash/_cloneRegExp.js b/lib/lodash/_cloneRegExp.js deleted file mode 100644 index 0ddb49b..0000000 --- a/lib/lodash/_cloneRegExp.js +++ /dev/null @@ -1,17 +0,0 @@ -/** Used to match `RegExp` flags from their coerced string values. */ -var reFlags = /\w*$/; - -/** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ -function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; -} - -export default cloneRegExp; diff --git a/lib/lodash/_cloneSymbol.js b/lib/lodash/_cloneSymbol.js deleted file mode 100644 index 357b155..0000000 --- a/lib/lodash/_cloneSymbol.js +++ /dev/null @@ -1,18 +0,0 @@ -import Symbol from './_Symbol.js'; - -/** Used to convert symbols to primitives and strings. */ -var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; - -/** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ -function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; -} - -export default cloneSymbol; diff --git a/lib/lodash/_cloneTypedArray.js b/lib/lodash/_cloneTypedArray.js deleted file mode 100644 index 2fa9b8a..0000000 --- a/lib/lodash/_cloneTypedArray.js +++ /dev/null @@ -1,16 +0,0 @@ -import cloneArrayBuffer from './_cloneArrayBuffer.js'; - -/** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ -function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); -} - -export default cloneTypedArray; diff --git a/lib/lodash/_copyArray.js b/lib/lodash/_copyArray.js deleted file mode 100644 index b29b71e..0000000 --- a/lib/lodash/_copyArray.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ -function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; -} - -export default copyArray; diff --git a/lib/lodash/_copyObject.js b/lib/lodash/_copyObject.js deleted file mode 100644 index 4e24755..0000000 --- a/lib/lodash/_copyObject.js +++ /dev/null @@ -1,40 +0,0 @@ -import assignValue from './_assignValue.js'; -import baseAssignValue from './_baseAssignValue.js'; - -/** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ -function copyObject(source, props, object, customizer) { - var isNew = !object; - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - if (newValue === undefined) { - newValue = source[key]; - } - if (isNew) { - baseAssignValue(object, key, newValue); - } else { - assignValue(object, key, newValue); - } - } - return object; -} - -export default copyObject; diff --git a/lib/lodash/_copySymbols.js b/lib/lodash/_copySymbols.js deleted file mode 100644 index 002d8b7..0000000 --- a/lib/lodash/_copySymbols.js +++ /dev/null @@ -1,16 +0,0 @@ -import copyObject from './_copyObject.js'; -import getSymbols from './_getSymbols.js'; - -/** - * Copies own symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ -function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); -} - -export default copySymbols; diff --git a/lib/lodash/_copySymbolsIn.js b/lib/lodash/_copySymbolsIn.js deleted file mode 100644 index 12268d2..0000000 --- a/lib/lodash/_copySymbolsIn.js +++ /dev/null @@ -1,16 +0,0 @@ -import copyObject from './_copyObject.js'; -import getSymbolsIn from './_getSymbolsIn.js'; - -/** - * Copies own and inherited symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ -function copySymbolsIn(source, object) { - return copyObject(source, getSymbolsIn(source), object); -} - -export default copySymbolsIn; diff --git a/lib/lodash/_coreJsData.js b/lib/lodash/_coreJsData.js deleted file mode 100644 index 2ad4fc1..0000000 --- a/lib/lodash/_coreJsData.js +++ /dev/null @@ -1,6 +0,0 @@ -import root from './_root.js'; - -/** Used to detect overreaching core-js shims. */ -var coreJsData = root['__core-js_shared__']; - -export default coreJsData; diff --git a/lib/lodash/_createAssigner.js b/lib/lodash/_createAssigner.js deleted file mode 100644 index 67dc499..0000000 --- a/lib/lodash/_createAssigner.js +++ /dev/null @@ -1,37 +0,0 @@ -import baseRest from './_baseRest.js'; -import isIterateeCall from './_isIterateeCall.js'; - -/** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ -function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); -} - -export default createAssigner; diff --git a/lib/lodash/_createBaseFor.js b/lib/lodash/_createBaseFor.js deleted file mode 100644 index ac15c59..0000000 --- a/lib/lodash/_createBaseFor.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ -function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; -} - -export default createBaseFor; diff --git a/lib/lodash/_defineProperty.js b/lib/lodash/_defineProperty.js deleted file mode 100644 index 826fc1d..0000000 --- a/lib/lodash/_defineProperty.js +++ /dev/null @@ -1,11 +0,0 @@ -import getNative from './_getNative.js'; - -var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} -}()); - -export default defineProperty; diff --git a/lib/lodash/_freeGlobal.js b/lib/lodash/_freeGlobal.js deleted file mode 100644 index 5e383a1..0000000 --- a/lib/lodash/_freeGlobal.js +++ /dev/null @@ -1,4 +0,0 @@ -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -export default freeGlobal; diff --git a/lib/lodash/_getAllKeys.js b/lib/lodash/_getAllKeys.js deleted file mode 100644 index e9a6772..0000000 --- a/lib/lodash/_getAllKeys.js +++ /dev/null @@ -1,16 +0,0 @@ -import baseGetAllKeys from './_baseGetAllKeys.js'; -import getSymbols from './_getSymbols.js'; -import keys from './keys.js'; - -/** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ -function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); -} - -export default getAllKeys; diff --git a/lib/lodash/_getAllKeysIn.js b/lib/lodash/_getAllKeysIn.js deleted file mode 100644 index d7fac96..0000000 --- a/lib/lodash/_getAllKeysIn.js +++ /dev/null @@ -1,17 +0,0 @@ -import baseGetAllKeys from './_baseGetAllKeys.js'; -import getSymbolsIn from './_getSymbolsIn.js'; -import keysIn from './keysIn.js'; - -/** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ -function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); -} - -export default getAllKeysIn; diff --git a/lib/lodash/_getMapData.js b/lib/lodash/_getMapData.js deleted file mode 100644 index 6f55f4f..0000000 --- a/lib/lodash/_getMapData.js +++ /dev/null @@ -1,18 +0,0 @@ -import isKeyable from './_isKeyable.js'; - -/** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ -function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; -} - -export default getMapData; diff --git a/lib/lodash/_getNative.js b/lib/lodash/_getNative.js deleted file mode 100644 index d2cb438..0000000 --- a/lib/lodash/_getNative.js +++ /dev/null @@ -1,17 +0,0 @@ -import baseIsNative from './_baseIsNative.js'; -import getValue from './_getValue.js'; - -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; -} - -export default getNative; diff --git a/lib/lodash/_getPrototype.js b/lib/lodash/_getPrototype.js deleted file mode 100644 index ce92d48..0000000 --- a/lib/lodash/_getPrototype.js +++ /dev/null @@ -1,6 +0,0 @@ -import overArg from './_overArg.js'; - -/** Built-in value references. */ -var getPrototype = overArg(Object.getPrototypeOf, Object); - -export default getPrototype; diff --git a/lib/lodash/_getRawTag.js b/lib/lodash/_getRawTag.js deleted file mode 100644 index a89a35b..0000000 --- a/lib/lodash/_getRawTag.js +++ /dev/null @@ -1,46 +0,0 @@ -import Symbol from './_Symbol.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString = objectProto.toString; - -/** Built-in value references. */ -var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - -/** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ -function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; - - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; -} - -export default getRawTag; diff --git a/lib/lodash/_getSymbols.js b/lib/lodash/_getSymbols.js deleted file mode 100644 index 474442a..0000000 --- a/lib/lodash/_getSymbols.js +++ /dev/null @@ -1,30 +0,0 @@ -import arrayFilter from './_arrayFilter.js'; -import stubArray from './stubArray.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Built-in value references. */ -var propertyIsEnumerable = objectProto.propertyIsEnumerable; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeGetSymbols = Object.getOwnPropertySymbols; - -/** - * Creates an array of the own enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ -var getSymbols = !nativeGetSymbols ? stubArray : function(object) { - if (object == null) { - return []; - } - object = Object(object); - return arrayFilter(nativeGetSymbols(object), function(symbol) { - return propertyIsEnumerable.call(object, symbol); - }); -}; - -export default getSymbols; diff --git a/lib/lodash/_getSymbolsIn.js b/lib/lodash/_getSymbolsIn.js deleted file mode 100644 index 5f33b71..0000000 --- a/lib/lodash/_getSymbolsIn.js +++ /dev/null @@ -1,25 +0,0 @@ -import arrayPush from './_arrayPush.js'; -import getPrototype from './_getPrototype.js'; -import getSymbols from './_getSymbols.js'; -import stubArray from './stubArray.js'; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeGetSymbols = Object.getOwnPropertySymbols; - -/** - * Creates an array of the own and inherited enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ -var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; -}; - -export default getSymbolsIn; diff --git a/lib/lodash/_getTag.js b/lib/lodash/_getTag.js deleted file mode 100644 index 0c86db0..0000000 --- a/lib/lodash/_getTag.js +++ /dev/null @@ -1,58 +0,0 @@ -import DataView from './_DataView.js'; -import Map from './_Map.js'; -import Promise from './_Promise.js'; -import Set from './_Set.js'; -import WeakMap from './_WeakMap.js'; -import baseGetTag from './_baseGetTag.js'; -import toSource from './_toSource.js'; - -/** `Object#toString` result references. */ -var mapTag = '[object Map]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - setTag = '[object Set]', - weakMapTag = '[object WeakMap]'; - -var dataViewTag = '[object DataView]'; - -/** Used to detect maps, sets, and weakmaps. */ -var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - -/** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ -var getTag = baseGetTag; - -// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. -if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = baseGetTag(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : ''; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; -} - -export default getTag; diff --git a/lib/lodash/_getValue.js b/lib/lodash/_getValue.js deleted file mode 100644 index cbdd538..0000000 --- a/lib/lodash/_getValue.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ -function getValue(object, key) { - return object == null ? undefined : object[key]; -} - -export default getValue; diff --git a/lib/lodash/_hashClear.js b/lib/lodash/_hashClear.js deleted file mode 100644 index 5b7cc2d..0000000 --- a/lib/lodash/_hashClear.js +++ /dev/null @@ -1,15 +0,0 @@ -import nativeCreate from './_nativeCreate.js'; - -/** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ -function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; -} - -export default hashClear; diff --git a/lib/lodash/_hashDelete.js b/lib/lodash/_hashDelete.js deleted file mode 100644 index 509839f..0000000 --- a/lib/lodash/_hashDelete.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; -} - -export default hashDelete; diff --git a/lib/lodash/_hashGet.js b/lib/lodash/_hashGet.js deleted file mode 100644 index 4a3f43b..0000000 --- a/lib/lodash/_hashGet.js +++ /dev/null @@ -1,30 +0,0 @@ -import nativeCreate from './_nativeCreate.js'; - -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; -} - -export default hashGet; diff --git a/lib/lodash/_hashHas.js b/lib/lodash/_hashHas.js deleted file mode 100644 index 6db025d..0000000 --- a/lib/lodash/_hashHas.js +++ /dev/null @@ -1,23 +0,0 @@ -import nativeCreate from './_nativeCreate.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); -} - -export default hashHas; diff --git a/lib/lodash/_hashSet.js b/lib/lodash/_hashSet.js deleted file mode 100644 index 63a0115..0000000 --- a/lib/lodash/_hashSet.js +++ /dev/null @@ -1,23 +0,0 @@ -import nativeCreate from './_nativeCreate.js'; - -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; - -/** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ -function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; -} - -export default hashSet; diff --git a/lib/lodash/_initCloneArray.js b/lib/lodash/_initCloneArray.js deleted file mode 100644 index 67478a8..0000000 --- a/lib/lodash/_initCloneArray.js +++ /dev/null @@ -1,26 +0,0 @@ -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ -function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; -} - -export default initCloneArray; diff --git a/lib/lodash/_initCloneByTag.js b/lib/lodash/_initCloneByTag.js deleted file mode 100644 index 0b03f8d..0000000 --- a/lib/lodash/_initCloneByTag.js +++ /dev/null @@ -1,77 +0,0 @@ -import cloneArrayBuffer from './_cloneArrayBuffer.js'; -import cloneDataView from './_cloneDataView.js'; -import cloneRegExp from './_cloneRegExp.js'; -import cloneSymbol from './_cloneSymbol.js'; -import cloneTypedArray from './_cloneTypedArray.js'; - -/** `Object#toString` result references. */ -var boolTag = '[object Boolean]', - dateTag = '[object Date]', - mapTag = '[object Map]', - numberTag = '[object Number]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]'; - -var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - -/** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ -function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case dataViewTag: - return cloneDataView(object, isDeep); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return new Ctor; - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - return cloneRegExp(object); - - case setTag: - return new Ctor; - - case symbolTag: - return cloneSymbol(object); - } -} - -export default initCloneByTag; diff --git a/lib/lodash/_initCloneObject.js b/lib/lodash/_initCloneObject.js deleted file mode 100644 index bdcf19b..0000000 --- a/lib/lodash/_initCloneObject.js +++ /dev/null @@ -1,18 +0,0 @@ -import baseCreate from './_baseCreate.js'; -import getPrototype from './_getPrototype.js'; -import isPrototype from './_isPrototype.js'; - -/** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ -function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; -} - -export default initCloneObject; diff --git a/lib/lodash/_isIndex.js b/lib/lodash/_isIndex.js deleted file mode 100644 index b6cb47f..0000000 --- a/lib/lodash/_isIndex.js +++ /dev/null @@ -1,25 +0,0 @@ -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991; - -/** Used to detect unsigned integer values. */ -var reIsUint = /^(?:0|[1-9]\d*)$/; - -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER : length; - - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); -} - -export default isIndex; diff --git a/lib/lodash/_isIterateeCall.js b/lib/lodash/_isIterateeCall.js deleted file mode 100644 index 1fb6dc9..0000000 --- a/lib/lodash/_isIterateeCall.js +++ /dev/null @@ -1,30 +0,0 @@ -import eq from './eq.js'; -import isArrayLike from './isArrayLike.js'; -import isIndex from './_isIndex.js'; -import isObject from './isObject.js'; - -/** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ -function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; -} - -export default isIterateeCall; diff --git a/lib/lodash/_isKeyable.js b/lib/lodash/_isKeyable.js deleted file mode 100644 index 2271596..0000000 --- a/lib/lodash/_isKeyable.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ -function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); -} - -export default isKeyable; diff --git a/lib/lodash/_isMasked.js b/lib/lodash/_isMasked.js deleted file mode 100644 index e3f9d6f..0000000 --- a/lib/lodash/_isMasked.js +++ /dev/null @@ -1,20 +0,0 @@ -import coreJsData from './_coreJsData.js'; - -/** Used to detect methods masquerading as native. */ -var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; -}()); - -/** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ -function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); -} - -export default isMasked; diff --git a/lib/lodash/_isPrototype.js b/lib/lodash/_isPrototype.js deleted file mode 100644 index f6c7660..0000000 --- a/lib/lodash/_isPrototype.js +++ /dev/null @@ -1,18 +0,0 @@ -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ -function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; -} - -export default isPrototype; diff --git a/lib/lodash/_listCacheClear.js b/lib/lodash/_listCacheClear.js deleted file mode 100644 index 8cfa184..0000000 --- a/lib/lodash/_listCacheClear.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ -function listCacheClear() { - this.__data__ = []; - this.size = 0; -} - -export default listCacheClear; diff --git a/lib/lodash/_listCacheDelete.js b/lib/lodash/_listCacheDelete.js deleted file mode 100644 index b08c834..0000000 --- a/lib/lodash/_listCacheDelete.js +++ /dev/null @@ -1,35 +0,0 @@ -import assocIndexOf from './_assocIndexOf.js'; - -/** Used for built-in method references. */ -var arrayProto = Array.prototype; - -/** Built-in value references. */ -var splice = arrayProto.splice; - -/** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; -} - -export default listCacheDelete; diff --git a/lib/lodash/_listCacheGet.js b/lib/lodash/_listCacheGet.js deleted file mode 100644 index 53ce001..0000000 --- a/lib/lodash/_listCacheGet.js +++ /dev/null @@ -1,19 +0,0 @@ -import assocIndexOf from './_assocIndexOf.js'; - -/** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; -} - -export default listCacheGet; diff --git a/lib/lodash/_listCacheHas.js b/lib/lodash/_listCacheHas.js deleted file mode 100644 index 8701cae..0000000 --- a/lib/lodash/_listCacheHas.js +++ /dev/null @@ -1,16 +0,0 @@ -import assocIndexOf from './_assocIndexOf.js'; - -/** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; -} - -export default listCacheHas; diff --git a/lib/lodash/_listCacheSet.js b/lib/lodash/_listCacheSet.js deleted file mode 100644 index 8c5a198..0000000 --- a/lib/lodash/_listCacheSet.js +++ /dev/null @@ -1,26 +0,0 @@ -import assocIndexOf from './_assocIndexOf.js'; - -/** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ -function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; -} - -export default listCacheSet; diff --git a/lib/lodash/_mapCacheClear.js b/lib/lodash/_mapCacheClear.js deleted file mode 100644 index e6b3d9c..0000000 --- a/lib/lodash/_mapCacheClear.js +++ /dev/null @@ -1,21 +0,0 @@ -import Hash from './_Hash.js'; -import ListCache from './_ListCache.js'; -import Map from './_Map.js'; - -/** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ -function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; -} - -export default mapCacheClear; diff --git a/lib/lodash/_mapCacheDelete.js b/lib/lodash/_mapCacheDelete.js deleted file mode 100644 index 1afc18f..0000000 --- a/lib/lodash/_mapCacheDelete.js +++ /dev/null @@ -1,18 +0,0 @@ -import getMapData from './_getMapData.js'; - -/** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; -} - -export default mapCacheDelete; diff --git a/lib/lodash/_mapCacheGet.js b/lib/lodash/_mapCacheGet.js deleted file mode 100644 index 3b481e0..0000000 --- a/lib/lodash/_mapCacheGet.js +++ /dev/null @@ -1,16 +0,0 @@ -import getMapData from './_getMapData.js'; - -/** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function mapCacheGet(key) { - return getMapData(this, key).get(key); -} - -export default mapCacheGet; diff --git a/lib/lodash/_mapCacheHas.js b/lib/lodash/_mapCacheHas.js deleted file mode 100644 index 9de3e7f..0000000 --- a/lib/lodash/_mapCacheHas.js +++ /dev/null @@ -1,16 +0,0 @@ -import getMapData from './_getMapData.js'; - -/** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function mapCacheHas(key) { - return getMapData(this, key).has(key); -} - -export default mapCacheHas; diff --git a/lib/lodash/_mapCacheSet.js b/lib/lodash/_mapCacheSet.js deleted file mode 100644 index e757c36..0000000 --- a/lib/lodash/_mapCacheSet.js +++ /dev/null @@ -1,22 +0,0 @@ -import getMapData from './_getMapData.js'; - -/** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ -function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; -} - -export default mapCacheSet; diff --git a/lib/lodash/_nativeCreate.js b/lib/lodash/_nativeCreate.js deleted file mode 100644 index 27b476b..0000000 --- a/lib/lodash/_nativeCreate.js +++ /dev/null @@ -1,6 +0,0 @@ -import getNative from './_getNative.js'; - -/* Built-in method references that are verified to be native. */ -var nativeCreate = getNative(Object, 'create'); - -export default nativeCreate; diff --git a/lib/lodash/_nativeKeys.js b/lib/lodash/_nativeKeys.js deleted file mode 100644 index 2ec8ec6..0000000 --- a/lib/lodash/_nativeKeys.js +++ /dev/null @@ -1,6 +0,0 @@ -import overArg from './_overArg.js'; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeKeys = overArg(Object.keys, Object); - -export default nativeKeys; diff --git a/lib/lodash/_nativeKeysIn.js b/lib/lodash/_nativeKeysIn.js deleted file mode 100644 index 94eda99..0000000 --- a/lib/lodash/_nativeKeysIn.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; -} - -export default nativeKeysIn; diff --git a/lib/lodash/_nodeUtil.js b/lib/lodash/_nodeUtil.js deleted file mode 100644 index 4673316..0000000 --- a/lib/lodash/_nodeUtil.js +++ /dev/null @@ -1,22 +0,0 @@ -import freeGlobal from './_freeGlobal.js'; - -/** Detect free variable `exports`. */ -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - -/** Detect free variable `module`. */ -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - -/** Detect the popular CommonJS extension `module.exports`. */ -var moduleExports = freeModule && freeModule.exports === freeExports; - -/** Detect free variable `process` from Node.js. */ -var freeProcess = moduleExports && freeGlobal.process; - -/** Used to access faster Node.js helpers. */ -var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} -}()); - -export default nodeUtil; diff --git a/lib/lodash/_objectToString.js b/lib/lodash/_objectToString.js deleted file mode 100644 index 749a5f9..0000000 --- a/lib/lodash/_objectToString.js +++ /dev/null @@ -1,22 +0,0 @@ -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString = objectProto.toString; - -/** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ -function objectToString(value) { - return nativeObjectToString.call(value); -} - -export default objectToString; diff --git a/lib/lodash/_overArg.js b/lib/lodash/_overArg.js deleted file mode 100644 index 93bafe3..0000000 --- a/lib/lodash/_overArg.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ -function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; -} - -export default overArg; diff --git a/lib/lodash/_overRest.js b/lib/lodash/_overRest.js deleted file mode 100644 index f4f79cb..0000000 --- a/lib/lodash/_overRest.js +++ /dev/null @@ -1,36 +0,0 @@ -import apply from './_apply.js'; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeMax = Math.max; - -/** - * A specialized version of `baseRest` which transforms the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. - */ -function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; -} - -export default overRest; diff --git a/lib/lodash/_root.js b/lib/lodash/_root.js deleted file mode 100644 index 281f812..0000000 --- a/lib/lodash/_root.js +++ /dev/null @@ -1,9 +0,0 @@ -import freeGlobal from './_freeGlobal.js'; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -export default root; diff --git a/lib/lodash/_safeGet.js b/lib/lodash/_safeGet.js deleted file mode 100644 index be5bfc3..0000000 --- a/lib/lodash/_safeGet.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Gets the value at `key`, unless `key` is "__proto__". - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ -function safeGet(object, key) { - return key == '__proto__' - ? undefined - : object[key]; -} - -export default safeGet; diff --git a/lib/lodash/_setToString.js b/lib/lodash/_setToString.js deleted file mode 100644 index db2dd26..0000000 --- a/lib/lodash/_setToString.js +++ /dev/null @@ -1,14 +0,0 @@ -import baseSetToString from './_baseSetToString.js'; -import shortOut from './_shortOut.js'; - -/** - * Sets the `toString` method of `func` to return `string`. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ -var setToString = shortOut(baseSetToString); - -export default setToString; diff --git a/lib/lodash/_shortOut.js b/lib/lodash/_shortOut.js deleted file mode 100644 index 78fadcd..0000000 --- a/lib/lodash/_shortOut.js +++ /dev/null @@ -1,37 +0,0 @@ -/** Used to detect hot functions by number of calls within a span of milliseconds. */ -var HOT_COUNT = 800, - HOT_SPAN = 16; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeNow = Date.now; - -/** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. - * - * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable function. - */ -function shortOut(func) { - var count = 0, - lastCalled = 0; - - return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; - } - return func.apply(undefined, arguments); - }; -} - -export default shortOut; diff --git a/lib/lodash/_stackClear.js b/lib/lodash/_stackClear.js deleted file mode 100644 index d4b10b0..0000000 --- a/lib/lodash/_stackClear.js +++ /dev/null @@ -1,15 +0,0 @@ -import ListCache from './_ListCache.js'; - -/** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ -function stackClear() { - this.__data__ = new ListCache; - this.size = 0; -} - -export default stackClear; diff --git a/lib/lodash/_stackDelete.js b/lib/lodash/_stackDelete.js deleted file mode 100644 index c3df897..0000000 --- a/lib/lodash/_stackDelete.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function stackDelete(key) { - var data = this.__data__, - result = data['delete'](key); - - this.size = data.size; - return result; -} - -export default stackDelete; diff --git a/lib/lodash/_stackGet.js b/lib/lodash/_stackGet.js deleted file mode 100644 index 139b9ac..0000000 --- a/lib/lodash/_stackGet.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function stackGet(key) { - return this.__data__.get(key); -} - -export default stackGet; diff --git a/lib/lodash/_stackHas.js b/lib/lodash/_stackHas.js deleted file mode 100644 index bc25f5a..0000000 --- a/lib/lodash/_stackHas.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function stackHas(key) { - return this.__data__.has(key); -} - -export default stackHas; diff --git a/lib/lodash/_stackSet.js b/lib/lodash/_stackSet.js deleted file mode 100644 index a85af6c..0000000 --- a/lib/lodash/_stackSet.js +++ /dev/null @@ -1,34 +0,0 @@ -import ListCache from './_ListCache.js'; -import Map from './_Map.js'; -import MapCache from './_MapCache.js'; - -/** Used as the size to enable large array optimizations. */ -var LARGE_ARRAY_SIZE = 200; - -/** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ -function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); - } - data.set(key, value); - this.size = data.size; - return this; -} - -export default stackSet; diff --git a/lib/lodash/_toSource.js b/lib/lodash/_toSource.js deleted file mode 100644 index 2696f7a..0000000 --- a/lib/lodash/_toSource.js +++ /dev/null @@ -1,26 +0,0 @@ -/** Used for built-in method references. */ -var funcProto = Function.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ -function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; -} - -export default toSource; diff --git a/lib/lodash/cloneDeep.js b/lib/lodash/cloneDeep.js deleted file mode 100644 index 44d403d..0000000 --- a/lib/lodash/cloneDeep.js +++ /dev/null @@ -1,29 +0,0 @@ -import baseClone from './_baseClone.js'; - -/** Used to compose bitmasks for cloning. */ -var CLONE_DEEP_FLAG = 1, - CLONE_SYMBOLS_FLAG = 4; - -/** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ -function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); -} - -export default cloneDeep; diff --git a/lib/lodash/constant.js b/lib/lodash/constant.js deleted file mode 100644 index c8dac98..0000000 --- a/lib/lodash/constant.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Creates a function that returns `value`. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Util - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new constant function. - * @example - * - * var objects = _.times(2, _.constant({ 'a': 1 })); - * - * console.log(objects); - * // => [{ 'a': 1 }, { 'a': 1 }] - * - * console.log(objects[0] === objects[1]); - * // => true - */ -function constant(value) { - return function() { - return value; - }; -} - -export default constant; diff --git a/lib/lodash/eq.js b/lib/lodash/eq.js deleted file mode 100644 index c3206c6..0000000 --- a/lib/lodash/eq.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ -function eq(value, other) { - return value === other || (value !== value && other !== other); -} - -export default eq; diff --git a/lib/lodash/identity.js b/lib/lodash/identity.js deleted file mode 100644 index ed074d8..0000000 --- a/lib/lodash/identity.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * This method returns the first argument it receives. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'a': 1 }; - * - * console.log(_.identity(object) === object); - * // => true - */ -function identity(value) { - return value; -} - -export default identity; diff --git a/lib/lodash/index.js b/lib/lodash/index.js deleted file mode 100644 index 00411d2..0000000 --- a/lib/lodash/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Lodash (Custom Build) - * Build: `lodash modularize exports="es" include="isLength,cloneDeep,merge" -o lib/lodash -p` - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -export {default as isLength} from './isLength.js'; -export {default as cloneDeep} from './cloneDeep.js'; -export {default as merge} from './merge.js'; diff --git a/lib/lodash/isArguments.js b/lib/lodash/isArguments.js deleted file mode 100644 index 6c49fe5..0000000 --- a/lib/lodash/isArguments.js +++ /dev/null @@ -1,36 +0,0 @@ -import baseIsArguments from './_baseIsArguments.js'; -import isObjectLike from './isObjectLike.js'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** Built-in value references. */ -var propertyIsEnumerable = objectProto.propertyIsEnumerable; - -/** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ -var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); -}; - -export default isArguments; diff --git a/lib/lodash/isArray.js b/lib/lodash/isArray.js deleted file mode 100644 index 5643c19..0000000 --- a/lib/lodash/isArray.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ -var isArray = Array.isArray; - -export default isArray; diff --git a/lib/lodash/isArrayLike.js b/lib/lodash/isArrayLike.js deleted file mode 100644 index f763abd..0000000 --- a/lib/lodash/isArrayLike.js +++ /dev/null @@ -1,33 +0,0 @@ -import isFunction from './isFunction.js'; -import isLength from './isLength.js'; - -/** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ -function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); -} - -export default isArrayLike; diff --git a/lib/lodash/isArrayLikeObject.js b/lib/lodash/isArrayLikeObject.js deleted file mode 100644 index 0332da4..0000000 --- a/lib/lodash/isArrayLikeObject.js +++ /dev/null @@ -1,33 +0,0 @@ -import isArrayLike from './isArrayLike.js'; -import isObjectLike from './isObjectLike.js'; - -/** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ -function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); -} - -export default isArrayLikeObject; diff --git a/lib/lodash/isBuffer.js b/lib/lodash/isBuffer.js deleted file mode 100644 index d7ba078..0000000 --- a/lib/lodash/isBuffer.js +++ /dev/null @@ -1,38 +0,0 @@ -import root from './_root.js'; -import stubFalse from './stubFalse.js'; - -/** Detect free variable `exports`. */ -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - -/** Detect free variable `module`. */ -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - -/** Detect the popular CommonJS extension `module.exports`. */ -var moduleExports = freeModule && freeModule.exports === freeExports; - -/** Built-in value references. */ -var Buffer = moduleExports ? root.Buffer : undefined; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; - -/** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ -var isBuffer = nativeIsBuffer || stubFalse; - -export default isBuffer; diff --git a/lib/lodash/isFunction.js b/lib/lodash/isFunction.js deleted file mode 100644 index 57c133d..0000000 --- a/lib/lodash/isFunction.js +++ /dev/null @@ -1,37 +0,0 @@ -import baseGetTag from './_baseGetTag.js'; -import isObject from './isObject.js'; - -/** `Object#toString` result references. */ -var asyncTag = '[object AsyncFunction]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - proxyTag = '[object Proxy]'; - -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; -} - -export default isFunction; diff --git a/lib/lodash/isLength.js b/lib/lodash/isLength.js deleted file mode 100644 index 2acf24e..0000000 --- a/lib/lodash/isLength.js +++ /dev/null @@ -1,35 +0,0 @@ -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991; - -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ -function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} - -export default isLength; diff --git a/lib/lodash/isMap.js b/lib/lodash/isMap.js deleted file mode 100644 index d867dfa..0000000 --- a/lib/lodash/isMap.js +++ /dev/null @@ -1,27 +0,0 @@ -import baseIsMap from './_baseIsMap.js'; -import baseUnary from './_baseUnary.js'; -import nodeUtil from './_nodeUtil.js'; - -/* Node.js helper references. */ -var nodeIsMap = nodeUtil && nodeUtil.isMap; - -/** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ -var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - -export default isMap; diff --git a/lib/lodash/isObject.js b/lib/lodash/isObject.js deleted file mode 100644 index ddfebd5..0000000 --- a/lib/lodash/isObject.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); -} - -export default isObject; diff --git a/lib/lodash/isObjectLike.js b/lib/lodash/isObjectLike.js deleted file mode 100644 index 0e931b1..0000000 --- a/lib/lodash/isObjectLike.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return value != null && typeof value == 'object'; -} - -export default isObjectLike; diff --git a/lib/lodash/isPlainObject.js b/lib/lodash/isPlainObject.js deleted file mode 100644 index 45ec39f..0000000 --- a/lib/lodash/isPlainObject.js +++ /dev/null @@ -1,62 +0,0 @@ -import baseGetTag from './_baseGetTag.js'; -import getPrototype from './_getPrototype.js'; -import isObjectLike from './isObjectLike.js'; - -/** `Object#toString` result references. */ -var objectTag = '[object Object]'; - -/** Used for built-in method references. */ -var funcProto = Function.prototype, - objectProto = Object.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** Used to infer the `Object` constructor. */ -var objectCtorString = funcToString.call(Object); - -/** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ -function isPlainObject(value) { - if (!isObjectLike(value) || baseGetTag(value) != objectTag) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor == 'function' && Ctor instanceof Ctor && - funcToString.call(Ctor) == objectCtorString; -} - -export default isPlainObject; diff --git a/lib/lodash/isSet.js b/lib/lodash/isSet.js deleted file mode 100644 index 78c8198..0000000 --- a/lib/lodash/isSet.js +++ /dev/null @@ -1,27 +0,0 @@ -import baseIsSet from './_baseIsSet.js'; -import baseUnary from './_baseUnary.js'; -import nodeUtil from './_nodeUtil.js'; - -/* Node.js helper references. */ -var nodeIsSet = nodeUtil && nodeUtil.isSet; - -/** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ -var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - -export default isSet; diff --git a/lib/lodash/isTypedArray.js b/lib/lodash/isTypedArray.js deleted file mode 100644 index 8cffbef..0000000 --- a/lib/lodash/isTypedArray.js +++ /dev/null @@ -1,27 +0,0 @@ -import baseIsTypedArray from './_baseIsTypedArray.js'; -import baseUnary from './_baseUnary.js'; -import nodeUtil from './_nodeUtil.js'; - -/* Node.js helper references. */ -var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - -/** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ -var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - -export default isTypedArray; diff --git a/lib/lodash/keys.js b/lib/lodash/keys.js deleted file mode 100644 index fd7089b..0000000 --- a/lib/lodash/keys.js +++ /dev/null @@ -1,37 +0,0 @@ -import arrayLikeKeys from './_arrayLikeKeys.js'; -import baseKeys from './_baseKeys.js'; -import isArrayLike from './isArrayLike.js'; - -/** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ -function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); -} - -export default keys; diff --git a/lib/lodash/keysIn.js b/lib/lodash/keysIn.js deleted file mode 100644 index a77147a..0000000 --- a/lib/lodash/keysIn.js +++ /dev/null @@ -1,32 +0,0 @@ -import arrayLikeKeys from './_arrayLikeKeys.js'; -import baseKeysIn from './_baseKeysIn.js'; -import isArrayLike from './isArrayLike.js'; - -/** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ -function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); -} - -export default keysIn; diff --git a/lib/lodash/lang.default.js b/lib/lodash/lang.default.js deleted file mode 100644 index 15c17c6..0000000 --- a/lib/lodash/lang.default.js +++ /dev/null @@ -1,23 +0,0 @@ -import cloneDeep from './cloneDeep.js'; -import eq from './eq.js'; -import isArguments from './isArguments.js'; -import isArray from './isArray.js'; -import isArrayLike from './isArrayLike.js'; -import isArrayLikeObject from './isArrayLikeObject.js'; -import isBuffer from './isBuffer.js'; -import isFunction from './isFunction.js'; -import isLength from './isLength.js'; -import isMap from './isMap.js'; -import isObject from './isObject.js'; -import isObjectLike from './isObjectLike.js'; -import isPlainObject from './isPlainObject.js'; -import isSet from './isSet.js'; -import isTypedArray from './isTypedArray.js'; -import toPlainObject from './toPlainObject.js'; - -export default { - cloneDeep, eq, isArguments, isArray, isArrayLike, - isArrayLikeObject, isBuffer, isFunction, isLength, isMap, - isObject, isObjectLike, isPlainObject, isSet, isTypedArray, - toPlainObject -}; diff --git a/lib/lodash/lang.js b/lib/lodash/lang.js deleted file mode 100644 index 4817b80..0000000 --- a/lib/lodash/lang.js +++ /dev/null @@ -1,17 +0,0 @@ -export { default as cloneDeep } from './cloneDeep.js'; -export { default as eq } from './eq.js'; -export { default as isArguments } from './isArguments.js'; -export { default as isArray } from './isArray.js'; -export { default as isArrayLike } from './isArrayLike.js'; -export { default as isArrayLikeObject } from './isArrayLikeObject.js'; -export { default as isBuffer } from './isBuffer.js'; -export { default as isFunction } from './isFunction.js'; -export { default as isLength } from './isLength.js'; -export { default as isMap } from './isMap.js'; -export { default as isObject } from './isObject.js'; -export { default as isObjectLike } from './isObjectLike.js'; -export { default as isPlainObject } from './isPlainObject.js'; -export { default as isSet } from './isSet.js'; -export { default as isTypedArray } from './isTypedArray.js'; -export { default as toPlainObject } from './toPlainObject.js'; -export { default } from './lang.default.js'; diff --git a/lib/lodash/merge.js b/lib/lodash/merge.js deleted file mode 100644 index 9aab628..0000000 --- a/lib/lodash/merge.js +++ /dev/null @@ -1,39 +0,0 @@ -import baseMerge from './_baseMerge.js'; -import createAssigner from './_createAssigner.js'; - -/** - * This method is like `_.assign` except that it recursively merges own and - * inherited enumerable string keyed properties of source objects into the - * destination object. Source properties that resolve to `undefined` are - * skipped if a destination value exists. Array and plain object properties - * are merged recursively. Other objects and value types are overridden by - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ -var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); -}); - -export default merge; diff --git a/lib/lodash/object.default.js b/lib/lodash/object.default.js deleted file mode 100644 index be234ec..0000000 --- a/lib/lodash/object.default.js +++ /dev/null @@ -1,7 +0,0 @@ -import keys from './keys.js'; -import keysIn from './keysIn.js'; -import merge from './merge.js'; - -export default { - keys, keysIn, merge -}; diff --git a/lib/lodash/object.js b/lib/lodash/object.js deleted file mode 100644 index 372b961..0000000 --- a/lib/lodash/object.js +++ /dev/null @@ -1,4 +0,0 @@ -export { default as keys } from './keys.js'; -export { default as keysIn } from './keysIn.js'; -export { default as merge } from './merge.js'; -export { default } from './object.default.js'; diff --git a/lib/lodash/stubArray.js b/lib/lodash/stubArray.js deleted file mode 100644 index b2b5503..0000000 --- a/lib/lodash/stubArray.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * This method returns a new empty array. - * - * @static - * @memberOf _ - * @since 4.13.0 - * @category Util - * @returns {Array} Returns the new empty array. - * @example - * - * var arrays = _.times(2, _.stubArray); - * - * console.log(arrays); - * // => [[], []] - * - * console.log(arrays[0] === arrays[1]); - * // => false - */ -function stubArray() { - return []; -} - -export default stubArray; diff --git a/lib/lodash/stubFalse.js b/lib/lodash/stubFalse.js deleted file mode 100644 index c569c25..0000000 --- a/lib/lodash/stubFalse.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * This method returns `false`. - * - * @static - * @memberOf _ - * @since 4.13.0 - * @category Util - * @returns {boolean} Returns `false`. - * @example - * - * _.times(2, _.stubFalse); - * // => [false, false] - */ -function stubFalse() { - return false; -} - -export default stubFalse; diff --git a/lib/lodash/toPlainObject.js b/lib/lodash/toPlainObject.js deleted file mode 100644 index b4e9129..0000000 --- a/lib/lodash/toPlainObject.js +++ /dev/null @@ -1,32 +0,0 @@ -import copyObject from './_copyObject.js'; -import keysIn from './keysIn.js'; - -/** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ -function toPlainObject(value) { - return copyObject(value, keysIn(value)); -} - -export default toPlainObject; diff --git a/lib/lodash/util.default.js b/lib/lodash/util.default.js deleted file mode 100644 index 60483cb..0000000 --- a/lib/lodash/util.default.js +++ /dev/null @@ -1,8 +0,0 @@ -import constant from './constant.js'; -import identity from './identity.js'; -import stubArray from './stubArray.js'; -import stubFalse from './stubFalse.js'; - -export default { - constant, identity, stubArray, stubFalse -}; diff --git a/lib/lodash/util.js b/lib/lodash/util.js deleted file mode 100644 index e8e68e0..0000000 --- a/lib/lodash/util.js +++ /dev/null @@ -1,5 +0,0 @@ -export { default as constant } from './constant.js'; -export { default as identity } from './identity.js'; -export { default as stubArray } from './stubArray.js'; -export { default as stubFalse } from './stubFalse.js'; -export { default } from './util.default.js'; diff --git a/lib/themeUtils.js b/lib/themeUtils.js index c00bf40..568ed62 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -1,4 +1,3 @@ -import {cloneDeep, merge} from './lodash/index.js'; import * as pluginRegistry from './pluginRegistry.js'; function freezeTheme(theme) { @@ -121,8 +120,10 @@ function normalizePlugins(plugins) { }; } - // eslint-disable-next-line unicorn/no-array-reduce - const theme = freezeTheme(themes.reduce((acc, pluginTheme) => merge(acc, pluginTheme), cloneDeep(defaultTheme))); + const theme = freezeTheme({ + ...structuredClone(defaultTheme), + ...Object.assign({}, ...themes), + }); normalizedPluginThemes.set(ref, theme); return {ref, theme}; } @@ -146,12 +147,12 @@ export function normalize(options) { return entry.withPlugins.get(normalizedPlugins.ref); } - const theme = freezeTheme(merge(cloneDeep(normalizedPlugins.theme), options.theme)); + const theme = freezeTheme({...structuredClone(defaultTheme), ...options.theme}); entry.withPlugins.set(normalizedPlugins.ref, theme); return theme; } - entry.theme ||= freezeTheme(merge(cloneDeep(defaultTheme), options.theme)); + entry.theme ||= freezeTheme({...structuredClone(defaultTheme), ...options.theme}); return entry.theme; } @@ -183,7 +184,7 @@ export function applyModifiers(descriptor, theme) { return cache.get(previous); } - const modifiedTheme = cloneDeep(previous); + const modifiedTheme = structuredClone(previous); modifier(modifiedTheme); freezeTheme(modifiedTheme); cache.set(previous, modifiedTheme); diff --git a/package.json b/package.json index d611d1a..54f11ed 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,6 @@ "xo": "^0.59.0" }, "xo": { - "ignores": [ - "lib/lodash" - ], "rules": { "import/order": [ "error", From f3fc13566810a7cd9599e945d002b11ac63ef8ea Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 21 Jul 2024 16:33:07 -0500 Subject: [PATCH 11/13] fix c8 config --- .c8rc.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.c8rc.json b/.c8rc.json index 4711308..87ea274 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,9 +1,7 @@ { "all": true, "exclude": [ - "{coverage,test}/**", - ".xo-config.cjs", - "lib/lodash" + "{coverage,test}/**" ], "reporter": [ "html", From 56e7ff2748ce00a8d6e41861a8048901ecea5536 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 21 Jul 2024 16:50:55 -0500 Subject: [PATCH 12/13] update `well-known-symbols` --- lib/primitiveValues/symbol.js | 4 +--- package.json | 2 +- test/format.js | 1 + test/snapshots/format.js.md | 8 +++++++- test/snapshots/format.js.snap | Bin 3438 -> 3460 bytes 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/primitiveValues/symbol.js b/lib/primitiveValues/symbol.js index 8a2f636..0243706 100644 --- a/lib/primitiveValues/symbol.js +++ b/lib/primitiveValues/symbol.js @@ -1,5 +1,5 @@ +import 'well-known-symbols/auto'; // eslint-disable-line import/no-unassigned-import import stringEscape from 'js-string-escape'; -import wellKnownSymbols from 'well-known-symbols'; import {DEEP_EQUAL, UNEQUAL} from '../constants.js'; import * as formatUtils from '../formatUtils.js'; @@ -11,8 +11,6 @@ export function describe(value) { const key = Symbol.keyFor(value); if (key !== undefined) { stringCompare = `Symbol.for(${stringEscape(key)})`; - } else if (wellKnownSymbols.isWellKnown(value)) { - stringCompare = wellKnownSymbols.getLabel(value); } return new SymbolValue({ diff --git a/package.json b/package.json index 54f11ed..39cca1a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "js-string-escape": "^1.0.1", "md5-hex": "^5.0.0", "semver": "^7.6.3", - "well-known-symbols": "^2.0.0" + "well-known-symbols": "^4.0.0" }, "devDependencies": { "@types/node": "18.18", diff --git a/test/format.js b/test/format.js index 8c7879f..0e72727 100644 --- a/test/format.js +++ b/test/format.js @@ -73,6 +73,7 @@ for (const value of [ Symbol.for('bar'), Symbol.for('bar\nbaz'), Symbol.iterator, + Symbol.matchAll, ]) { test(formatsPrimitive, value); } diff --git a/test/snapshots/format.js.md b/test/snapshots/format.js.md index c0f726e..d54c18e 100644 --- a/test/snapshots/format.js.md +++ b/test/snapshots/format.js.md @@ -143,7 +143,13 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - '%symbol.open%Symbol.iterator%symbol.close%' + '%symbol.open%Symbol(Symbol.iterator)%symbol.close%' + +## formats primitive: Symbol(Symbol.matchAll) + +> Snapshot 1 + + '%symbol.open%Symbol(Symbol.matchAll)%symbol.close%' ## formats primitive: 42n diff --git a/test/snapshots/format.js.snap b/test/snapshots/format.js.snap index 108457c5e0e2fa15db926663445d843a76df2bff..f40f23626b867c97f62b72db43d1f1155ff48917 100644 GIT binary patch literal 3460 zcmV-~4SVuIRzVz%o?vC~%2N)-@VsD#9;@Szp(flo;M5q#nUUn+qBp-M;~!C$~r z^Yk3gx%0BUyB<$JH0zl;_nh-PuY1ot?)%NU${HKS4_hBlu5gv!ZZf@1xFL0PrLAyf zi=L7+Q&km1BOPO%apR5mWtniYa(Hg$-Wlt^(mgYuDebFRSIx5y)$G5VpAD56wBiok z-H(iIYBFsq8kNHgo&pSxRQyXFF8WrzBXbvZv#y>wbXqzfmY%T^TIxnv!1gya{t~2$D(%`1Zr{7`E-!gMK^n&LU=17l z7#RB@Fm_EaI3{;(A)VZ{1$1bR42_I@1dO~NjEoQ5-G_{PNoy*a!h2x`i-18HFz~2w zKA4Bs#Eg~zqeme|k(@9SUnZB+nfNlfoE)yJy>^|chYrWXW!P6bEIcajAmoE3UYDZD z7{Y29uzCz*Wf9`s%8}gcGKjD|30NK#uym+XYl*WQoJ)pT&NrEUNX#)pQ>#X5b#ez` z`wU=vJc6w=0?zx0n72EK!l_O;!!$nwL|DSW9vmdA6m7yA>t|JUC@K6wP${q=U0%}S zgS4)+E@|A$@tXHLb~0Z>M+cLY(!*f%nrQg$erhyGhZ<5*qWkqXAoJoA0wgW4M zHytK$Qvb21SF5L;6R&_1AAfqa`q8_0_nZ!KIhcvdK@pdOIG43dT-HQf)&Q4hJuZf# zwN$!kGENOi(IlqPnl%BCoEd>3-B$Rz#axnUlb9+G3Gx9ZNOiSZr7EdYb<D@c8Hy7%BLi_z{1vM!r3QSlJ!R?O-}XlF^j9UXv)a7PV{VCJqYYeJPcm={ccKv1}27GsvZwq2m@i9Zvrvo4hrbUMEaQ2e@&VuLex4Rg-vLxK~I%#s-L*oJAG zA_s(u;QiEhKxzBhIMhJ8vT<7M6Ka7q3%&_-xD(dlvb~f{r$SUWBToGNLh;dN$G3p| zuZ~{+P{$-Y{#Zk0?D!9MW#YttP$)hk{WpO0z0pgbQus%N!i(EA@!4otCGeh4oGu5& zek4}rU7*YxV^BuW!O9-iXoG9)VIAs{Wmf>b8TD&mh@T;bxM~;QbQ+B2mR5FE(N09H zto3!BQS-n)oRWvUC%zj6)a1Jo8WGRdJ#m|36gyO4iNvtOhr`;h~doE5>~NLlPh@+QT+}j z=^%53ISP<_WiC8d_#)}-#6+ReCY=i!*Mm+cJ#%_=-7bH8q%pkfJJp%N5kJ?G0G+tO z8%%G}p=>M0zolEZr?Q%$Mf8r^8=Do9HcTIjzh7VlYB)}39|dvxx!KXh>27)SFO&=g zQ5;H!aj`J*w=`0_Sv8pS6U`a@O8P6{XYV6x$FzR7Ly1!`o0;6|6m4_A&Ks0tb`7ls z!aV_+vduBBWkXaA-u@1OIQtJw!V+eF@%&a`xo3gp7Di~fyiJ1>CPfS9bV>0AV1j2x zV1ga;Drp(+qC#oIqmEvlcqbynOP7DZbAYoKk^J*A zZC&W5od1svfZ*V}zscWsBcd^_*Jh@jk{TR$BQTLFDHZS1c}JLQ#Fh4aWtSVO(|`4gwG{&~M`-a9D#}+J(&Q_E7~eTMC{r5mS@{cap5GzQz@?UVSH4iw zw;WS6PLX;@8_V$s# zaBV1h!|pKXv`KZUHL#d`3#5?SLKwZlL^yiq%Qw%vf8845t(&vf6CLNwW|Jbbgt_}c z?EDY8>lvU=vmD{Q4wY@%`Ff92x1S-?25Hub96s$0SJ3SSy8K%(y74)WL{F;O-P}(= zV7-Gp_EQAb6w>A2g1hW~N@SS(FJ!q9e&)KO@u$w>&p^(7354_)kdTgu=Ge7zpLK!- zbCDZzNSA*LMn~fl;%H1)d;bao^}`}i3%Vju^IF9H4$*Vg7jYDN8%YSC1PS5a$ST(( zE@tA>LYIFFCVchHbNzHR_D3M3?jkj|2&rkK%fAIDs4n{7hP|jV!XIA}t!h6F0(k}r zFODtR9W<^Lj`);@U=$kRfXe+x#}$XYmd(pAX! zKv=zvRLCN%rjIWF7M#%fDDJi5AizK~Q}gFOEe}O&4AMEjU57(SKRfdbV8L zT#bKOGeBR2^0d(9-+~EW)(m+6s9)AB0&5EC@^8UOt&!peYqAxxQ6n?8 zSd-PrBCw{6F8>yspc<(Mqg>czjlTyOe#N;6R((BCMv5F8>ys zp!(STJP7jhDrtKvApyM?1oSpO*$sQ;7a)>v%i-N8jCFR~+A~3`y=Y%3anh2MW^msGXYU2YkYuH4f7qG#k$%hd6d8ER zE6B@V#wOHA=78;Kp`r@ttfE2mLof;8A;X zq=jyj_5g+dg(&=z+0CXf++!@meiEOFpU&cjuI!puIa(^K6E!T`Eg;*A73Vs~9M9W- zdxwUQqWgd&hEus($`;k6j%v0PEj&Fq0R%d9-ZVICJNw(5asGML`Zhk3=_#pt<%R3d mU%Fg9w&!)1`Y512&?j(r4LK!M?M+fFlK%tBH$qqTrT_rUqmq*V literal 3438 zcmV-!4UzIeRzV~Pki7@B@iHlgai`&1w8M} zotd4pbMCx$*Y?g%KQ!K%d+s^scV73Nc|EC>Wwmlo|3U33F(gAK>orwth=wjSHK`#P z(i%A_C@oo*bVY3HE2^Qt{iIqI4RP_%#Mm=q=6|^zW1q_HDVU?C)h1D_zu3=;tm>p- zPu<>&%-vF|q$Vk(>Su5qFgRRrhcYhiPtOU+Z#TlPCdxYT^O^y?CJSX%m5Hb@P8N-O z2=Kt*GPD-L;V9s60CF%%a0Z&6fq(8d!QAHyx}ix*eOjiNSo7zL1?QN>&iTPOf#KF6 zI^Jf#hC!&Rei3d05iW&_KqrYVMSDLY#*$Df2}SdNlYVi&48*w>D$bH;wit39z~Na^ z%A&SZ7Vj4k(f;5SZTvT54ueKZHYAISZit$ZUycY^MO6$XETvjFqbM(a2tfXIRNvbykb6X~&)c3vGKeM`YC_E&YLq(`7V~pTcvzIB`ens%vZ~_z4qZN%(AmNA zAol{8y~LZoy_e_}u}O5gvJ)#6RjbnKAsDJ)tdNFhjs6Z}0+-Pr`P@?RG&^w%ocJg` zK}-J5(>^YfiMUMixJ=?)mJ@MV=5bjDTwZgy=yZCSthQ8x{*V+wRY=J!xdN-fy09)8 zD<*S+ZoWiXkbQzY#RMrX6^ld`%S2wKqgrxRC=-G4tTF<)lXzy?!g`s}v}_thHN14T z?57>s%VOo8A<=EEDY&&*NF@3jK$3~#axqW}4Bll1?=n~At~d}W?v18Q1hxDXQZbNq zGT3&HKc6eGkya!uXjE}xU+|ppXA?|t)Y=Szo zi#3`-@>3>PbDNToE6sw*xH=G6LmUhqx=G-LZg8grh3E#U@-I+J~d+3Zds!r~PrXSTZ=X1h&KC+^y_thQ+m z3GXd_2cY;h7sU$Igo(PqI)C57?ifJ4nhs24;rS$9jVu3DS7cq#<-55mOX%M~AOFMJco|DgZ!`+5|~@yA*i1INF+4-zK+^IY)} z>Aw!7-{`;eF@-Ji%7{;MLQ9pwpy?{5izS^P_ra?A;)_ukAMbm^RI4{bGdEhf!0h^J4`8;4{dUB{BpoeE^Za`HMyea5ZUceQq26wO%QXja?Q-Ww8pGSZQ=J$b{+%Qd&TOXUoS8N)gPzhFM>Gz%y|Febi3Sa=Szm1DE1}8uvi%SOB%7=tmsYpk=BfECH*Dv zvnR;jF|MC&QR3vRW`?&q1>4-M^ExpwyZZJ5{+pZ&WQVG%Pw ze|^ib+-tycGkvsN+Lpl)lcI@pyrg&qnBY_&Ot3|sJm91l%N{2jd(>LWy$$;=30*K& zM1$`0h+uAN%+5zuSP|E(-Jf%F9%7+?01N#wd8%)Q>Kk$OuOHG#C78qswc(f%l2Tmh~AFBK>e9Y3wBEv;fpeAIGuc!CLbwBQ`B z$zol%Hx*I?9%Xtt;vEYRFJAru_W_PyMDov@q<*0tbNxRs0KAiL|0aLOjYLINHX3Tn zN=X$1cO$Tn%1H%h=rj}NhGT6m+@S1VD;Nt~u*aqv<9!*BCar znz>It*;g8grl}ed*8c?d`O{dz8tC!V8yih>!933smR=W;&GE~+XQGIq#y|NKE8!X5w59~xqeZ#x)6a7{4S zs=TTa-MZ6XQYvzb?pQ4ltR=d8icU~r4;0YlE|sfQ!58dzfJv_SO|l?Hv<9_ZpdHx4 zThunLgF=u$Q(!ja4;%KNIfNQCVnM9{1Ksc&C{do-nmx-lH&nCp=$G1%bi^FK&5N%n zUt^@vcK{*2bEI3QINr1PXW%@)Mec!%E$_B`pr&IvRZ=Jg5=i6V(W&u;@qh&*w^7b- ziEdF7Ao2q=g82-7e6_60l(DI{3XXVy^zG>*cjH=-w2IYX&`6DFM5$mg`7THy>s%O} z$#^(A=ks^Y*?-;b;i;Rm<{cdits0dZxjW%G5Ig@vu6lat<7`I^TD+3$ZbDaV2vPM`YpK4uBQZsx%)tt z9pPtg(naR+v-mxb6JG=&{dpv$1EM)}uiRlBVZ)r|h7{7J--5x>_zFK7yJ}PwSw_wCa-yGMES7Uz&Lh2Dx zW3!MNHM;a$aER)n`!?2#vML%c&+&G(p9FzCh6J*Af-IOvg)aRT46ctyvG|EsBYy%y z>)TmqWptwwTEki=kIna3C+!KcU>+5^^jk1aowVJ5Aaybetr4S3zXgY=PP!k5x~v$p z$9PrpSrE$qMLMk=@+^=?g)aRT46czSf9%AokRO1sdJn0PSy+u8UHUCJr1g>CZH-hP zvxd-!(WT#l(d%QPPHUw4n1$7d(WT#lLsTDEJu%L`#kT7sFnD=9o`vy9(WT#l!PRlf z7di2YoZnmxe^}E)pM~LZCn>jiA>dE;TVRo)Tlg*8D-oXxiocC|r(!K>= z)~m!7R#K=0QZ;Y?8&d`+i5>)y#(RDIZUFbkkk5$p1a};yx8<9|+pkc(*3EAwD5ck} zfr25{1*zu!ZUX!Efs|*@3YURzx#(1b$;>Q3si!yK?i=<*UW1oeyp5BY=8ehrs@72&J(; Ql46qlABJW_8EB>e03-&9Bme*a From dc8f747b759a613b8b4c651ee689f13945168c27 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sun, 21 Jul 2024 17:07:38 -0500 Subject: [PATCH 13/13] fix formatter errors --- lib/themeUtils.js | 19 +++++++++++-------- package.json | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/themeUtils.js b/lib/themeUtils.js index 568ed62..93210fa 100644 --- a/lib/themeUtils.js +++ b/lib/themeUtils.js @@ -1,3 +1,5 @@ +import defaults from 'defaults'; + import * as pluginRegistry from './pluginRegistry.js'; function freezeTheme(theme) { @@ -93,6 +95,10 @@ const defaultTheme = freezeTheme({ undefined: {open: '', close: ''}, }); +function withDefaults(theme) { + return freezeTheme(defaults(theme, defaultTheme)); +} + const pluginRefs = new Map(); pluginRefs.count = 0; const normalizedPluginThemes = new Map(); @@ -120,10 +126,7 @@ function normalizePlugins(plugins) { }; } - const theme = freezeTheme({ - ...structuredClone(defaultTheme), - ...Object.assign({}, ...themes), - }); + const theme = withDefaults(Object.assign({}, ...themes)); normalizedPluginThemes.set(ref, theme); return {ref, theme}; } @@ -134,10 +137,10 @@ export function normalize(options) { const normalizedPlugins = normalizePlugins(options.plugins); if (!options.theme) { - return normalizedPlugins ? normalizedPlugins.theme : defaultTheme; + return normalizedPlugins?.theme ?? defaultTheme; } - const entry = normalizedCache.get(options.theme) || {theme: null, withPlugins: new Map()}; + const entry = normalizedCache.get(options.theme) ?? {theme: null, withPlugins: new Map()}; if (!normalizedCache.has(options.theme)) { normalizedCache.set(options.theme, entry); } @@ -147,12 +150,12 @@ export function normalize(options) { return entry.withPlugins.get(normalizedPlugins.ref); } - const theme = freezeTheme({...structuredClone(defaultTheme), ...options.theme}); + const theme = withDefaults(options.theme); entry.withPlugins.set(normalizedPlugins.ref, theme); return theme; } - entry.theme ||= freezeTheme({...structuredClone(defaultTheme), ...options.theme}); + entry.theme ??= withDefaults(options.theme); return entry.theme; } diff --git a/package.json b/package.json index 39cca1a..5484bc9 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "homepage": "https://github.com/concordancejs/concordance#readme", "dependencies": { "date-time": "^4.0.0", + "defaults": "^3.0.0", "esutils": "^2.0.3", "fast-diff": "^1.3.0", "js-string-escape": "^1.0.1",