wallet-core/node_modules/concordance/lib/describe.js
2017-08-14 05:02:09 +02:00

171 lines
5.7 KiB
JavaScript

'use strict'
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 itemDescriptor = require('./metaDescriptors/item')
const mapEntryDescriptor = require('./metaDescriptors/mapEntry')
const propertyDescriptor = require('./metaDescriptors/property')
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 getCtor = require('./getCtor')
const getStringTag = require('./getStringTag')
const pluginRegistry = require('./pluginRegistry')
const Registry = require('./Registry')
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]
])
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 === 'number') return numberValue.describe(value)
if (type === 'string') return stringValue.describe(value)
if (type === 'symbol') return symbolValue.describe(value)
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
}
function registerPlugins (plugins) {
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
}
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
}
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 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 describeProperty = (key, valueDescriptor) => {
const keyDescriptor = describePrimitive(key)
return valueDescriptor.isPrimitive === true
? propertyDescriptor.describePrimitive(keyDescriptor, valueDescriptor)
: propertyDescriptor.describeComplex(keyDescriptor, valueDescriptor)
}
return curriedComplex(value)
}
module.exports = describe