diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-08-14 05:01:11 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-08-14 05:02:09 +0200 |
commit | 363723fc84f7b8477592e0105aeb331ec9a017af (patch) | |
tree | 29f92724f34131bac64d6a318dd7e30612e631c7 /node_modules/concordance/lib/pluginRegistry.js | |
parent | 5634e77ad96bfe1818f6b6ee70b7379652e5487f (diff) | |
download | wallet-core-363723fc84f7b8477592e0105aeb331ec9a017af.tar.xz |
node_modules
Diffstat (limited to 'node_modules/concordance/lib/pluginRegistry.js')
-rw-r--r-- | node_modules/concordance/lib/pluginRegistry.js | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/node_modules/concordance/lib/pluginRegistry.js b/node_modules/concordance/lib/pluginRegistry.js new file mode 100644 index 000000000..b4fb76b37 --- /dev/null +++ b/node_modules/concordance/lib/pluginRegistry.js @@ -0,0 +1,222 @@ +'use strict' + +const semver = require('semver') + +const pkg = require('../package.json') +const constants = require('./constants') +const object = require('./complexValues/object') +const lineBuilder = require('./lineBuilder') +const formatUtils = require('./formatUtils') +const itemDescriptor = require('./metaDescriptors/item') +const propertyDescriptor = require('./metaDescriptors/property') +const stringDescriptor = require('./primitiveValues/string') +const recursorUtils = require('./recursorUtils') +const themeUtils = require('./themeUtils') + +const API_VERSION = 1 +const CONCORDANCE_VERSION = pkg.version + +const descriptorRegistry = new Map() +const registry = new Map() + +class PluginError extends Error { + constructor (message, plugin) { + super(message) + this.name = 'PluginError' + this.plugin = plugin + } +} + +class PluginTypeError extends TypeError { + constructor (message, plugin) { + super(message) + this.name = 'PluginTypeError' + this.plugin = plugin + } +} + +class UnsupportedApiError extends PluginError { + constructor (plugin) { + super('Plugin requires an unsupported API version', plugin) + this.name = 'UnsupportedApiError' + } +} + +class UnsupportedError extends PluginError { + constructor (plugin) { + super('Plugin does not support this version of Concordance', plugin) + this.name = 'UnsupportedError' + } +} + +class DuplicateDescriptorTagError extends PluginError { + constructor (tag, plugin) { + super(`Could not add descriptor: tag ${String(tag)} has already been registered`, plugin) + this.name = 'DuplicateDescriptorTagError' + this.tag = tag + } +} + +class DuplicateDescriptorIdError extends PluginError { + constructor (id, plugin) { + const printed = typeof id === 'number' + ? `0x${id.toString(16).toUpperCase()}` + : String(id) + super(`Could not add descriptor: id ${printed} has already been registered`, plugin) + this.name = 'DuplicateDescriptorIdError' + this.id = id + } +} + +function verify (plugin) { + if (typeof plugin.name !== 'string' || !plugin.name) { + throw new PluginTypeError('Plugin must have a `name`', plugin) + } + + if (plugin.apiVersion !== API_VERSION) { + throw new UnsupportedApiError(plugin) + } + + if ('minimalConcordanceVersion' in plugin) { + if (!semver.valid(plugin.minimalConcordanceVersion)) { + throw new PluginTypeError('If specified, `minimalConcordanceVersion` must be a valid SemVer version', plugin) + } + + const range = `>=${plugin.minimalConcordanceVersion}` + if (!semver.satisfies(CONCORDANCE_VERSION, range)) { + throw new UnsupportedError(plugin) + } + } +} + +// Selectively expose descriptor tags. +const publicDescriptorTags = Object.freeze({ + complexItem: itemDescriptor.complexTag, + primitiveItem: itemDescriptor.primitiveTag, + primitiveProperty: propertyDescriptor.primitiveTag, + string: stringDescriptor.tag +}) + +// Don't expose `setDefaultGutter()`. +const publicLineBuilder = Object.freeze({ + buffer: lineBuilder.buffer, + first: lineBuilder.first, + last: lineBuilder.last, + line: lineBuilder.line, + single: lineBuilder.single, + actual: Object.freeze({ + buffer: lineBuilder.actual.buffer, + first: lineBuilder.actual.first, + last: lineBuilder.actual.last, + line: lineBuilder.actual.line, + single: lineBuilder.actual.single + }), + expected: Object.freeze({ + buffer: lineBuilder.expected.buffer, + first: lineBuilder.expected.first, + last: lineBuilder.expected.last, + line: lineBuilder.expected.line, + single: lineBuilder.expected.single + }) +}) + +function modifyTheme (descriptor, modifier) { + themeUtils.addModifier(descriptor, modifier) + return descriptor +} + +function add (plugin) { + verify(plugin) + + const name = plugin.name + if (registry.has(name)) return registry.get(name) + + const id2deserialize = new Map() + const tag2id = new Map() + const addDescriptor = (id, tag, deserialize) => { + if (id2deserialize.has(id)) throw new DuplicateDescriptorIdError(id, plugin) + if (descriptorRegistry.has(tag) || tag2id.has(tag)) throw new DuplicateDescriptorTagError(tag, plugin) + + id2deserialize.set(id, deserialize) + tag2id.set(tag, id) + } + + const tryDescribeValue = plugin.register({ + // Concordance makes assumptions about when AMBIGUOUS occurs. Do not expose + // it to plugins. + UNEQUAL: constants.UNEQUAL, + SHALLOW_EQUAL: constants.SHALLOW_EQUAL, + DEEP_EQUAL: constants.DEEP_EQUAL, + + ObjectValue: object.ObjectValue, + DescribedMixin: object.DescribedMixin, + DeserializedMixin: object.DeserializedMixin, + + addDescriptor, + applyThemeModifiers: themeUtils.applyModifiers, + descriptorTags: publicDescriptorTags, + lineBuilder: publicLineBuilder, + mapRecursor: recursorUtils.map, + modifyTheme, + wrapFromTheme: formatUtils.wrap + }) + + const registered = { + id2deserialize, + serializerVersion: plugin.serializerVersion, + name, + tag2id, + theme: plugin.theme || {}, + tryDescribeValue + } + + registry.set(name, registered) + for (const tag of tag2id.keys()) { + descriptorRegistry.set(tag, registered) + } + + return registered +} +exports.add = add + +function getDeserializers (plugins) { + return plugins.map(plugin => { + const registered = add(plugin) + return { + id2deserialize: registered.id2deserialize, + name: registered.name, + serializerVersion: registered.serializerVersion + } + }) +} +exports.getDeserializers = getDeserializers + +function getThemes (plugins) { + return plugins.map(plugin => { + const registered = add(plugin) + return { + name: registered.name, + theme: registered.theme + } + }) +} +exports.getThemes = getThemes + +function getTryDescribeValues (plugins) { + return plugins.map(plugin => add(plugin).tryDescribeValue) +} +exports.getTryDescribeValues = getTryDescribeValues + +function resolveDescriptorRef (tag) { + if (!descriptorRegistry.has(tag)) return null + + const registered = descriptorRegistry.get(tag) + return { + id: registered.tag2id.get(tag), + name: registered.name, + serialization: { + serializerVersion: registered.serializerVersion + } + } +} +exports.resolveDescriptorRef = resolveDescriptorRef |