diff options
Diffstat (limited to 'node_modules/concordance/lib/serialize.js')
-rw-r--r-- | node_modules/concordance/lib/serialize.js | 339 |
1 files changed, 0 insertions, 339 deletions
diff --git a/node_modules/concordance/lib/serialize.js b/node_modules/concordance/lib/serialize.js deleted file mode 100644 index 07f568415..000000000 --- a/node_modules/concordance/lib/serialize.js +++ /dev/null @@ -1,339 +0,0 @@ -'use strict' - -const md5hex = require('md5-hex') - -const encoder = require('./encoder') -const pluginRegistry = require('./pluginRegistry') - -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 pointerDescriptor = require('./metaDescriptors/pointer') -const propertyDescriptor = require('./metaDescriptors/property') -const statsDescriptors = require('./metaDescriptors/stats') - -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') - -// 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 = 2 - -// Adding or removing mappings or changing an index requires the version in -// encoder.js to be bumped, which necessitates a major version bump of -// Concordance itself. Indexes are hexadecimal to make reading the binary -// output easier. -const mappings = [ - [0x01, booleanValue.tag, booleanValue.deserialize], - [0x02, nullValue.tag, nullValue.deserialize], - [0x03, numberValue.tag, numberValue.deserialize], - [0x04, stringValue.tag, stringValue.deserialize], - [0x05, symbolValue.tag, symbolValue.deserialize], - [0x06, undefinedValue.tag, undefinedValue.deserialize], - - [0x07, objectValue.tag, objectValue.deserialize], - [0x08, statsDescriptors.iterableTag, statsDescriptors.deserializeIterableStats], - [0x09, statsDescriptors.listTag, statsDescriptors.deserializeListStats], - [0x0A, itemDescriptor.complexTag, itemDescriptor.deserializeComplex], - [0x0B, itemDescriptor.primitiveTag, itemDescriptor.deserializePrimitive], - [0x0C, statsDescriptors.propertyTag, statsDescriptors.deserializePropertyStats], - [0x0D, propertyDescriptor.complexTag, propertyDescriptor.deserializeComplex], - [0x0E, propertyDescriptor.primitiveTag, propertyDescriptor.deserializePrimitive], - [0x0F, pointerDescriptor.tag, pointerDescriptor.deserialize], - - [0x10, mapValue.tag, mapValue.deserialize], - [0x11, mapEntryDescriptor.tag, mapEntryDescriptor.deserialize], - - [0x12, argumentsValue.tag, argumentsValue.deserialize], - [0x13, arrayBufferValue.tag, arrayBufferValue.deserialize], - [0x14, boxedValue.tag, boxedValue.deserialize], - [0x15, dataViewValue.tag, dataViewValue.deserialize], - [0x16, dateValue.tag, dateValue.deserialize], - [0x17, errorValue.tag, errorValue.deserialize], - [0x18, functionValue.tag, functionValue.deserialize], - [0x19, globalValue.tag, globalValue.deserialize], - [0x1A, promiseValue.tag, promiseValue.deserialize], - [0x1B, regexpValue.tag, regexpValue.deserialize], - [0x1C, setValue.tag, setValue.deserialize], - [0x1D, typedArrayValue.tag, typedArrayValue.deserialize], - [0x1E, 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 - } -} - -class MissingPluginError extends Error { - 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 - } -} - -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 - } -} - -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 - - return serializeState(descriptor.serialize(), resolvePluginRef) -} - -function serializeState (state, resolvePluginRef) { - if (Array.isArray(state)) return state.map(serializeState) - - 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 -} - -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) -} -exports.serialize = serialize - -function deserializeState (state, getDescriptorDeserializer) { - if (state && state[encoder.descriptorSymbol] === true) { - return shallowDeserializeDescriptor(state, getDescriptorDeserializer) - } - - 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]) -} - -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) - } - - 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) - } - - 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 -} - -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)) throw new PointerLookupError(descriptor.index) - - return descriptorsByPointerIndex.get(descriptor.index) - } else 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)) - } - } - return deserializeRecord(decoded.rootRecord, getDescriptorDeserializer, buffer) -} -exports.deserialize = deserialize |