Repository URL to install this package:
|
Version:
1.1.16 ▾
|
// eslint-disable-next-line
'use strict'
const {EventEmitter} = require('events')
const log = require('fliplog')
const traverse = require('../src/deps/traverse')
const isArray = require('../src/deps/is/array')
const isObj = require('../src/deps/is/obj')
const isNumber = require('../src/deps/is/number')
const isReal = require('../src/deps/is/real')
const {eq, copy} = traverse
const deepEqual = eq
test('pre-copy eq to themselves invariant for environment', () => {
const date = new Date(0, 0, 0, 0)
expect(date).toBe(date)
const error = new Error('ehror')
expect(error).toBe(error)
const regexp = new RegExp('../', 'gmi')
expect(regexp).toBe(regexp)
})
test('copy', () => {
const date = new Date(0, 0, 0, 0)
expect(copy(date)).not.toBe(date)
const error = new Error('ehror')
expect(copy(error)).not.toBe(error)
const regexp = new RegExp('../', 'gmi')
expect(copy(regexp)).not.toBe(regexp)
})
test('deepDates', () => {
expect.assertions(2)
expect(
deepEqual(
{d: new Date(0, 0, 0, 0), x: [1, 2, 3]},
{d: new Date(0, 0, 0, 0), x: [1, 2, 3]}
)
).toBeTruthy()
const d0 = new Date()
return new Promise(res => setTimeout(res, 5)).then(val => {
expect(
!deepEqual({d: d0, x: [1, 2, 3]}, {d: new Date(), x: [1, 2, 3]})
).toBeTruthy()
return Promise.resolve()
})
})
test.skip('deepCircular', () => {
// return expect(true).toBe(true)
var a = [1]
a.push(a) // a = [ 1, *a ]
var b = [1]
b.push(a) // b = [ 1, [ 1, *a ] ]
expect(!deepEqual(a, b, false)).toBeTruthy()
var c = [1]
c.push(c) // c = [ 1, *c ]
expect(deepEqual(a, c)).toBeTruthy()
var d = [1]
d.push(a) // c = [ 1, [ 1, *d ] ]
expect(deepEqual(b, d)).toBeTruthy()
})
test('deepInstances', () => {
expect(!deepEqual([new Boolean(false)], [false])).toBeTruthy()
expect(!deepEqual([new String('x')], ['x'])).toBeTruthy()
expect(!deepEqual([new Number(4)], [4])).toBeTruthy()
expect(deepEqual([new RegExp('x')], [/x/])).toBeTruthy()
expect(!deepEqual([new RegExp(/./)], [/../])).toBeTruthy()
expect(
!deepEqual(
[
function(x) {
return x * 2
},
],
[
function(x) {
return x * 2
},
]
)
).toBeTruthy()
var f = function(x) {
return x * 2
}
expect(deepEqual([f], [f])).toBeTruthy()
})
test('deepEqual', () => {
expect(!deepEqual([1, 2, 3], {0: 1, 1: 2, 2: 3})).toBeTruthy()
})
test('falsy', () => {
expect(!deepEqual([undefined], [null])).toBeTruthy()
expect(!deepEqual([null], [undefined])).toBeTruthy()
expect(
!deepEqual(
{a: 1, b: 2, c: [3, undefined, 5]},
{a: 1, b: 2, c: [3, null, 5]}
)
).toBeTruthy()
expect(
!deepEqual(
{a: 1, b: 2, c: [3, undefined, 5]},
{a: 1, b: 2, c: [3, null, 5]}
)
).toBeTruthy()
expect(
!deepEqual(
{a: 1, b: 2, c: [3, undefined, 5]},
{a: 1, b: 2, c: [3, null, 5]}
)
).toBeTruthy()
})
test.skip('deletedArrayEqual', () => {
var xs = [1, 2, 3, 4]
delete xs[2]
var ys = Object.create(Array.prototype)
ys[0] = 1
ys[1] = 2
ys[3] = 4
ys = Array.from(ys)
expect(deepEqual(xs, ys)).toBeTruthy()
expect(!deepEqual(xs, [1, 2, undefined, 4])).toBeTruthy()
// expect(!deepEqual(xs, [1, 2, null, 4])).toBeTruthy()
})
test('deletedObjectEqual', () => {
var obj = {a: 1, b: 2, c: 3}
delete obj.c
expect(deepEqual(obj, {a: 1, b: 2})).toBeTruthy()
expect(!deepEqual(obj, {a: 1, b: 2, c: undefined})).toBeTruthy()
expect(!deepEqual(obj, {a: 1, b: 2, c: null})).toBeTruthy()
})
test('emptyKeyEqual', () => {
expect(!deepEqual({a: 1}, {'a': 1, '': 55})).toBeTruthy()
})
test('deepArguments', () => {
expect(
!deepEqual(
[4, 5, 6],
(function() {
return arguments
})(4, 5, 6)
)
).toBeTruthy()
expect(
deepEqual(
(function() {
return arguments
})(4, 5, 6),
(function() {
return arguments
})(4, 5, 6)
)
).toBeTruthy()
})
test('deepUn', () => {
expect(!deepEqual({a: 1, b: 2}, undefined)).toBeTruthy()
expect(!deepEqual({a: 1, b: 2}, {})).toBeTruthy()
expect(!deepEqual(undefined, {a: 1, b: 2})).toBeTruthy()
expect(!deepEqual({}, {a: 1, b: 2})).toBeTruthy()
expect(deepEqual(undefined, undefined)).toBeTruthy()
expect(deepEqual(null, null)).toBeTruthy()
expect(!deepEqual(undefined, null)).toBeTruthy()
})
test('deepLevels', () => {
var xs = [1, 2, [3, 4, [5, 6]]]
expect(!deepEqual(xs, [])).toBeTruthy()
})
test('number, string, Error, Promise', () => {
const ErrorOne = new Error('1')
expect(deepEqual(1, 1)).toBe(true)
expect(deepEqual(1, 0)).toBe(false)
expect(deepEqual('string', 'string')).toBe(true)
expect(deepEqual('1', '1')).toBe(true)
expect(deepEqual(ErrorOne, ErrorOne)).toBe(true)
expect(deepEqual('1', 1)).toBe(false)
expect(deepEqual(new Promise(r => r()), 'string')).toBe(false)
expect(deepEqual(new Error(), '1')).toBe(false)
// expect(deepEqual(new Promise(r => r()), new Error('2'))).toBe(false)
})
test('Error vs Error', () => {
expect(deepEqual(new Error('1'), new Error('2'))).toBe(false)
})
test('null vs undefined', () => {
expect(!deepEqual(null, undefined)).toBeTruthy()
expect(!deepEqual(undefined, null)).toBeTruthy()
expect(deepEqual(null, null)).toBeTruthy()
expect(deepEqual(undefined, undefined)).toBeTruthy()
})
test('RegExp vs RegExp', () => {
expect(deepEqual(new RegExp('.*'), new RegExp('.*'))).toBeTruthy()
})
test('RegExp vs RegExp !', () => {
expect(!deepEqual(new RegExp('not-the-same'), new RegExp('.*'))).toBeTruthy()
})
test('Fn vs Fn', () => {
const noop = function() {
/* noop */
}
const noops = function() {
/* noops */
}
noops.eh = true
noop()
noops()
console.log('noop == noop')
expect(deepEqual(noop, noop)).toBeTruthy()
console.log('noop != noops')
expect(!deepEqual(noop, noops)).toBeTruthy()
})
test('Fn vs Fn - string diff', () => {
function noop() {
/* noop */
}
function noops() {
/* noops */
}
noop()
noops()
expect(deepEqual(noop, noop)).toBe(true)
expect(deepEqual(noop, noops)).toBe(false)
})
test('ObjKeys', () => {
expect(
!deepEqual({one: true, two: true}, {one: true, three: false})
).toBeTruthy()
})
test.skip('supports.equals', () => {
const alwaysFalse = {
equals() {
return false
},
}
const alwaysTrue = {
equals() {
return true
},
}
expect(deepEqual(alwaysFalse, alwaysTrue)).toBe(false)
expect(deepEqual(alwaysTrue, alwaysFalse)).toBe(true)
})
test.skip('eq: simple primitives', () => {
// 'null == undefined'
expect(eq(null, undefined)).toBe(true)
// 'null == null'
expect(eq(null, null)).toBe(true)
// '1 == 1'
expect(eq(1, 1)).toBe(true)
// '"1" == 1'
expect(eq(1, '1')).toBe(true)
// '"1" ~= 1'
expect(eq(1, '1', true)).toBe(true)
// '1 == 0'
expect(eq(1, 0)).toBe(true)
// '1 == [1]'
expect(eq(1, [1])).toBe(true)
// '[1] == [1]'
expect(eq([1], [1])).toBe(true)
})
test.skip('edge', () => {
// '[Number(4)], [4]'
expect(deepEqual([new Number(4)], [4])).toBe(true)
// 'Number(4), 4'
expect(deepEqual(new Number(4), 4)).toBe(true)
// '4, Number(4)'
expect(deepEqual(4, new Number(4))).toBe(true)
// '[4], [Number(4)]'
expect(deepEqual([4], [new Number(4)])).toBe(true)
// 'RegExp(x), /x/',
expect(deepEqual([new RegExp('x')], [/x/])).toBe(true)
// '! RegExp(/./), /../'
expect(deepEqual([new RegExp(/./)], [/../])).toBe(true)
expect(deepEqual(1, 1)).toBe(true)
expect(deepEqual(1, 0)).toBe(true)
expect(deepEqual('string', 'string')).toBe(true)
expect(deepEqual('string', 'str')).toBe(true)
expect(deepEqual('stringy', new String('stringy'))).toBe(true)
expect(deepEqual('1', '1')).toBe(true)
const ErrorOne = new Error('1')
expect(deepEqual(ErrorOne, ErrorOne)).toBe(true)
expect(deepEqual(ErrorOne, new Error('2'))).toBe(true)
// 'new Error(), "1"'
expect(deepEqual(new Error(), '1')).toBe(true)
// expect(deepEqual(new Promise(r => r()).toBe(true), new Error('2')).toBe(true))
// expect(deepEqual(new Promise(r => r()).toBe(true), 'string')).toBe(true)
// '{1, 3} == {1, 3}'
expect(eq({one: 2, three: 3}, {one: 2, three: 3})).toBe(true)
// '{1, 4} == {1, 3}'
expect(eq({'1': 2, '2': 3}, {'1': 2, '2': 4})).toBe(true)
})
test('negative update test', () => {
var obj = [5, 6, -3, [7, 8, -2, 1], {f: 10, g: -13}]
var cloned = traverse(obj).clone()
// log.quick({obj, cloned})
var fixed = traverse(cloned).forEach(function(key, x, t) {
log.bold(t.path.join('.')).data({[key]: x}).echo()
if (x < 0) t.update(x + 128)
})
// console.log({fixed})
expect(fixed).toEqual([5, 6, 125, [7, 8, 126, 1], {f: 10, g: 115}])
expect(obj).toEqual([5, 6, -3, [7, 8, -2, 1], {f: 10, g: -13}])
})
// ----- events ----
test('check instanceof on node elems', () => {
var counts = {emitter: 0}
var list = [new EventEmitter(), 3, 4, {ev: new EventEmitter()}]
traverse(list).forEach((key, node, t) => {
if (node instanceof EventEmitter) counts.emitter++
})
expect(counts.emitter).toEqual(2)
})
// ---- obj ---
test('traverse an object with nested functions', () => {
expect.assertions(1)
function Cons(x) {
expect(x).toEqual(10)
}
traverse(new Cons(10))
})
//// ------ stringify ----
test('stringify', () => {
// var obj = [5, 6, -3, [7, 8, -2, 1], {f: 10, g: -13}]
// var obj = [1, 2, 3]
var obj = [1, 2, 3, [4, 5, 6], {a: 7, b: 8}]
var s = ''
const trav = traverse(obj)
trav.before(t => {
// console.log('before', t.key, t.path.join(''), '\n\n')
// s += '\nbefore\n'
if (isArray(t.node)) s += '['
else if (isObj(t.node)) s += '{'
})
trav.pre(traverser => {
// s += '\npre\n'
// console.log('pre', traverser.key, traverser.path.join(''), '\n\n')
const key = traverser.key || traverser.path.join('')
if (key && isObj(traverser.node) && !isArray(traverser.node)) {
s += '"' + key + '"' + ':'
}
})
trav.after(t => {
// console.log('after')
if (s.endsWith(',')) s = s.slice(0, -1)
// s += '\nafter\n'
if (isArray(t.node)) s += ']'
else if (isObj(t.node)) s += '}'
})
trav.post(child => {
// console.log('post', child)
// s += '\npost\n'
s += ','
})
trav.forEach(function(key, node, t) {
// console.log({
// [key]: node,
// t,
// isArrayay: Array.isArrayay(node),
// typeof: typeof node,
// })
if (typeof node === 'function') {
s += 'null'
}
else if (!isArray(node) && !isObj(node)) {
s += node.toString()
}
})
expect(s).toEqual(JSON.stringify(obj))
})
/* istanbul ignore next: is a failing test */
test('Map can iterate in order with leaves', () => {
var acc = []
const map = new Map()
map.set('a', {a: [1, 2, 3]})
map.set('b', 4)
map.set('c', [5, 6])
map.set('d', {e: [7, 8], f: 9})
const obj = map
traverse({obj}).forEach(function(key, x) {
if (this.isLeaf) acc.push(x)
})
expect(acc.join(' ')).toEqual('1 2 3 4 5 6 7 8 9')
})
/* istanbul ignore next: is a failing test */
test('Set can iterate in order', () => {
var acc = []
const set = new Set()
set.add({a: [1, 2, 3]})
set.add([4])
set.add([5, 6])
set.add({e: [7, 8], f: 9})
traverse(set).forEach(function(key, x) {
if (this.isLeaf) acc.push(x)
})
expect(acc.join(' ')).toEqual('1 2 3 4 5 6 7 8 9')
})
test('eq: loose', () => {
expect(eq('1', 1, true)).toBe(true)
})
test.skip('clone: MapSet', () => {
const map = new Map()
const set = new Set()
set.add(0)
set.add(1)
set.add(2)
map.set('zero', 0)
map.set('one', 1)
map.set('two', 2)
const mapset = [map, set]
// log.quick(traverse.clone(mapset))
})
test('stop', () => {
var visits = 0
traverse('abcdefghij'.split('')).forEach(function(key, node, t) {
if (typeof node === 'string') {
visits++
if (node === 'e') t.stop()
}
})
expect(visits).toEqual(5)
})
// ---- keys.js
// test.skip('sort test', () => {
// var acc = []
// traverse({
// a: 30,
// b: 22,
// id: 9,
// }).forEach(function(key, node) {
// if (!Array.isArrayay(node) && typeof node === 'object') {
// this.before(function(node) {
// this.keys = Object.keys(node)
// this.keys.sort((a, b) => {
// a = [a === 'id' ? 0 : 1, a]
// b = [b === 'id' ? 0 : 1, b]
// return a < b ? -1 : a > b ? 1 : 0
// })
// })
// }
// if (t.isLeaf) acc.push(node)
// })
//
// expect(acc.join(' ')).toEqual('9 30 22')
// })
// ----- remove
test('traverse no argument', () => {
traverse().forEach(() => {})
})
test('remove arr', () => {
traverse([]).forEach((key, val, it) => {})
const arr = [0]
traverse(arr).forEach((key, val, it) => it.remove())
expect(arr.filter(isReal)).toEqual([])
let arrString = [0, 100, 10, 100, 'not number', 200, 1000]
traverse(arrString).forEach((key, val, it) => {
log.bold(key).data(val).echo()
if (isNumber(val)) it.remove()
})
expect(arrString.filter(isReal)).toEqual(['not number'])
})
test('remove obj', () => {
const emptyObj = {}
traverse(emptyObj).forEach((key, val, it) => {})
expect(emptyObj).toEqual(emptyObj)
const obj = {eh: true}
traverse(obj).forEach((key, val, it) => it.remove())
expect(obj).toEqual({})
const objNumber = {eh: true, num: 100}
traverse(objNumber).forEach((key, val, it) => {
if (!isNumber(val)) it.remove()
})
expect(objNumber).toEqual({num: 100})
})
// --- leaves.js
test('leaves test', () => {
var acc = []
traverse({
a: [1, 2, 3],
b: 4,
c: [5, 6],
d: {e: [7, 8], f: 9},
}).forEach(function(key, x, t) {
if (t.isLeaf) acc.push(x)
})
expect(acc.join(' ')).toEqual('1 2 3 4 5 6 7 8 9')
})
// --- circular.js
test('circular', () => {
expect.assertions(1)
var obj = {x: 3}
obj.y = obj
traverse(obj).forEach(function(key, x, t) {
if (key == 'y') {
expect(x == obj).toBe(true)
}
})
})
test('deepCirc', () => {
expect.assertions(1)
var obj = {x: [1, 2, 3], y: [4, 5]}
obj.y[2] = obj
var times = 0
traverse(obj).forEach(function(key, x, t) {
if (t.isCircular) {
// expect(t.circular.path).toEqual([])
expect(t.path).toEqual(['y', 2])
}
})
})
test('doubleCirc', () => {
var obj = {x: [1, 2, 3], y: [4, 5]}
obj.y[2] = obj
obj.x.push(obj.y)
var circs = []
traverse(obj).forEach(function(key, x, self) {
if (self.isCircular) {
circs.push({self, path: self.path.slice(0)})
}
})
expect(circs[0].path).toEqual(['x', 3, 2])
// de(circs[0].circ.path, [])
// 'y', 2
expect(circs[1].path).toEqual(['y'])
// de(circs[1].circ.path, [])
expect(circs.length).toBe(2)
})
test('circDubForEach', () => {
var obj = {x: [1, 2, 3], y: [4, 5]}
obj.y[2] = obj
obj.x.push(obj.y)
traverse(obj).forEach(function(key, x, t) {
if (t.isCircular) {
t.update('...')
t.clear()
}
})
expect(obj).toEqual({x: [1, 2, 3, [4, 5, '...']], y: [4, 5, '...']})
})
// test('circDubMap', () => {
// var obj = {x: [1, 2, 3], y: [4, 5]}
// obj.y[2] = obj
// obj.x.push(obj.y)
//
// var c = traverse(obj).map(function(x) {
// if (this.circular) {
// this.update('...')
// }
// })
//
// expect(c).toEqual({x: [1, 2, 3, [4, 5, '...']], y: [4, 5, '...']})
// })
test('circClone', () => {
var obj = {x: [1, 2, 3], y: [4, 5]}
obj.y[2] = obj
obj.x.push(obj.y)
var clone = traverse.clone(obj)
expect(obj !== clone).toBeTruthy()
// log.quick({clone, obj}, clone.x.slice(0, 3), obj.x.slice(0, 3))
expect(clone.x.slice(0, 3)).toEqual([1, 2, 3])
expect(clone.y.slice(0, 2)).toEqual([4, 5])
})
test.skip('circClone - @FIXME', () => {
var obj = {x: [1, 2, 3], y: [4, 5]}
obj.y[2] = obj
obj.x.push(obj.y)
var clone = traverse.clone(obj)
log.quick(clone.x[3][2], clone)
// expect(clone.y[2] === clone).toBeTruthy()
expect(eq(clone.y[2], clone)).toBeTruthy()
expect(eq(clone, clone.y[2])).toBeTruthy()
expect(eq(clone.x[3][2], clone)).toBeTruthy()
console.log(clone.y[2] !== obj)
console.log(clone.x[3][2] !== obj)
})
test.skip('circMapScrub', () => {
var obj = {a: 1, b: 2}
obj.c = obj
var scrubbed = traverse(obj).map(function(node) {
if (this.circular) this.remove()
})
expect(Object.keys(scrubbed).sort()).toEqual(['a', 'b'])
expect(deepEqual(scrubbed, {a: 1, b: 2}, true)).toBeTruthy()
expect(deepEqual(obj.c, obj, true)).toBeTruthy()
})