diff --git a/.eustia.js b/.eustia.js
index 54418ab..d76bbdf 100644
--- a/.eustia.js
+++ b/.eustia.js
@@ -13,7 +13,7 @@ module.exports = {
format: 'es'
},
stringify: {
- files: 'src/lib/stringify.js',
+ files: 'src/lib/stringifyWorker.js',
output: 'src/lib/stringifyUtil.js',
format: 'es'
},
diff --git a/doc/UTIL_API.md b/doc/UTIL_API.md
index 1d25fc8..57b7c29 100644
--- a/doc/UTIL_API.md
+++ b/doc/UTIL_API.md
@@ -1076,6 +1076,20 @@ if (detectOs() === 'ios') {
}
```
+## difference
+
+Create an array of unique array values not included in the other given array.
+
+|Name |Type |Desc |
+|---------|-----|----------------------------|
+|arr |array|Array to inspect |
+|[...rest]|array|Values to exclude |
+|return |array|New array of filtered values|
+
+```javascript
+difference([3, 2, 1], [4, 2]); // -> [3, 1]
+```
+
## each
Iterate over elements of collection and invokes iterator for each element.
@@ -1215,6 +1229,19 @@ filter([1, 2, 3, 4, 5], function (val) {
}); // -> [2, 4]
```
+## flatten
+
+Recursively flatten an array.
+
+|Name |Type |Desc |
+|------|-----|-------------------|
+|arr |array|Array to flatten |
+|return|array|New flattened array|
+
+```javascript
+flatten(['a', ['b', ['c']], 'd', ['e']]); // -> ['a', 'b', 'c', 'd', 'e']
+```
+
## freeze
Shortcut for Object.freeze.
@@ -1602,6 +1629,20 @@ isObj({}); // -> true
isObj([]); // -> true
```
+## isPromise
+
+Check if value looks like a promise.
+
+|Name |Type |Desc |
+|------|-------|----------------------------------|
+|val |* |Value to check |
+|return|boolean|True if value looks like a promise|
+
+```javascript
+isPromise(new Promise(function () {})); // -> true
+isPromise({}); // -> false
+```
+
## isRegExp
Check if value is a regular expression.
@@ -2219,6 +2260,32 @@ obj.b = obj;
stringify(obj); // -> '{"a":1,"b":"[Circular ~]"}'
```
+## stringifyAll
+
+Stringify object into json with types.
+
+|Name |Type |Desc |
+|---------|------|-------------------|
+|obj |* |Object to stringify|
+|[options]|object|Stringify options |
+|return |string|Stringified object |
+
+Available options:
+
+|Name |Type |Desc |
+|------------------|-------|-------------------------|
+|unenumerable=false|boolean|Include unenumerable keys|
+|symbol=false |boolean|Include symbol keys |
+|accessGetter=false|boolean|Access getter value |
+|timeout=0 |number |Timeout of stringify |
+|depth=0 |number |Max depth of recursion |
+
+When time is out, all remaining values will all be "Timeout".
+
+```javascript
+stringifyAll(function test() {}); // -> '{"value":"function test() {}","type":"Function",...}'
+```
+
## stripHtmlTag
Strip html tags from a string.
diff --git a/src/Console/Console.js b/src/Console/Console.js
index a80b0f1..935f792 100644
--- a/src/Console/Console.js
+++ b/src/Console/Console.js
@@ -4,7 +4,6 @@ import { noop, evalCss, $, Emitter } from '../lib/util'
import emitter from '../lib/emitter'
import Settings from '../Settings/Settings'
import stringify from './stringify'
-import libStringify from '../lib/stringify'
export default class Console extends Tool {
constructor() {
@@ -314,8 +313,6 @@ export default class Console extends Tool {
}
}
-Console.stringify = libStringify
-
const CONSOLE_METHOD = [
'log',
'error',
diff --git a/src/Console/Log.js b/src/Console/Log.js
index b8d808d..6108619 100644
--- a/src/Console/Log.js
+++ b/src/Console/Log.js
@@ -425,8 +425,10 @@ let render = data => tpl(data)
function extractObj(obj, options = {}, cb) {
defaults(options, {
- getterVal: Log.showGetterVal,
- unenumerable: Log.showUnenumerable
+ accessGetter: Log.showGetterVal,
+ unenumerable: Log.showUnenumerable,
+ symbol: Log.showUnenumerable,
+ timeout: 1000
})
stringify(obj, options, result => cb(JSON.parse(result)))
diff --git a/src/Console/stringify.js b/src/Console/stringify.js
index e24a407..fd57e52 100644
--- a/src/Console/stringify.js
+++ b/src/Console/stringify.js
@@ -1,6 +1,5 @@
-import stringify from '../lib/stringify'
import StringifyWorker from '../lib/stringifyWorker'
-import { nextTick, uniqId, tryIt } from '../lib/util'
+import { nextTick, uniqId, tryIt, stringifyAll } from '../lib/util'
let isWorkerSupported = !!window.Worker
@@ -38,7 +37,7 @@ function exports(obj, options, cb) {
}
}
- let result = stringify(obj, options)
+ let result = stringifyAll(obj, options)
nextTick(() => cb(result))
}
diff --git a/src/Elements/Elements.js b/src/Elements/Elements.js
index d8e16f3..75f43f0 100644
--- a/src/Elements/Elements.js
+++ b/src/Elements/Elements.js
@@ -1,6 +1,5 @@
import Tool from '../DevTools/Tool'
import CssStore from './CssStore'
-import stringify from '../lib/stringify'
import Highlight from './Highlight'
import Select from './Select'
import Settings from '../Settings/Settings'
@@ -22,7 +21,8 @@ import {
safeGet,
pxToNum,
isNaN,
- isNum
+ isNum,
+ stringifyAll
} from '../lib/util'
export default class Elements extends Tool {
@@ -171,7 +171,12 @@ export default class Elements extends Tool {
let data = this._elData
if (!data) {
- data = stringify(this._curEl, { getterVal: true })
+ data = stringifyAll(this._curEl, {
+ unenumerable: true,
+ symbol: true,
+ accessGetter: true,
+ timeout: 1000
+ })
data = JSON.parse(data)
}
let sources = container.get('sources')
diff --git a/src/lib/JsonViewer.js b/src/lib/JsonViewer.js
index 52f858a..db8fe92 100644
--- a/src/lib/JsonViewer.js
+++ b/src/lib/JsonViewer.js
@@ -1,31 +1,33 @@
import {
evalCss,
$,
- isStr,
startWith,
- trim,
isArr,
- contain,
isObj,
uniqId,
upperFirst,
- isNum,
toNum,
- isBool,
escape,
toStr,
chunk,
each,
- map,
- isNaN
+ isNaN,
+ isNum,
+ isBool,
+ keys,
+ trim
} from './util'
export default class JsonViewer {
constructor(data, $el) {
evalCss(require('./json.scss'))
- this._data = [data]
- this._data.erudaId = uniqId('erudaJson')
+ this._data = {
+ id: uniqId('json'),
+ enumerable: {
+ 0: data
+ }
+ }
this._$el = $el
this._map = {}
createMap(this._map, this._data)
@@ -36,63 +38,65 @@ export default class JsonViewer {
jsonToHtml(data, firstLevel) {
let ret = ''
- for (let key in data) {
- let val = data[key]
+ each(['enumerable', 'unenumerable', 'symbol'], type => {
+ if (!data[type]) return
- if (
- key === 'erudaObjAbstract' ||
- key === 'erudaCircular' ||
- key === 'erudaId' ||
- key === 'erudaSplitArr' ||
- (isStr(val) && startWith(val, 'erudaJson'))
- )
- continue
+ const typeKeys = keys(data[type])
+ typeKeys.sort(sortObjName)
+ for (let i = 0, len = typeKeys.length; i < len; i++) {
+ const key = typeKeys[i]
+ ret += this.createEl(key, data[type][key], type, firstLevel)
+ }
+ })
- if (Object.hasOwnProperty.call(data, key))
- ret += this.createEl(key, val, firstLevel)
+ if (data.proto) {
+ if (ret === '') {
+ ret = this.jsonToHtml(data.proto, firstLevel)
+ } else {
+ ret += this.createEl('__proto__', data.proto, 'proto', firstLevel)
+ }
}
return ret
}
- createEl(key, val, firstLevel = false) {
- let type = 'object',
- isUnenumerable = false,
- id
-
- if (key === 'erudaProto') key = '__proto__'
- if (startWith(key, 'erudaUnenumerable')) {
- key = trim(key.replace('erudaUnenumerable', ''))
- isUnenumerable = true
- }
+ createEl(key, val, keyType, firstLevel = false) {
+ let type = 'object'
+ let id
if (isArr(val)) type = 'array'
function wrapKey(key) {
if (firstLevel) return ''
- if (isObj(val) && val.erudaSplitArr) return ''
+ if (isObj(val) && val.jsonSplitArr) return ''
let keyClass = 'eruda-key'
- if (isUnenumerable || contain(LIGHTER_KEY, key))
+ if (
+ keyType === 'unenumerable' ||
+ keyType === 'proto' ||
+ keyType === 'symbol'
+ ) {
keyClass = 'eruda-key-lighter'
+ }
return `${encode(key)}: `
}
if (val === null) {
- return `
- ${wrapKey(key)}
- null
- `
- }
-
- if (isObj(val)) {
- id = val.erudaId
- let circularId = val.erudaCircular
- let objAbstract = val['erudaObjAbstract'] || upperFirst(type)
+ return `${wrapKey(key)}null`
+ } else if (type === 'Number' || isNum(val) || isBool(val)) {
+ return `${wrapKey(key)}${encode(
+ val
+ )}`
+ } else if (type === 'Undefined' || val === 'Symbol' || val === '(...)') {
+ return `${wrapKey(key)}${val}`
+ } else if (isObj(val)) {
+ id = val.id
+ let referenceId = val.reference
+ let objAbstract = getObjAbstract(val) || upperFirst(type)
let obj = `
+ } ${'data-object-id="' + (referenceId || id) + '"'}>
@@ -108,35 +112,13 @@ export default class JsonViewer {
return obj + ''
}
- if (isNum(val) || isBool(val)) {
- return `
- ${wrapKey(key)}
- ${encode(val)}
- `
- }
- if (isStr(val) && startWith(val, 'function')) {
- return `
- ${wrapKey(key)}
- ${encode(val).replace(
- 'function',
- ''
- )}
- `
- }
- if (val === 'undefined' || val === 'Symbol' || val === '(...)') {
- return `
- ${wrapKey(key)}
- ${val}
- `
- }
- return `
- ${wrapKey(key)}
- "${encode(val)}"
- `
+ return `${wrapKey(key)}"${encode(
+ val
+ )}"`
}
_appendTpl() {
- let data = this._map[this._data.erudaId]
+ let data = this._map[this._data.id]
this._$el.html(this.jsonToHtml(data, true))
}
@@ -146,11 +128,11 @@ export default class JsonViewer {
let self = this
this._$el.on('click', 'li', function(e) {
- let $this = $(this),
- circularId = $this.data('object-id'),
- $firstSpan = $(this)
- .find('span')
- .eq(0)
+ let $this = $(this)
+ let circularId = $this.data('object-id')
+ let $firstSpan = $(this)
+ .find('span')
+ .eq(0)
if ($this.data('first-level')) return
if (circularId) {
@@ -175,77 +157,164 @@ export default class JsonViewer {
}
function createMap(map, data) {
- let id
+ let id = data.id
- if (data.erudaId) {
- id = data.erudaId
- } else {
- id = uniqId('erudaJson')
- data.erudaId = id
+ if (!id && id !== 0) return
+
+ let isArr = data.type && startWith(data.type, 'Array')
+ if (isArr && data.enumerable) {
+ let arr = objToArr(data, id, data.type)
+ if (arr.length > 100) data = splitBigArr(arr)
}
+ map[id] = data
- if (id) {
- let objAbstract = data.erudaObjAbstract
-
- let isArr = objAbstract && startWith(objAbstract, 'Array')
- if (isArr) {
- let arr = objToArr(data)
- if (arr.length > 100) data = splitBigArr(objToArr(data), id)
+ const values = []
+ each(['enumerable', 'unenumerable', 'symbol'], type => {
+ if (!data[type]) return
+ for (let key in data[type]) {
+ values.push(data[type][key])
}
- map[id] = data
+ })
+ if (data.proto) {
+ values.push(data.proto)
}
-
- for (let key in data) {
- let val = data[key]
+ for (let i = 0, len = values.length; i < len; i++) {
+ const val = values[i]
if (isObj(val)) createMap(map, val)
}
}
-function splitBigArr(val, id) {
- let ret = chunk(val, 100)
+function splitBigArr(data) {
let idx = 0
- ret = map(ret, val => {
+ const enumerable = {}
+ each(chunk(data, 100), val => {
let obj = {}
let startIdx = idx
- obj.erudaObjAbstract = '[' + startIdx
+ obj.type = '[' + startIdx
+ obj.enumerable = {}
each(val, val => {
- obj[idx] = val
+ obj.enumerable[idx] = val
idx += 1
})
let endIdx = idx - 1
- obj.erudaObjAbstract += (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']'
- obj.erudaId = uniqId('erudaJson')
- obj.erudaSplitArr = true
- return obj
+ obj.type += (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']'
+ obj.id = uniqId('json')
+ obj.jsonSplitArr = true
+ enumerable[idx] = obj
})
- each(val.erudaStrKeys, (val, key) => (ret[key] = val))
- ret.erudaId = id
+
+ const ret = {}
+ ret.enumerable = enumerable
+ ret.id = data.id
+ ret.type = data.type
+ if (data.unenumerable) ret.unenumerable = data.unenumerable
+ if (data.symbol) ret.symbol = data.symbol
+ if (data.proto) ret.proto = data.proto
return ret
}
-function objToArr(val) {
+function objToArr(data, id, type) {
let ret = []
- let strKeys = {}
-
- each(val, (val, key) => {
+ const enumerable = {}
+ each(data.enumerable, (val, key) => {
let idx = toNum(key)
if (!isNaN(idx)) {
ret[idx] = val
} else {
- strKeys[key] = val
+ enumerable[key] = val
}
})
- ret['erudaStrKeys'] = strKeys
+ ret.enumerable = enumerable
+ ret.type = type
+ ret.id = id
+ if (data.unenumerable) ret.unenumerable = data.unenumerable
+ if (data.symbol) ret.symbol = data.symbol
+ if (data.proto) ret.proto = data.proto
return ret
}
-const LIGHTER_KEY = ['__proto__']
-
-let encode = str =>
- escape(toStr(str))
+let encode = str => {
+ return escape(toStr(str))
.replace(/\n/g, '↵')
.replace(/\f|\r|\t/g, '')
+}
+
+// $, upperCase, lowerCase, _
+function sortObjName(a, b) {
+ const numA = toNum(a)
+ const numB = toNum(b)
+ if (!isNaN(numA) && !isNaN(numB)) {
+ if (numA > numB) return 1
+ if (numA < numB) return -1
+ return 0
+ }
+
+ if (startWith(a, 'get ') || startWith(a, 'set ')) a = a.slice(4)
+ if (startWith(b, 'get ') || startWith(b, 'set ')) b = b.slice(4)
+
+ let lenA = a.length
+ let lenB = b.length
+ let len = lenA > lenB ? lenB : lenA
+
+ for (let i = 0; i < len; i++) {
+ let codeA = a.charCodeAt(i)
+ let codeB = b.charCodeAt(i)
+ let cmpResult = cmpCode(codeA, codeB)
+
+ if (cmpResult !== 0) return cmpResult
+ }
+
+ if (lenA > lenB) return 1
+ if (lenA < lenB) return -1
+
+ return 0
+}
+
+function cmpCode(a, b) {
+ a = transCode(a)
+ b = transCode(b)
+
+ if (a > b) return 1
+ if (a < b) return -1
+ return 0
+}
+
+function transCode(code) {
+ // _ should be placed after lowercase chars.
+ if (code === 95) return 123
+ return code
+}
+
+function getObjAbstract(data) {
+ const { type, value } = data
+ if (!type) return
+
+ if (type === 'Function') {
+ return getFnAbstract(value)
+ }
+ if (type === 'Array' && data.unenumerable) {
+ return `Array(${data.unenumerable.length})`
+ }
+
+ return data.type
+}
+
+const regFnHead = /function(.*?)\((.*?)\)/
+
+function extractFnHead(str) {
+ let fnHead = str.match(regFnHead)
+
+ if (fnHead) return fnHead[0]
+
+ return str
+}
+
+function getFnAbstract(str) {
+ if (str.length > 500) str = str.slice(0, 500) + '...'
+
+ return 'ƒ ' + trim(extractFnHead(str).replace('function', ''))
+}
diff --git a/src/lib/getAbstract.js b/src/lib/getAbstract.js
index dedc8f4..2671165 100644
--- a/src/lib/getAbstract.js
+++ b/src/lib/getAbstract.js
@@ -100,7 +100,7 @@ export default function getAbstract(
} else if (isRegExp) {
json = wrapRegExp(escapeJsonStr(obj.toString()))
} else if (isFn) {
- json = wrapStr('function')
+ json = wrapStr('ƒ')
} else if (isArr) {
if (doStringify) {
json = '['
@@ -174,7 +174,7 @@ export default function getAbstract(
return json
}
-const SPECIAL_VAL = ['(...)', 'undefined', 'Symbol', 'Object', 'function']
+const SPECIAL_VAL = ['(...)', 'undefined', 'Symbol', 'Object', 'ƒ']
function canBeProto(obj) {
let emptyObj = isEmpty(Object.getOwnPropertyNames(obj))
diff --git a/src/lib/stringify.js b/src/lib/stringify.js
deleted file mode 100644
index 388c332..0000000
--- a/src/lib/stringify.js
+++ /dev/null
@@ -1,314 +0,0 @@
-import {
- escapeJsonStr,
- toStr,
- each,
- endWith,
- contain,
- filter,
- isEmpty,
- isArr,
- isFn,
- isRegExp,
- uniqId,
- last,
- extend
-} from './stringifyUtil'
-
-// Modified from: https://jsconsole.com/
-export default function stringify(
- obj,
- {
- visitor = new Visitor(),
- topObj,
- level = 0,
- getterVal = false,
- unenumerable = true
- } = {}
-) {
- let json = ''
- let type
- let parts = []
- let names = []
- let proto
- let objAbstract
- let circularObj
- let allKeys
- let keys
- let id = ''
-
- topObj = topObj || obj
-
- let passOpts = { visitor, getterVal, unenumerable, level: level + 1 }
- let passProtoOpts = {
- visitor,
- getterVal,
- topObj,
- unenumerable,
- level: level + 1
- }
-
- let wrapKey = key => `"${escapeJsonStr(key)}"`
- let wrapStr = str => `"${escapeJsonStr(toStr(str))}"`
-
- type = getType(obj)
-
- let isFn = type === '[object Function]'
- let isStr = type === '[object String]'
- let isArr = type === '[object Array]'
- let isObj = type === '[object Object]'
- let isNum = type === '[object Number]'
- let isSymbol = type === '[object Symbol]'
- let isBool = type === '[object Boolean]'
-
- circularObj = visitor.check(obj)
-
- if (circularObj) {
- let abstract = circularObj.abstract
- json = `{"erudaObjAbstract": ${wrapStr(
- abstract.erudaObjAbstract
- )}, "erudaCircular": ${wrapStr(abstract.erudaCircular)}}`
- } else if (isStr) {
- json = wrapStr(obj)
- } else if (isArr || isObj || isFn) {
- id = visitor.visit(obj)
-
- if (canBeProto(obj)) {
- obj = Object.getPrototypeOf(obj)
- id = visitor.visit(obj)
- }
-
- names = getKeys(obj)
- keys = names.keys
- allKeys = names.allKeys
- names = unenumerable ? allKeys : keys
-
- proto = Object.getPrototypeOf(obj)
- if (proto) {
- proto = `${wrapKey('erudaProto')}: ${stringify(proto, passProtoOpts)}`
- }
- if (isFn) {
- // We don't need these properties to display for functions.
- names = names.filter(val => ['arguments', 'caller'].indexOf(val) < 0)
- }
- json = '{ '
- objAbstract = getObjAbstract(obj)
- visitor.updateAbstract(id, {
- erudaObjAbstract: objAbstract,
- erudaCircular: id
- })
- parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}`)
- parts.push(`"erudaId": "${id}"`)
- each(names, objIteratee)
- if (proto) parts.push(proto)
- json += parts.join(', ') + ' }'
- } else if (isNum) {
- json = obj + ''
- if (endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"`
- } else if (isBool) {
- json = obj ? 'true' : 'false'
- } else if (obj === null) {
- json = 'null'
- } else if (isSymbol) {
- json = wrapStr('Symbol')
- } else if (obj === undefined) {
- json = wrapStr('undefined')
- } else if (type === '[object HTMLAllCollection]') {
- // https://docs.webplatform.org/wiki/dom/HTMLAllCollection
- // Might cause a performance issue when stringify a dom element.
- json = wrapStr('[object HTMLAllCollection]')
- } else if (type === '[object HTMLDocument]' && level > 1) {
- // Same as reason above.
- json = wrapStr('[object HTMLDocument]')
- } else {
- try {
- id = visitor.visit(obj)
- if (canBeProto(obj)) {
- obj = Object.getPrototypeOf(obj)
- id = visitor.visit(obj)
- }
-
- json = '{ '
- objAbstract = getObjAbstract(obj)
- visitor.updateAbstract(id, {
- erudaObjAbstract: objAbstract,
- erudaCircular: id
- })
- parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}`)
- parts.push(`"erudaId": "${id}"`)
-
- names = getKeys(obj)
- keys = names.keys
- allKeys = names.allKeys
- names = unenumerable ? allKeys : keys
-
- proto = Object.getPrototypeOf(obj)
- if (proto) {
- try {
- proto = `${wrapKey('erudaProto')}: ${stringify(proto, passProtoOpts)}`
- } catch (e) {
- proto = `${wrapKey('erudaProto')}: ${wrapStr(e.message)}`
- }
- }
- each(names, objIteratee)
- if (proto) parts.push(proto)
- json += parts.join(', ') + ' }'
- } catch (e) {
- json = wrapStr(obj)
- }
- }
-
- function objIteratee(name) {
- let unenumerable = !contain(keys, name) ? 'erudaUnenumerable ' : ''
- let key = wrapKey(unenumerable + name)
- let getKey = wrapKey(unenumerable + 'get ' + name)
- let setKey = wrapKey(unenumerable + 'set ' + name)
-
- let descriptor = Object.getOwnPropertyDescriptor(obj, name)
- let hasGetter = descriptor && descriptor.get
- let hasSetter = descriptor && descriptor.set
-
- if (!getterVal && hasGetter) {
- parts.push(`${key}: "(...)"`)
- parts.push(`${getKey}: ${stringify(descriptor.get, passOpts)}`)
- } else {
- let val
- try {
- val = topObj[name]
- } catch (e) {
- val = e.message
- }
- parts.push(`${key}: ${stringify(val, passOpts)}`)
- }
- if (hasSetter) {
- parts.push(`${setKey}: ${stringify(descriptor.set, passOpts)}`)
- }
- }
-
- return json
-}
-
-function getKeys(obj) {
- let allKeys = Object.getOwnPropertyNames(obj)
- let keys = Object.keys(obj).sort(sortObjName)
-
- allKeys = keys.concat(
- filter(allKeys, val => !contain(keys, val)).sort(sortObjName)
- )
-
- return { keys, allKeys }
-}
-
-// $, upperCase, lowerCase, _
-function sortObjName(a, b) {
- let lenA = a.length
- let lenB = b.length
- let len = lenA > lenB ? lenB : lenA
-
- for (let i = 0; i < len; i++) {
- let codeA = a.charCodeAt(i)
- let codeB = b.charCodeAt(i)
- let cmpResult = cmpCode(codeA, codeB)
-
- if (cmpResult !== 0) return cmpResult
- }
-
- if (lenA > lenB) return 1
- if (lenA < lenB) return -1
-
- return 0
-}
-
-function cmpCode(a, b) {
- a = transCode(a)
- b = transCode(b)
-
- if (a > b) return 1
- if (a < b) return -1
- return 0
-}
-
-function transCode(code) {
- // _ should be placed after lowercase chars.
- if (code === 95) return 123
- return code
-}
-
-let regFnHead = /function(.*?)\((.*?)\)/
-
-function extractFnHead(fn) {
- let str = fn.toString(),
- fnHead = str.match(regFnHead)
-
- if (fnHead) return fnHead[0]
-
- return str
-}
-
-function getFnAbstract(fn) {
- let fnStr = fn.toString()
- if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...'
-
- return extractFnHead(fnStr).replace('function', '')
-}
-
-function canBeProto(obj) {
- let emptyObj = isEmpty(Object.getOwnPropertyNames(obj))
- let proto = Object.getPrototypeOf(obj)
-
- return emptyObj && proto && proto !== Object.prototype
-}
-
-function getObjAbstract(obj) {
- if (isArr(obj)) return `Array(${obj.length})`
- if (isFn(obj)) return getFnAbstract(obj)
- if (isRegExp(obj)) return obj.toString()
-
- let type = getType(obj)
-
- return type.replace(/(\[object )|]/g, '')
-}
-
-function getType(obj) {
- let type
-
- try {
- type = {}.toString.call(obj)
- } catch (e) {
- type = '[object Object]'
- }
-
- return type
-}
-
-class Visitor {
- constructor() {
- this._visited = []
- this._map = {}
- }
- visit(val) {
- /* Add 0 to distinguish stringify generated id from JsonViewer id.
- * When used in web worker, they are not calling the same uniqId method, thus result may be repeated.
- */
- let id = uniqId('erudaJson0')
-
- this._visited.push({ id, val, abstract: {} })
- this._map[id] = last(this._visited)
-
- return id
- }
- check(val) {
- let visited = this._visited
-
- for (let i = 0, len = visited.length; i < len; i++) {
- if (val === visited[i].val) return visited[i]
- }
-
- return false
- }
- update(id, data) {
- extend(this._map[id], data)
- }
- updateAbstract(id, abstract) {
- this.update(id, { abstract })
- }
-}
diff --git a/src/lib/stringifyUtil.js b/src/lib/stringifyUtil.js
index acc6ba8..f9dc44f 100644
--- a/src/lib/stringifyUtil.js
+++ b/src/lib/stringifyUtil.js
@@ -4,6 +4,78 @@
var _ = {};
+/* ------------------------------ inherits ------------------------------ */
+
+export var inherits = _.inherits = (function (exports) {
+ /* Inherit the prototype methods from one constructor into another.
+ *
+ * |Name |Type |Desc |
+ * |----------|--------|-----------|
+ * |Class |function|Child Class|
+ * |SuperClass|function|Super Class|
+ */
+
+ /* example
+ * function People(name) {
+ * this._name = name;
+ * }
+ * People.prototype = {
+ * getName: function () {
+ * return this._name;
+ * }
+ * };
+ * function Student(name) {
+ * this._name = name;
+ * }
+ * inherits(Student, People);
+ * var s = new Student('RedHood');
+ * s.getName(); // -> 'RedHood'
+ */
+
+ /* typescript
+ * export declare function inherits(Class: Function, SuperClass: Function): void;
+ */
+ exports = function exports(Class, SuperClass) {
+ if (objCreate) return (Class.prototype = objCreate(SuperClass.prototype));
+ noop.prototype = SuperClass.prototype;
+ Class.prototype = new noop();
+ };
+
+ var objCreate = Object.create;
+
+ function noop() {}
+
+ return exports;
+})({});
+
+/* ------------------------------ has ------------------------------ */
+
+export var has = _.has = (function (exports) {
+ /* Checks if key is a direct property.
+ *
+ * |Name |Type |Desc |
+ * |------|-------|--------------------------------|
+ * |obj |object |Object to query |
+ * |key |string |Path to check |
+ * |return|boolean|True if key is a direct property|
+ */
+
+ /* example
+ * has({one: 1}, 'one'); // -> true
+ */
+
+ /* typescript
+ * export declare function has(obj: {}, key: string): boolean;
+ */
+ var hasOwnProp = Object.prototype.hasOwnProperty;
+
+ exports = function exports(obj, key) {
+ return hasOwnProp.call(obj, key);
+ };
+
+ return exports;
+})({});
+
/* ------------------------------ idxOf ------------------------------ */
export var idxOf = _.idxOf = (function (exports) {
@@ -57,6 +129,62 @@ export var isUndef = _.isUndef = (function (exports) {
return exports;
})({});
+/* ------------------------------ restArgs ------------------------------ */
+
+export var restArgs = _.restArgs = (function (exports) {
+ /* This accumulates the arguments passed into an array, after a given index.
+ *
+ * |Name |Type |Desc |
+ * |------------|--------|---------------------------------------|
+ * |function |function|Function that needs rest parameters |
+ * |[startIndex]|number |The start index to accumulates |
+ * |return |function|Generated function with rest parameters|
+ */
+
+ /* example
+ * var paramArr = restArgs(function (rest) { return rest });
+ * paramArr(1, 2, 3, 4); // -> [1, 2, 3, 4]
+ */
+
+ /* typescript
+ * export declare function restArgs(fn: Function, startIndex?: number): Function;
+ */
+ exports = function exports(fn, startIdx) {
+ startIdx = startIdx == null ? fn.length - 1 : +startIdx;
+ return function() {
+ var len = Math.max(arguments.length - startIdx, 0),
+ rest = new Array(len),
+ i;
+
+ for (i = 0; i < len; i++) {
+ rest[i] = arguments[i + startIdx];
+ } // Call runs faster than apply.
+
+ switch (startIdx) {
+ case 0:
+ return fn.call(this, rest);
+
+ case 1:
+ return fn.call(this, arguments[0], rest);
+
+ case 2:
+ return fn.call(this, arguments[0], arguments[1], rest);
+ }
+
+ var args = new Array(startIdx + 1);
+
+ for (i = 0; i < startIdx; i++) {
+ args[i] = arguments[i];
+ }
+
+ args[startIdx] = rest;
+ return fn.apply(this, args);
+ };
+ };
+
+ return exports;
+})({});
+
/* ------------------------------ optimizeCb ------------------------------ */
export var optimizeCb = _.optimizeCb = (function (exports) {
@@ -245,25 +373,6 @@ export var escapeJsStr = _.escapeJsStr = (function (exports) {
return exports;
})({});
-/* ------------------------------ escapeJsonStr ------------------------------ */
-
-export var escapeJsonStr = _.escapeJsonStr = (function (exports) {
- /* Escape json string.
- */
-
- /* dependencies
- * escapeJsStr
- */
-
- exports = function (str) {
- return escapeJsStr(str)
- .replace(/\\'/g, "'")
- .replace(/\t/g, '\\t')
- }
-
- return exports;
-})({});
-
/* ------------------------------ isObj ------------------------------ */
export var isObj = _.isObj = (function (exports) {
@@ -312,34 +421,6 @@ export var isObj = _.isObj = (function (exports) {
return exports;
})({});
-/* ------------------------------ has ------------------------------ */
-
-export var has = _.has = (function (exports) {
- /* Checks if key is a direct property.
- *
- * |Name |Type |Desc |
- * |------|-------|--------------------------------|
- * |obj |object |Object to query |
- * |key |string |Path to check |
- * |return|boolean|True if key is a direct property|
- */
-
- /* example
- * has({one: 1}, 'one'); // -> true
- */
-
- /* typescript
- * export declare function has(obj: {}, key: string): boolean;
- */
- var hasOwnProp = Object.prototype.hasOwnProperty;
-
- exports = function exports(obj, key) {
- return hasOwnProp.call(obj, key);
- };
-
- return exports;
-})({});
-
/* ------------------------------ identity ------------------------------ */
export var identity = _.identity = (function (exports) {
@@ -392,38 +473,169 @@ export var objToStr = _.objToStr = (function (exports) {
return exports;
})({});
-/* ------------------------------ isArgs ------------------------------ */
+/* ------------------------------ isArr ------------------------------ */
-export var isArgs = _.isArgs = (function (exports) {
- /* Check if value is classified as an arguments object.
+export var isArr = _.isArr = (function (exports) {
+ /* Check if value is an `Array` object.
*
- * |Name |Type |Desc |
- * |------|-------|------------------------------------|
- * |val |* |Value to check |
- * |return|boolean|True if value is an arguments object|
+ * |Name |Type |Desc |
+ * |------|-------|----------------------------------|
+ * |val |* |Value to check |
+ * |return|boolean|True if value is an `Array` object|
*/
/* example
- * (function () {
- * isArgs(arguments); // -> true
- * })();
+ * isArr([]); // -> true
+ * isArr({}); // -> false
*/
/* typescript
- * export declare function isArgs(val: any): boolean;
+ * export declare function isArr(val: any): boolean;
*/
/* dependencies
* objToStr
*/
- exports = function exports(val) {
- return objToStr(val) === '[object Arguments]';
+ exports =
+ Array.isArray ||
+ function(val) {
+ return objToStr(val) === '[object Array]';
+ };
+
+ return exports;
+})({});
+
+/* ------------------------------ castPath ------------------------------ */
+
+export var castPath = _.castPath = (function (exports) {
+ /* Cast value into a property path array.
+ *
+ * |Name |Type |Desc |
+ * |------|------------|-------------------|
+ * |path |string array|Value to inspect |
+ * |[obj] |object |Object to query |
+ * |return|array |Property path array|
+ */
+
+ /* example
+ * castPath('a.b.c'); // -> ['a', 'b', 'c']
+ * castPath(['a']); // -> ['a']
+ * castPath('a[0].b'); // -> ['a', '0', 'b']
+ * castPath('a.b.c', {'a.b.c': true}); // -> ['a.b.c']
+ */
+
+ /* typescript
+ * export declare function castPath(path: string | string[], obj?: any): string[];
+ */
+
+ /* dependencies
+ * has isArr
+ */
+
+ exports = function exports(str, obj) {
+ if (isArr(str)) return str;
+ if (obj && has(obj, str)) return [str];
+ var ret = [];
+ str.replace(regPropName, function(match, number, quote, str) {
+ ret.push(quote ? str.replace(regEscapeChar, '$1') : number || match);
+ });
+ return ret;
+ }; // Lodash _stringToPath
+
+ var regPropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,
+ regEscapeChar = /\\(\\)?/g;
+
+ return exports;
+})({});
+
+/* ------------------------------ safeGet ------------------------------ */
+
+export var safeGet = _.safeGet = (function (exports) {
+ /* Get object property, don't throw undefined error.
+ *
+ * |Name |Type |Desc |
+ * |------|------------|-------------------------|
+ * |obj |object |Object to query |
+ * |path |array string|Path of property to get |
+ * |return|* |Target value or undefined|
+ */
+
+ /* example
+ * var obj = {a: {aa: {aaa: 1}}};
+ * safeGet(obj, 'a.aa.aaa'); // -> 1
+ * safeGet(obj, ['a', 'aa']); // -> {aaa: 1}
+ * safeGet(obj, 'a.b'); // -> undefined
+ */
+
+ /* typescript
+ * export declare function safeGet(obj: any, path: string | string[]): any;
+ */
+
+ /* dependencies
+ * isUndef castPath
+ */
+
+ exports = function exports(obj, path) {
+ path = castPath(path, obj);
+ var prop;
+ prop = path.shift();
+
+ while (!isUndef(prop)) {
+ obj = obj[prop];
+ if (obj == null) return;
+ prop = path.shift();
+ }
+
+ return obj;
};
return exports;
})({});
+/* ------------------------------ flatten ------------------------------ */
+
+export var flatten = _.flatten = (function (exports) {
+ /* Recursively flatten an array.
+ *
+ * |Name |Type |Desc |
+ * |------|-----|-------------------|
+ * |arr |array|Array to flatten |
+ * |return|array|New flattened array|
+ */
+
+ /* example
+ * flatten(['a', ['b', ['c']], 'd', ['e']]); // -> ['a', 'b', 'c', 'd', 'e']
+ */
+
+ /* typescript
+ * export declare function flatten(arr: any[]): any[];
+ */
+
+ /* dependencies
+ * isArr
+ */
+
+ exports = function exports(arr) {
+ return flat(arr, []);
+ };
+
+ function flat(arr, res) {
+ var len = arr.length,
+ i = -1,
+ cur;
+
+ while (len--) {
+ cur = arr[++i];
+ isArr(cur) ? flat(cur, res) : res.push(cur);
+ }
+
+ return res;
+ }
+
+ return exports;
+})({});
+
/* ------------------------------ isFn ------------------------------ */
export var isFn = _.isFn = (function (exports) {
@@ -503,6 +715,30 @@ export var getProto = _.getProto = (function (exports) {
return exports;
})({});
+/* ------------------------------ isMiniProgram ------------------------------ */
+
+export var isMiniProgram = _.isMiniProgram = (function (exports) {
+ /* Check if running in wechat mini program.
+ */
+
+ /* example
+ * console.log(isMiniProgram); // -> true if running in mini program.
+ */
+
+ /* typescript
+ * export declare const isMiniProgram: boolean;
+ */
+
+ /* dependencies
+ * isFn
+ */
+ /* eslint-disable no-undef */
+
+ exports = typeof wx !== 'undefined' && isFn(wx.openLocation);
+
+ return exports;
+})({});
+
/* ------------------------------ isStr ------------------------------ */
export var isStr = _.isStr = (function (exports) {
@@ -533,39 +769,6 @@ export var isStr = _.isStr = (function (exports) {
return exports;
})({});
-/* ------------------------------ isArr ------------------------------ */
-
-export var isArr = _.isArr = (function (exports) {
- /* Check if value is an `Array` object.
- *
- * |Name |Type |Desc |
- * |------|-------|----------------------------------|
- * |val |* |Value to check |
- * |return|boolean|True if value is an `Array` object|
- */
-
- /* example
- * isArr([]); // -> true
- * isArr({}); // -> false
- */
-
- /* typescript
- * export declare function isArr(val: any): boolean;
- */
-
- /* dependencies
- * objToStr
- */
-
- exports =
- Array.isArray ||
- function(val) {
- return objToStr(val) === '[object Array]';
- };
-
- return exports;
-})({});
-
/* ------------------------------ isNum ------------------------------ */
export var isNum = _.isNum = (function (exports) {
@@ -960,44 +1163,6 @@ export var extendOwn = _.extendOwn = (function (exports) {
return exports;
})({});
-/* ------------------------------ isEmpty ------------------------------ */
-
-export var isEmpty = _.isEmpty = (function (exports) {
- /* Check if value is an empty object or array.
- *
- * |Name |Type |Desc |
- * |------|-------|----------------------|
- * |val |* |Value to check |
- * |return|boolean|True if value is empty|
- */
-
- /* example
- * isEmpty([]); // -> true
- * isEmpty({}); // -> true
- * isEmpty(''); // -> true
- */
-
- /* typescript
- * export declare function isEmpty(val: any): boolean;
- */
-
- /* dependencies
- * isArrLike isArr isStr isArgs keys
- */
-
- exports = function exports(val) {
- if (val == null) return true;
-
- if (isArrLike(val) && (isArr(val) || isStr(val) || isArgs(val))) {
- return val.length === 0;
- }
-
- return keys(val).length === 0;
- };
-
- return exports;
-})({});
-
/* ------------------------------ isMatch ------------------------------ */
export var isMatch = _.isMatch = (function (exports) {
@@ -1040,57 +1205,95 @@ export var isMatch = _.isMatch = (function (exports) {
return exports;
})({});
-/* ------------------------------ isRegExp ------------------------------ */
+/* ------------------------------ isNaN ------------------------------ */
-export var isRegExp = _.isRegExp = (function (exports) {
- /* Check if value is a regular expression.
+export var isNaN = _.isNaN = (function (exports) {
+ /* Check if value is an NaN.
*
- * |Name |Type |Desc |
- * |------|-------|-------------------------------------|
- * |val |* |Value to check |
- * |return|boolean|True if value is a regular expression|
+ * |Name |Type |Desc |
+ * |------|-------|-----------------------|
+ * |val |* |Value to check |
+ * |return|boolean|True if value is an NaN|
+ *
+ * Undefined is not an NaN, different from global isNaN function.
*/
/* example
- * isRegExp(/a/); // -> true
+ * isNaN(0); // -> false
+ * isNaN(NaN); // -> true
*/
/* typescript
- * export declare function isRegExp(val: any): boolean;
+ * export declare function isNaN(val: any): boolean;
*/
/* dependencies
- * objToStr
+ * isNum
*/
exports = function exports(val) {
- return objToStr(val) === '[object RegExp]';
+ return isNum(val) && val !== +val;
};
return exports;
})({});
-/* ------------------------------ last ------------------------------ */
+/* ------------------------------ isNil ------------------------------ */
-export var last = _.last = (function (exports) {
- /* Get the last element of array.
+export var isNil = _.isNil = (function (exports) {
+ /* Check if value is null or undefined, the same as value == null.
*
- * |Name |Type |Desc |
- * |------|-----|-------------------------|
- * |arr |array|The array to query |
- * |return|* |The last element of array|
+ * |Name |Type |Desc |
+ * |------|-------|----------------------------------|
+ * |val |* |Value to check |
+ * |return|boolean|True if value is null or undefined|
*/
/* example
- * last([1, 2]); // -> 2
+ * isNil(null); // -> true
+ * isNil(void 0); // -> true
+ * isNil(undefined); // -> true
+ * isNil(false); // -> false
+ * isNil(0); // -> false
+ * isNil([]); // -> false
*/
/* typescript
- * export declare function last(arr: any[]): any;
+ * export declare function isNil(val: any): boolean;
*/
- exports = function exports(arr) {
- var len = arr ? arr.length : 0;
- if (len) return arr[len - 1];
+ exports = function exports(val) {
+ return val == null;
+ };
+
+ return exports;
+})({});
+
+/* ------------------------------ isPromise ------------------------------ */
+
+export var isPromise = _.isPromise = (function (exports) {
+ /* Check if value looks like a promise.
+ *
+ * |Name |Type |Desc |
+ * |------|-------|----------------------------------|
+ * |val |* |Value to check |
+ * |return|boolean|True if value looks like a promise|
+ */
+
+ /* example
+ * isPromise(new Promise(function () {})); // -> true
+ * isPromise({}); // -> false
+ */
+
+ /* typescript
+ * export declare function isPromise(val: any): boolean;
+ */
+
+ /* dependencies
+ * isObj isFn
+ */
+
+ exports = function exports(val) {
+ return isObj(val) && isFn(val.then);
};
return exports;
@@ -1209,6 +1412,40 @@ export var filter = _.filter = (function (exports) {
return exports;
})({});
+/* ------------------------------ difference ------------------------------ */
+
+export var difference = _.difference = (function (exports) {
+ /* Create an array of unique array values not included in the other given array.
+ *
+ * |Name |Type |Desc |
+ * |---------|-----|----------------------------|
+ * |arr |array|Array to inspect |
+ * |[...rest]|array|Values to exclude |
+ * |return |array|New array of filtered values|
+ */
+
+ /* example
+ * difference([3, 2, 1], [4, 2]); // -> [3, 1]
+ */
+
+ /* typescript
+ * export declare function difference(arr: any[], ...rest: any[]): any[];
+ */
+
+ /* dependencies
+ * restArgs flatten filter contain
+ */
+
+ exports = restArgs(function(arr, rest) {
+ rest = flatten(rest);
+ return filter(arr, function(val) {
+ return !contain(rest, val);
+ });
+ });
+
+ return exports;
+})({});
+
/* ------------------------------ unique ------------------------------ */
export var unique = _.unique = (function (exports) {
@@ -1384,32 +1621,669 @@ export var extend = _.extend = (function (exports) {
return exports;
})({});
-/* ------------------------------ uniqId ------------------------------ */
+/* ------------------------------ map ------------------------------ */
-export var uniqId = _.uniqId = (function (exports) {
- /* Generate a globally-unique id.
+export var map = _.map = (function (exports) {
+ /* Create an array of values by running each element in collection through iteratee.
*
- * |Name |Type |Desc |
- * |--------|------|------------------|
- * |[prefix]|string|Id prefix |
- * |return |string|Globally-unique id|
+ * |Name |Type |Desc |
+ * |---------|------------|------------------------------|
+ * |object |array object|Collection to iterate over |
+ * |iterator |function |Function invoked per iteration|
+ * |[context]|* |Function context |
+ * |return |array |New mapped array |
*/
/* example
- * uniqId('eusita_'); // -> 'eustia_xxx'
+ * map([4, 8], function (n) { return n * n; }); // -> [16, 64]
*/
/* typescript
- * export declare function uniqId(prefix?: string): string;
+ * export declare function map(
+ * list: types.List,
+ * iterator: types.ListIterator,
+ * context?: any
+ * ): TResult[];
+ * export declare function map(
+ * object: types.Dictionary,
+ * iterator: types.ObjectIterator,
+ * context?: any
+ * ): TResult[];
*/
- var idCounter = 0;
- exports = function exports(prefix) {
- var id = ++idCounter + '';
- return prefix ? prefix + id : id;
+ /* dependencies
+ * safeCb keys isArrLike types
+ */
+
+ exports = function exports(obj, iterator, ctx) {
+ iterator = safeCb(iterator, ctx);
+
+ var _keys = !isArrLike(obj) && keys(obj),
+ len = (_keys || obj).length,
+ results = Array(len);
+
+ for (var i = 0; i < len; i++) {
+ var curKey = _keys ? _keys[i] : i;
+ results[i] = iterator(obj[curKey], curKey, obj);
+ }
+
+ return results;
};
return exports;
})({});
+/* ------------------------------ toArr ------------------------------ */
+
+export var toArr = _.toArr = (function (exports) {
+ /* Convert value to an array.
+ *
+ * |Name |Type |Desc |
+ * |------|-----|----------------|
+ * |val |* |Value to convert|
+ * |return|array|Converted array |
+ */
+
+ /* example
+ * toArr({a: 1, b: 2}); // -> [{a: 1, b: 2}]
+ * toArr('abc'); // -> ['abc']
+ * toArr(1); // -> [1]
+ * toArr(null); // -> []
+ */
+
+ /* typescript
+ * export declare function toArr(val: any): any[];
+ */
+
+ /* dependencies
+ * isArrLike map isArr isStr
+ */
+
+ exports = function exports(val) {
+ if (!val) return [];
+ if (isArr(val)) return val;
+ if (isArrLike(val) && !isStr(val)) return map(val);
+ return [val];
+ };
+
+ return exports;
+})({});
+
+/* ------------------------------ Class ------------------------------ */
+
+export var Class = _.Class = (function (exports) {
+ /* Create JavaScript class.
+ *
+ * |Name |Type |Desc |
+ * |---------|--------|---------------------------------|
+ * |methods |object |Public methods |
+ * |[statics]|object |Static methods |
+ * |return |function|Function used to create instances|
+ */
+
+ /* example
+ * var People = Class({
+ * initialize: function People(name, age) {
+ * this.name = name;
+ * this.age = age;
+ * },
+ * introduce: function () {
+ * return 'I am ' + this.name + ', ' + this.age + ' years old.';
+ * }
+ * });
+ *
+ * var Student = People.extend({
+ * initialize: function Student(name, age, school) {
+ * this.callSuper(People, 'initialize', arguments);
+ *
+ * this.school = school;
+ * },
+ * introduce: function () {
+ * return this.callSuper(People, 'introduce') + '\n I study at ' + this.school + '.';
+ * }
+ * }, {
+ * is: function (obj) {
+ * return obj instanceof Student;
+ * }
+ * });
+ *
+ * var a = new Student('allen', 17, 'Hogwarts');
+ * a.introduce(); // -> 'I am allen, 17 years old. \n I study at Hogwarts.'
+ * Student.is(a); // -> true
+ */
+
+ /* typescript
+ * export declare namespace Class {
+ * class Base {
+ * toString(): string;
+ * }
+ * class IConstructor extends Base {
+ * constructor(...args: any[]);
+ * static extend(methods: any, statics: any): IConstructor;
+ * static inherits(Class: Function): void;
+ * static methods(methods: any): IConstructor;
+ * static statics(statics: any): IConstructor;
+ * [method: string]: any;
+ * }
+ * }
+ * export declare function Class(methods: any, statics?: any): Class.IConstructor;
+ */
+
+ /* dependencies
+ * extend toArr inherits safeGet isMiniProgram
+ */
+
+ exports = function exports(methods, statics) {
+ return Base.extend(methods, statics);
+ };
+
+ function makeClass(parent, methods, statics) {
+ statics = statics || {};
+ var className =
+ methods.className || safeGet(methods, 'initialize.name') || '';
+ delete methods.className;
+ var ctor;
+
+ if (isMiniProgram) {
+ ctor = function ctor() {
+ var args = toArr(arguments);
+ return this.initialize
+ ? this.initialize.apply(this, args) || this
+ : this;
+ };
+ } else {
+ ctor = new Function(
+ 'toArr',
+ 'return function ' +
+ className +
+ '()' +
+ '{' +
+ 'var args = toArr(arguments);' +
+ 'return this.initialize ? this.initialize.apply(this, args) || this : this;' +
+ '};'
+ )(toArr);
+ }
+
+ inherits(ctor, parent);
+ ctor.prototype.constructor = ctor;
+
+ ctor.extend = function(methods, statics) {
+ return makeClass(ctor, methods, statics);
+ };
+
+ ctor.inherits = function(Class) {
+ inherits(ctor, Class);
+ };
+
+ ctor.methods = function(methods) {
+ extend(ctor.prototype, methods);
+ return ctor;
+ };
+
+ ctor.statics = function(statics) {
+ extend(ctor, statics);
+ return ctor;
+ };
+
+ ctor.methods(methods).statics(statics);
+ return ctor;
+ }
+
+ var Base = (exports.Base = makeClass(Object, {
+ className: 'Base',
+ callSuper: function callSuper(parent, name, args) {
+ var superMethod = parent.prototype[name];
+ return superMethod.apply(this, args);
+ },
+ toString: function toString() {
+ return this.constructor.name;
+ }
+ }));
+
+ return exports;
+})({});
+
+/* ------------------------------ now ------------------------------ */
+
+export var now = _.now = (function (exports) {
+ /* Gets the number of milliseconds that have elapsed since the Unix epoch.
+ */
+
+ /* example
+ * now(); // -> 1468826678701
+ */
+
+ /* typescript
+ * export declare function now(): number;
+ */
+ exports =
+ Date.now ||
+ function() {
+ return new Date().getTime();
+ };
+
+ return exports;
+})({});
+
+/* ------------------------------ type ------------------------------ */
+
+export var type = _.type = (function (exports) {
+ /* Determine the internal JavaScript [[Class]] of an object.
+ *
+ * |Name |Type |Desc |
+ * |--------------|-------|-----------------|
+ * |val |* |Value to get type|
+ * |lowerCase=true|boolean|LowerCase result |
+ * |return |string |Type of object |
+ */
+
+ /* example
+ * type(5); // -> 'number'
+ * type({}); // -> 'object'
+ * type(function () {}); // -> 'function'
+ * type([]); // -> 'array'
+ * type([], false); // -> 'Array'
+ * type(async function () {}, false); // -> 'AsyncFunction'
+ */
+
+ /* typescript
+ * export declare function type(val: any, lowerCase: boolean): string;
+ */
+
+ /* dependencies
+ * objToStr isNaN
+ */
+
+ exports = function exports(val) {
+ var lowerCase =
+ arguments.length > 1 && arguments[1] !== undefined
+ ? arguments[1]
+ : true;
+ if (val === null) return lowerCase ? 'null' : 'Null';
+ if (val === undefined) return lowerCase ? 'undefined' : 'Undefined';
+ if (isNaN(val)) return lowerCase ? 'nan' : 'NaN';
+ var ret = objToStr(val).match(regObj);
+ if (!ret) return '';
+ return lowerCase ? ret[1].toLowerCase() : ret[1];
+ };
+
+ var regObj = /^\[object\s+(.*?)]$/;
+
+ return exports;
+})({});
+
+/* ------------------------------ toSrc ------------------------------ */
+
+export var toSrc = _.toSrc = (function (exports) {
+ /* Convert function to its source code.
+ *
+ * |Name |Type |Desc |
+ * |------|--------|-------------------|
+ * |fn |function|Function to convert|
+ * |return|string |Source code |
+ */
+
+ /* example
+ * toSrc(Math.min); // -> 'function min() { [native code] }'
+ * toSrc(function () {}) // -> 'function () { }'
+ */
+
+ /* typescript
+ * export declare function toSrc(fn: Function): string;
+ */
+
+ /* dependencies
+ * isNil
+ */
+
+ exports = function exports(fn) {
+ if (isNil(fn)) return '';
+
+ try {
+ return fnToStr.call(fn);
+ /* eslint-disable no-empty */
+ } catch (e) {}
+
+ try {
+ return fn + '';
+ /* eslint-disable no-empty */
+ } catch (e) {}
+
+ return '';
+ };
+
+ var fnToStr = Function.prototype.toString;
+
+ return exports;
+})({});
+
+/* ------------------------------ stringifyAll ------------------------------ */
+
+export var stringifyAll = _.stringifyAll = (function (exports) {
+ function _typeof(obj) {
+ if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') {
+ _typeof = function _typeof(obj) {
+ return typeof obj;
+ };
+ } else {
+ _typeof = function _typeof(obj) {
+ return obj &&
+ typeof Symbol === 'function' &&
+ obj.constructor === Symbol &&
+ obj !== Symbol.prototype
+ ? 'symbol'
+ : typeof obj;
+ };
+ }
+ return _typeof(obj);
+ }
+
+ /* Stringify object into json with types.
+ *
+ * |Name |Type |Desc |
+ * |---------|------|-------------------|
+ * |obj |* |Object to stringify|
+ * |[options]|object|Stringify options |
+ * |return |string|Stringified object |
+ *
+ * Available options:
+ *
+ * |Name |Type |Desc |
+ * |------------------|-------|-------------------------|
+ * |unenumerable=false|boolean|Include unenumerable keys|
+ * |symbol=false |boolean|Include symbol keys |
+ * |accessGetter=false|boolean|Access getter value |
+ * |timeout=0 |number |Timeout of stringify |
+ * |depth=0 |number |Max depth of recursion |
+ *
+ * When time is out, all remaining values will all be "Timeout".
+ */
+
+ /* example
+ * stringifyAll(function test() {}); // -> '{"value":"function test() {}","type":"Function",...}'
+ */
+
+ /* typescript
+ * export declare namespace stringifyAll {
+ * interface IOptions {
+ * unenumerable?: boolean;
+ * symbol?: boolean;
+ * accessGetter?: boolean;
+ * timeout?: number;
+ * depth?: number;
+ * }
+ * }
+ * export declare function stringifyAll(
+ * obj: any,
+ * options?: stringifyAll.IOptions
+ * ): string;
+ */
+
+ /* dependencies
+ * escapeJsStr type toStr endWith toSrc keys each Class getProto difference extend isPromise filter now allKeys
+ */
+
+ exports = (function(_exports) {
+ function exports(_x) {
+ return _exports.apply(this, arguments);
+ }
+
+ exports.toString = function() {
+ return _exports.toString();
+ };
+
+ return exports;
+ })(function(obj) {
+ var _ref =
+ arguments.length > 1 && arguments[1] !== undefined
+ ? arguments[1]
+ : {},
+ self = _ref.self,
+ _ref$startTime = _ref.startTime,
+ startTime = _ref$startTime === void 0 ? now() : _ref$startTime,
+ _ref$timeout = _ref.timeout,
+ timeout = _ref$timeout === void 0 ? 0 : _ref$timeout,
+ _ref$depth = _ref.depth,
+ depth = _ref$depth === void 0 ? 0 : _ref$depth,
+ _ref$curDepth = _ref.curDepth,
+ curDepth = _ref$curDepth === void 0 ? 1 : _ref$curDepth,
+ _ref$visitor = _ref.visitor,
+ visitor = _ref$visitor === void 0 ? new Visitor() : _ref$visitor,
+ _ref$unenumerable = _ref.unenumerable,
+ unenumerable = _ref$unenumerable === void 0 ? false : _ref$unenumerable,
+ _ref$symbol = _ref.symbol,
+ symbol = _ref$symbol === void 0 ? false : _ref$symbol,
+ _ref$accessGetter = _ref.accessGetter,
+ accessGetter = _ref$accessGetter === void 0 ? false : _ref$accessGetter;
+
+ var json = '';
+ var options = {
+ visitor: visitor,
+ unenumerable: unenumerable,
+ symbol: symbol,
+ accessGetter: accessGetter,
+ depth: depth,
+ curDepth: curDepth + 1,
+ timeout: timeout,
+ startTime: startTime
+ };
+ var t = type(obj, false);
+
+ if (t === 'String') {
+ json = wrapStr(obj);
+ } else if (t === 'Number') {
+ json = toStr(obj);
+
+ if (endWith(json, 'Infinity')) {
+ json = '{"value":"'.concat(json, '","type":"Number"}');
+ }
+ } else if (t === 'NaN') {
+ json = '{"value":"NaN","type":"Number"}';
+ } else if (t === 'Boolean') {
+ json = obj ? 'true' : 'false';
+ } else if (t === 'Null') {
+ json = 'null';
+ } else if (t === 'Undefined') {
+ json = '{"type":"Undefined"}';
+ } else if (t === 'Symbol') {
+ var val = 'Symbol';
+
+ try {
+ val = toStr(obj);
+ /* eslint-disable no-empty */
+ } catch (e) {}
+
+ json = '{"value":'.concat(wrapStr(val), ',"type":"Symbol"}');
+ } else {
+ if (timeout && now() - startTime > timeout) {
+ return wrapStr('Timeout');
+ }
+
+ if (depth && curDepth > depth) {
+ return wrapStr('{...}');
+ }
+
+ json = '{';
+ var parts = [];
+ var visitedObj = visitor.get(obj);
+ var id;
+
+ if (visitedObj) {
+ id = visitedObj.id;
+ parts.push('"reference":'.concat(id));
+ } else {
+ id = visitor.set(obj);
+ parts.push('"id":'.concat(id));
+ }
+
+ parts.push('"type":"'.concat(t, '"'));
+
+ if (endWith(t, 'Function')) {
+ parts.push('"value":'.concat(wrapStr(toSrc(obj))));
+ } else if (t === 'RegExp') {
+ parts.push('"value":'.concat(wrapStr(obj)));
+ }
+
+ if (!visitedObj) {
+ var enumerableKeys = keys(obj);
+
+ if (enumerableKeys.length) {
+ parts.push(
+ iterateObj(
+ 'enumerable',
+ enumerableKeys,
+ self || obj,
+ options
+ )
+ );
+ }
+
+ if (unenumerable) {
+ var unenumerableKeys = difference(
+ allKeys(obj, {
+ prototype: false,
+ unenumerable: true
+ }),
+ enumerableKeys
+ );
+
+ if (unenumerableKeys.length) {
+ parts.push(
+ iterateObj(
+ 'unenumerable',
+ unenumerableKeys,
+ self || obj,
+ options
+ )
+ );
+ }
+ }
+
+ if (symbol) {
+ var symbolKeys = filter(
+ allKeys(obj, {
+ prototype: false,
+ symbol: true
+ }),
+ function(key) {
+ return _typeof(key) === 'symbol';
+ }
+ );
+
+ if (symbolKeys.length) {
+ parts.push(
+ iterateObj('symbol', symbolKeys, self || obj, options)
+ );
+ }
+ }
+
+ var prototype = getProto(obj);
+
+ if (prototype) {
+ var proto = '"proto":'.concat(
+ exports(
+ prototype,
+ extend(options, {
+ self: self || obj
+ })
+ )
+ );
+ parts.push(proto);
+ }
+ }
+
+ json += parts.join(',') + '}';
+ }
+
+ return json;
+ });
+
+ function iterateObj(name, keys, obj, options) {
+ var parts = [];
+ each(keys, function(key) {
+ var val;
+ var descriptor = Object.getOwnPropertyDescriptor(obj, key);
+ var hasGetter = descriptor && descriptor.get;
+ var hasSetter = descriptor && descriptor.set;
+
+ if (!options.accessGetter && hasGetter) {
+ val = '(...)';
+ } else {
+ try {
+ val = obj[key];
+
+ if (isPromise(val)) {
+ val.catch(function() {});
+ }
+ } catch (e) {
+ val = e.message;
+ }
+ }
+
+ parts.push(''.concat(wrapKey(key), ':').concat(exports(val, options)));
+
+ if (hasGetter) {
+ parts.push(
+ ''
+ .concat(wrapKey('get ' + toStr(key)), ':')
+ .concat(exports(descriptor.get, options))
+ );
+ }
+
+ if (hasSetter) {
+ parts.push(
+ ''
+ .concat(wrapKey('set ' + toStr(key)), ':')
+ .concat(exports(descriptor.set, options))
+ );
+ }
+ });
+ return '"'.concat(name, '":{') + parts.join(',') + '}';
+ }
+
+ function wrapKey(key) {
+ return '"'.concat(escapeJsonStr(key), '"');
+ }
+
+ function wrapStr(str) {
+ return '"'.concat(escapeJsonStr(toStr(str)), '"');
+ }
+
+ function escapeJsonStr(str) {
+ return escapeJsStr(str)
+ .replace(/\\'/g, "'")
+ .replace(/\t/g, '\\t');
+ }
+
+ var Visitor = Class({
+ initialize: function initialize() {
+ this.id = 0;
+ this.visited = [];
+ },
+ set: function set(val) {
+ var visited = this.visited,
+ id = this.id;
+ var obj = {
+ id: id,
+ val: val
+ };
+ visited.push(obj);
+ this.id++;
+ return id;
+ },
+ get: function get(val) {
+ var visited = this.visited;
+
+ for (var i = 0, len = visited.length; i < len; i++) {
+ var obj = visited[i];
+ if (val === obj.val) return obj;
+ }
+
+ return false;
+ }
+ });
+
+ return exports;
+})({});
+
export default _;
\ No newline at end of file
diff --git a/src/lib/stringifyWorker.js b/src/lib/stringifyWorker.js
index ae93aad..58f7fae 100644
--- a/src/lib/stringifyWorker.js
+++ b/src/lib/stringifyWorker.js
@@ -1,7 +1,7 @@
-import stringify from './stringify'
+import { stringifyAll } from './stringifyUtil'
onmessage = function(e) {
let [id, obj, options] = e.data
- let result = stringify(obj, options)
+ let result = stringifyAll(obj, options)
postMessage([id, result])
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 2c4d175..4507dfc 100644
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -1017,6 +1017,62 @@ export var detectOs = _.detectOs = (function (exports) {
return exports;
})({});
+/* ------------------------------ restArgs ------------------------------ */
+
+export var restArgs = _.restArgs = (function (exports) {
+ /* This accumulates the arguments passed into an array, after a given index.
+ *
+ * |Name |Type |Desc |
+ * |------------|--------|---------------------------------------|
+ * |function |function|Function that needs rest parameters |
+ * |[startIndex]|number |The start index to accumulates |
+ * |return |function|Generated function with rest parameters|
+ */
+
+ /* example
+ * var paramArr = restArgs(function (rest) { return rest });
+ * paramArr(1, 2, 3, 4); // -> [1, 2, 3, 4]
+ */
+
+ /* typescript
+ * export declare function restArgs(fn: Function, startIndex?: number): Function;
+ */
+ exports = function exports(fn, startIdx) {
+ startIdx = startIdx == null ? fn.length - 1 : +startIdx;
+ return function() {
+ var len = Math.max(arguments.length - startIdx, 0),
+ rest = new Array(len),
+ i;
+
+ for (i = 0; i < len; i++) {
+ rest[i] = arguments[i + startIdx];
+ } // Call runs faster than apply.
+
+ switch (startIdx) {
+ case 0:
+ return fn.call(this, rest);
+
+ case 1:
+ return fn.call(this, arguments[0], rest);
+
+ case 2:
+ return fn.call(this, arguments[0], arguments[1], rest);
+ }
+
+ var args = new Array(startIdx + 1);
+
+ for (i = 0; i < startIdx; i++) {
+ args[i] = arguments[i];
+ }
+
+ args[startIdx] = rest;
+ return fn.apply(this, args);
+ };
+ };
+
+ return exports;
+})({});
+
/* ------------------------------ optimizeCb ------------------------------ */
export var optimizeCb = _.optimizeCb = (function (exports) {
@@ -1569,6 +1625,49 @@ export var safeGet = _.safeGet = (function (exports) {
return exports;
})({});
+/* ------------------------------ flatten ------------------------------ */
+
+export var flatten = _.flatten = (function (exports) {
+ /* Recursively flatten an array.
+ *
+ * |Name |Type |Desc |
+ * |------|-----|-------------------|
+ * |arr |array|Array to flatten |
+ * |return|array|New flattened array|
+ */
+
+ /* example
+ * flatten(['a', ['b', ['c']], 'd', ['e']]); // -> ['a', 'b', 'c', 'd', 'e']
+ */
+
+ /* typescript
+ * export declare function flatten(arr: any[]): any[];
+ */
+
+ /* dependencies
+ * isArr
+ */
+
+ exports = function exports(arr) {
+ return flat(arr, []);
+ };
+
+ function flat(arr, res) {
+ var len = arr.length,
+ i = -1,
+ cur;
+
+ while (len--) {
+ cur = arr[++i];
+ isArr(cur) ? flat(cur, res) : res.push(cur);
+ }
+
+ return res;
+ }
+
+ return exports;
+})({});
+
/* ------------------------------ isDate ------------------------------ */
export var isDate = _.isDate = (function (exports) {
@@ -2536,6 +2635,37 @@ export var isNull = _.isNull = (function (exports) {
return exports;
})({});
+/* ------------------------------ isPromise ------------------------------ */
+
+export var isPromise = _.isPromise = (function (exports) {
+ /* Check if value looks like a promise.
+ *
+ * |Name |Type |Desc |
+ * |------|-------|----------------------------------|
+ * |val |* |Value to check |
+ * |return|boolean|True if value looks like a promise|
+ */
+
+ /* example
+ * isPromise(new Promise(function () {})); // -> true
+ * isPromise({}); // -> false
+ */
+
+ /* typescript
+ * export declare function isPromise(val: any): boolean;
+ */
+
+ /* dependencies
+ * isObj isFn
+ */
+
+ exports = function exports(val) {
+ return isObj(val) && isFn(val.then);
+ };
+
+ return exports;
+})({});
+
/* ------------------------------ isRegExp ------------------------------ */
export var isRegExp = _.isRegExp = (function (exports) {
@@ -3068,6 +3198,40 @@ export var filter = _.filter = (function (exports) {
return exports;
})({});
+/* ------------------------------ difference ------------------------------ */
+
+export var difference = _.difference = (function (exports) {
+ /* Create an array of unique array values not included in the other given array.
+ *
+ * |Name |Type |Desc |
+ * |---------|-----|----------------------------|
+ * |arr |array|Array to inspect |
+ * |[...rest]|array|Values to exclude |
+ * |return |array|New array of filtered values|
+ */
+
+ /* example
+ * difference([3, 2, 1], [4, 2]); // -> [3, 1]
+ */
+
+ /* typescript
+ * export declare function difference(arr: any[], ...rest: any[]): any[];
+ */
+
+ /* dependencies
+ * restArgs flatten filter contain
+ */
+
+ exports = restArgs(function(arr, rest) {
+ rest = flatten(rest);
+ return filter(arr, function(val) {
+ return !contain(rest, val);
+ });
+ });
+
+ return exports;
+})({});
+
/* ------------------------------ evalCss ------------------------------ */
export var evalCss = _.evalCss = (function (exports) {
@@ -5869,62 +6033,6 @@ export var now = _.now = (function (exports) {
return exports;
})({});
-/* ------------------------------ restArgs ------------------------------ */
-
-export var restArgs = _.restArgs = (function (exports) {
- /* This accumulates the arguments passed into an array, after a given index.
- *
- * |Name |Type |Desc |
- * |------------|--------|---------------------------------------|
- * |function |function|Function that needs rest parameters |
- * |[startIndex]|number |The start index to accumulates |
- * |return |function|Generated function with rest parameters|
- */
-
- /* example
- * var paramArr = restArgs(function (rest) { return rest });
- * paramArr(1, 2, 3, 4); // -> [1, 2, 3, 4]
- */
-
- /* typescript
- * export declare function restArgs(fn: Function, startIndex?: number): Function;
- */
- exports = function exports(fn, startIdx) {
- startIdx = startIdx == null ? fn.length - 1 : +startIdx;
- return function() {
- var len = Math.max(arguments.length - startIdx, 0),
- rest = new Array(len),
- i;
-
- for (i = 0; i < len; i++) {
- rest[i] = arguments[i + startIdx];
- } // Call runs faster than apply.
-
- switch (startIdx) {
- case 0:
- return fn.call(this, rest);
-
- case 1:
- return fn.call(this, arguments[0], rest);
-
- case 2:
- return fn.call(this, arguments[0], arguments[1], rest);
- }
-
- var args = new Array(startIdx + 1);
-
- for (i = 0; i < startIdx; i++) {
- args[i] = arguments[i];
- }
-
- args[startIdx] = rest;
- return fn.apply(this, args);
- };
- };
-
- return exports;
-})({});
-
/* ------------------------------ partial ------------------------------ */
export var partial = _.partial = (function (exports) {
@@ -7444,6 +7552,335 @@ export var LocalStore = _.LocalStore = (function (exports) {
return exports;
})({});
+/* ------------------------------ stringifyAll ------------------------------ */
+
+export var stringifyAll = _.stringifyAll = (function (exports) {
+ function _typeof(obj) {
+ if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') {
+ _typeof = function _typeof(obj) {
+ return typeof obj;
+ };
+ } else {
+ _typeof = function _typeof(obj) {
+ return obj &&
+ typeof Symbol === 'function' &&
+ obj.constructor === Symbol &&
+ obj !== Symbol.prototype
+ ? 'symbol'
+ : typeof obj;
+ };
+ }
+ return _typeof(obj);
+ }
+
+ /* Stringify object into json with types.
+ *
+ * |Name |Type |Desc |
+ * |---------|------|-------------------|
+ * |obj |* |Object to stringify|
+ * |[options]|object|Stringify options |
+ * |return |string|Stringified object |
+ *
+ * Available options:
+ *
+ * |Name |Type |Desc |
+ * |------------------|-------|-------------------------|
+ * |unenumerable=false|boolean|Include unenumerable keys|
+ * |symbol=false |boolean|Include symbol keys |
+ * |accessGetter=false|boolean|Access getter value |
+ * |timeout=0 |number |Timeout of stringify |
+ * |depth=0 |number |Max depth of recursion |
+ *
+ * When time is out, all remaining values will all be "Timeout".
+ */
+
+ /* example
+ * stringifyAll(function test() {}); // -> '{"value":"function test() {}","type":"Function",...}'
+ */
+
+ /* typescript
+ * export declare namespace stringifyAll {
+ * interface IOptions {
+ * unenumerable?: boolean;
+ * symbol?: boolean;
+ * accessGetter?: boolean;
+ * timeout?: number;
+ * depth?: number;
+ * }
+ * }
+ * export declare function stringifyAll(
+ * obj: any,
+ * options?: stringifyAll.IOptions
+ * ): string;
+ */
+
+ /* dependencies
+ * escapeJsStr type toStr endWith toSrc keys each Class getProto difference extend isPromise filter now allKeys
+ */
+
+ exports = (function(_exports) {
+ function exports(_x) {
+ return _exports.apply(this, arguments);
+ }
+
+ exports.toString = function() {
+ return _exports.toString();
+ };
+
+ return exports;
+ })(function(obj) {
+ var _ref =
+ arguments.length > 1 && arguments[1] !== undefined
+ ? arguments[1]
+ : {},
+ self = _ref.self,
+ _ref$startTime = _ref.startTime,
+ startTime = _ref$startTime === void 0 ? now() : _ref$startTime,
+ _ref$timeout = _ref.timeout,
+ timeout = _ref$timeout === void 0 ? 0 : _ref$timeout,
+ _ref$depth = _ref.depth,
+ depth = _ref$depth === void 0 ? 0 : _ref$depth,
+ _ref$curDepth = _ref.curDepth,
+ curDepth = _ref$curDepth === void 0 ? 1 : _ref$curDepth,
+ _ref$visitor = _ref.visitor,
+ visitor = _ref$visitor === void 0 ? new Visitor() : _ref$visitor,
+ _ref$unenumerable = _ref.unenumerable,
+ unenumerable = _ref$unenumerable === void 0 ? false : _ref$unenumerable,
+ _ref$symbol = _ref.symbol,
+ symbol = _ref$symbol === void 0 ? false : _ref$symbol,
+ _ref$accessGetter = _ref.accessGetter,
+ accessGetter = _ref$accessGetter === void 0 ? false : _ref$accessGetter;
+
+ var json = '';
+ var options = {
+ visitor: visitor,
+ unenumerable: unenumerable,
+ symbol: symbol,
+ accessGetter: accessGetter,
+ depth: depth,
+ curDepth: curDepth + 1,
+ timeout: timeout,
+ startTime: startTime
+ };
+ var t = type(obj, false);
+
+ if (t === 'String') {
+ json = wrapStr(obj);
+ } else if (t === 'Number') {
+ json = toStr(obj);
+
+ if (endWith(json, 'Infinity')) {
+ json = '{"value":"'.concat(json, '","type":"Number"}');
+ }
+ } else if (t === 'NaN') {
+ json = '{"value":"NaN","type":"Number"}';
+ } else if (t === 'Boolean') {
+ json = obj ? 'true' : 'false';
+ } else if (t === 'Null') {
+ json = 'null';
+ } else if (t === 'Undefined') {
+ json = '{"type":"Undefined"}';
+ } else if (t === 'Symbol') {
+ var val = 'Symbol';
+
+ try {
+ val = toStr(obj);
+ /* eslint-disable no-empty */
+ } catch (e) {}
+
+ json = '{"value":'.concat(wrapStr(val), ',"type":"Symbol"}');
+ } else {
+ if (timeout && now() - startTime > timeout) {
+ return wrapStr('Timeout');
+ }
+
+ if (depth && curDepth > depth) {
+ return wrapStr('{...}');
+ }
+
+ json = '{';
+ var parts = [];
+ var visitedObj = visitor.get(obj);
+ var id;
+
+ if (visitedObj) {
+ id = visitedObj.id;
+ parts.push('"reference":'.concat(id));
+ } else {
+ id = visitor.set(obj);
+ parts.push('"id":'.concat(id));
+ }
+
+ parts.push('"type":"'.concat(t, '"'));
+
+ if (endWith(t, 'Function')) {
+ parts.push('"value":'.concat(wrapStr(toSrc(obj))));
+ } else if (t === 'RegExp') {
+ parts.push('"value":'.concat(wrapStr(obj)));
+ }
+
+ if (!visitedObj) {
+ var enumerableKeys = keys(obj);
+
+ if (enumerableKeys.length) {
+ parts.push(
+ iterateObj(
+ 'enumerable',
+ enumerableKeys,
+ self || obj,
+ options
+ )
+ );
+ }
+
+ if (unenumerable) {
+ var unenumerableKeys = difference(
+ allKeys(obj, {
+ prototype: false,
+ unenumerable: true
+ }),
+ enumerableKeys
+ );
+
+ if (unenumerableKeys.length) {
+ parts.push(
+ iterateObj(
+ 'unenumerable',
+ unenumerableKeys,
+ self || obj,
+ options
+ )
+ );
+ }
+ }
+
+ if (symbol) {
+ var symbolKeys = filter(
+ allKeys(obj, {
+ prototype: false,
+ symbol: true
+ }),
+ function(key) {
+ return _typeof(key) === 'symbol';
+ }
+ );
+
+ if (symbolKeys.length) {
+ parts.push(
+ iterateObj('symbol', symbolKeys, self || obj, options)
+ );
+ }
+ }
+
+ var prototype = getProto(obj);
+
+ if (prototype) {
+ var proto = '"proto":'.concat(
+ exports(
+ prototype,
+ extend(options, {
+ self: self || obj
+ })
+ )
+ );
+ parts.push(proto);
+ }
+ }
+
+ json += parts.join(',') + '}';
+ }
+
+ return json;
+ });
+
+ function iterateObj(name, keys, obj, options) {
+ var parts = [];
+ each(keys, function(key) {
+ var val;
+ var descriptor = Object.getOwnPropertyDescriptor(obj, key);
+ var hasGetter = descriptor && descriptor.get;
+ var hasSetter = descriptor && descriptor.set;
+
+ if (!options.accessGetter && hasGetter) {
+ val = '(...)';
+ } else {
+ try {
+ val = obj[key];
+
+ if (isPromise(val)) {
+ val.catch(function() {});
+ }
+ } catch (e) {
+ val = e.message;
+ }
+ }
+
+ parts.push(''.concat(wrapKey(key), ':').concat(exports(val, options)));
+
+ if (hasGetter) {
+ parts.push(
+ ''
+ .concat(wrapKey('get ' + toStr(key)), ':')
+ .concat(exports(descriptor.get, options))
+ );
+ }
+
+ if (hasSetter) {
+ parts.push(
+ ''
+ .concat(wrapKey('set ' + toStr(key)), ':')
+ .concat(exports(descriptor.set, options))
+ );
+ }
+ });
+ return '"'.concat(name, '":{') + parts.join(',') + '}';
+ }
+
+ function wrapKey(key) {
+ return '"'.concat(escapeJsonStr(key), '"');
+ }
+
+ function wrapStr(str) {
+ return '"'.concat(escapeJsonStr(toStr(str)), '"');
+ }
+
+ function escapeJsonStr(str) {
+ return escapeJsStr(str)
+ .replace(/\\'/g, "'")
+ .replace(/\t/g, '\\t');
+ }
+
+ var Visitor = Class({
+ initialize: function initialize() {
+ this.id = 0;
+ this.visited = [];
+ },
+ set: function set(val) {
+ var visited = this.visited,
+ id = this.id;
+ var obj = {
+ id: id,
+ val: val
+ };
+ visited.push(obj);
+ this.id++;
+ return id;
+ },
+ get: function get(val) {
+ var visited = this.visited;
+
+ for (var i = 0, len = visited.length; i < len; i++) {
+ var obj = visited[i];
+ if (val === obj.val) return obj;
+ }
+
+ return false;
+ }
+ });
+
+ return exports;
+})({});
+
/* ------------------------------ stripHtmlTag ------------------------------ */
export var stripHtmlTag = _.stripHtmlTag = (function (exports) {