summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/pacote/node_modules/protoduck/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/pacote/node_modules/protoduck/index.js')
-rw-r--r--deps/npm/node_modules/pacote/node_modules/protoduck/index.js349
1 files changed, 349 insertions, 0 deletions
diff --git a/deps/npm/node_modules/pacote/node_modules/protoduck/index.js b/deps/npm/node_modules/pacote/node_modules/protoduck/index.js
new file mode 100644
index 0000000000..3596bb3299
--- /dev/null
+++ b/deps/npm/node_modules/pacote/node_modules/protoduck/index.js
@@ -0,0 +1,349 @@
+'use strict'
+
+const genfun = require('genfun')
+
+class Duck extends Function {
+ // Duck.impl(Foo, [String, Array], { frob (str, arr) { ... }})
+ impl (target, types, impls) {
+ if (!impls && !isArray(types)) {
+ impls = types
+ types = []
+ }
+ if (!impls && this.isDerivable) {
+ impls = this._defaultImpls
+ }
+ if (!impls) {
+ impls = {}
+ }
+ if (typeof target === 'function' && !target.isGenfun) {
+ target = target.prototype
+ }
+ checkImpls(this, target, impls)
+ checkArgTypes(this, types)
+ this._constraints.forEach(c => {
+ if (!c.verify(target, types)) {
+ throw new Error(`Implementations of ${
+ this.name || 'this protocol'
+ } must first implement ${
+ c.parent.name || 'its constraint protocols defined in opts.where.'
+ }`)
+ }
+ })
+ this._methodNames.forEach(name => {
+ defineMethod(this, name, target, types, impls)
+ })
+ }
+
+ hasImpl (arg, args) {
+ args = args || []
+ const fns = this._methodNames
+ var gf
+ if (typeof arg === 'function' && !arg.isGenfun) {
+ arg = arg.prototype
+ }
+ args = args.map(arg => {
+ if (typeof arg === 'function' && !arg.isGenfun) {
+ return arg.prototype
+ } else {
+ return arg
+ }
+ })
+ for (var i = 0; i < fns.length; i++) {
+ gf = arg[fns[i]]
+ if (!gf ||
+ (gf.hasMethod
+ ? !gf.hasMethod.apply(gf, args)
+ : typeof gf === 'function')) {
+ return false
+ }
+ }
+ return true
+ }
+
+ // MyDuck.matches('a', ['this', 'c'])
+ matches (thisType, argTypes) {
+ if (!argTypes && isArray(thisType)) {
+ argTypes = thisType
+ thisType = 'this'
+ }
+ if (!thisType) {
+ thisType = 'this'
+ }
+ if (!argTypes) {
+ argTypes = []
+ }
+ return new Constraint(this, thisType, argTypes)
+ }
+}
+Duck.prototype.isDuck = true
+Duck.prototype.isProtocol = true
+
+const Protoduck = module.exports = define(['duck'], {
+ createGenfun: ['duck', _metaCreateGenfun],
+ addMethod: ['duck', _metaAddMethod]
+}, {name: 'Protoduck'})
+
+const noImplFound = module.exports.noImplFound = genfun.noApplicableMethod
+
+module.exports.define = define
+function define (types, spec, opts) {
+ if (!isArray(types)) {
+ // protocol(spec, opts?) syntax for method-based protocols
+ opts = spec
+ spec = types
+ types = []
+ }
+ const duck = function (thisType, argTypes) {
+ return duck.matches(thisType, argTypes)
+ }
+ Object.setPrototypeOf(duck, Duck.prototype)
+ duck.isDerivable = true
+ Object.defineProperty(duck, 'name', {
+ value: (opts && opts.name) || 'Protocol'
+ })
+ if (opts && opts.where) {
+ let where = opts.where
+ if (!isArray(opts.where)) { where = [opts.where] }
+ duck._constraints = where.map(w => w.isProtocol // `where: [Foo]`
+ ? w.matches()
+ : w
+ )
+ } else {
+ duck._constraints = []
+ }
+ duck.isProtocol = true
+ duck._metaobject = opts && opts.metaobject
+ duck._types = types
+ duck._defaultImpls = {}
+ duck._gfTypes = {}
+ duck._methodNames = Object.keys(spec)
+ duck._methodNames.forEach(name => {
+ checkMethodSpec(duck, name, spec)
+ })
+ duck._constraints.forEach(c => c.attach(duck))
+ return duck
+}
+
+function checkMethodSpec (duck, name, spec) {
+ let gfTypes = spec[name]
+ if (typeof gfTypes === 'function') {
+ duck._defaultImpls[name] = gfTypes
+ gfTypes = [gfTypes]
+ } if (typeof gfTypes[gfTypes.length - 1] === 'function') {
+ duck._defaultImpls[name] = gfTypes.pop()
+ } else {
+ duck.isDerivable = false
+ }
+ duck._gfTypes[name] = gfTypes.map(typeId => {
+ const idx = duck._types.indexOf(typeId)
+ if (idx === -1) {
+ throw new Error(
+ `type '${
+ typeId
+ }' for function '${
+ name
+ }' does not match any protocol types (${
+ duck._types.join(', ')
+ }).`
+ )
+ } else {
+ return idx
+ }
+ })
+}
+
+function defineMethod (duck, name, target, types, impls) {
+ const methodTypes = duck._gfTypes[name].map(function (typeIdx) {
+ return types[typeIdx]
+ })
+ for (let i = methodTypes.length - 1; i >= 0; i--) {
+ if (methodTypes[i] === undefined) {
+ methodTypes.pop()
+ } else {
+ break
+ }
+ }
+ const useMetaobject = duck._metaobject && duck._metaobject !== Protoduck
+ // `target` does not necessarily inherit from `Object`
+ if (!Object.prototype.hasOwnProperty.call(target, name)) {
+ // Make a genfun if there's nothing there
+ const gf = useMetaobject
+ ? duck._metaobject.createGenfun(duck, target, name, null)
+ : _metaCreateGenfun(duck, target, name, null)
+ target[name] = gf
+ } else if (typeof target[name] === 'function' && !target[name].isGenfun) {
+ // Turn non-gf functions into genfuns
+ const gf = useMetaobject
+ ? duck._metaobject.createGenfun(duck, target, name, target[name])
+ : _metaCreateGenfun(duck, target, name, target[name])
+ target[name] = gf
+ }
+
+ const fn = impls[name] || duck._defaultImpls[name]
+ if (fn) { // checkImpls made sure this is safe
+ useMetaobject
+ ? duck._metaobject.addMethod(duck, target, name, methodTypes, fn)
+ : _metaAddMethod(duck, target, name, methodTypes, fn)
+ }
+}
+
+function checkImpls (duck, target, impls) {
+ duck._methodNames.forEach(function (name) {
+ if (
+ !impls[name] &&
+ !duck._defaultImpls[name] &&
+ // Existing methods on the target are acceptable defaults.
+ typeof target[name] !== 'function'
+ ) {
+ throw new Error(`Missing implementation for ${
+ formatMethod(duck, name, duck.name)
+ }. Make sure the method is present in your ${
+ duck.name || 'protocol'
+ } definition. Required methods: ${
+ duck._methodNames.filter(m => {
+ return !duck._defaultImpls[m]
+ }).map(m => formatMethod(duck, m)).join(', ')
+ }.`)
+ }
+ })
+ Object.keys(impls).forEach(function (name) {
+ if (duck._methodNames.indexOf(name) === -1) {
+ throw new Error(
+ `${name}() was included in the impl, but is not part of ${
+ duck.name || 'the protocol'
+ }. Allowed methods: ${
+ duck._methodNames.map(m => formatMethod(duck, m)).join(', ')
+ }.`
+ )
+ }
+ })
+}
+
+function formatMethod (duck, name, withDuckName) {
+ return `${
+ withDuckName && duck.name ? `${duck.name}#` : ''
+ }${name}(${duck._gfTypes[name].map(n => duck._types[n]).join(', ')})`
+}
+
+function checkArgTypes (duck, types) {
+ var requiredTypes = duck._types
+ if (types.length > requiredTypes.length) {
+ throw new Error(
+ `${
+ duck.name || 'Protocol'
+ } expects to be defined across ${
+ requiredTypes.length
+ } type${requiredTypes.length > 1 ? 's' : ''}, but ${
+ types.length
+ } ${types.length > 1 ? 'were' : 'was'} specified.`
+ )
+ }
+}
+
+function typeName (obj) {
+ return (/\[object ([a-zA-Z0-9]+)\]/).exec(({}).toString.call(obj))[1]
+}
+
+function installMethodErrorMessage (proto, gf, target, name) {
+ noImplFound.add([gf], function (gf, thisArg, args) {
+ let parent = Object.getPrototypeOf(thisArg)
+ while (parent && parent[name] === gf) {
+ parent = Object.getPrototypeOf(parent)
+ }
+ if (parent && parent[name] && typeof parent[name] === 'function') {
+ }
+ var msg = `No ${typeName(thisArg)} impl for ${
+ proto.name ? `${proto.name}#` : ''
+ }${name}(${[].map.call(args, typeName).join(', ')}). You must implement ${
+ proto.name
+ ? formatMethod(proto, name, true)
+ : `the protocol ${formatMethod(proto, name)} belongs to`
+ } in order to call ${typeName(thisArg)}#${name}(${
+ [].map.call(args, typeName).join(', ')
+ }).`
+ const err = new Error(msg)
+ err.protocol = proto
+ err.function = gf
+ err.thisArg = thisArg
+ err.args = args
+ err.code = 'ENOIMPL'
+ throw err
+ })
+}
+
+function isArray (x) {
+ return Object.prototype.toString.call(x) === '[object Array]'
+}
+
+// Metaobject Protocol
+Protoduck.impl(Protoduck) // defaults configured by definition
+
+function _metaCreateGenfun (proto, target, name, deflt) {
+ var gf = genfun({
+ default: deflt,
+ name: `${proto.name ? `${proto.name}#` : ''}${name}`
+ })
+ installMethodErrorMessage(proto, gf, target, name)
+ gf.duck = proto
+ return gf
+}
+
+function _metaAddMethod (duck, target, name, methodTypes, fn) {
+ return target[name].add(methodTypes, fn)
+}
+
+// Constraints
+class Constraint {
+ constructor (parent, thisType, argTypes) {
+ this.parent = parent
+ this.target = thisType
+ this.types = argTypes
+ }
+
+ attach (obj) {
+ this.child = obj
+ if (this.target === 'this') {
+ this.thisIdx = 'this'
+ } else {
+ const idx = this.child._types.indexOf(this.target)
+ if (idx === -1) {
+ this.thisIdx = null
+ } else {
+ this.thisIdx = idx
+ }
+ }
+ this.indices = this.types.map(typeId => {
+ if (typeId === 'this') {
+ return 'this'
+ } else {
+ const idx = this.child._types.indexOf(typeId)
+ if (idx === -1) {
+ return null
+ } else {
+ return idx
+ }
+ }
+ })
+ }
+
+ verify (target, types) {
+ const thisType = (
+ this.thisIdx === 'this' || this.thisIdx == null
+ )
+ ? target
+ : types[this.thisIdx]
+ const parentTypes = this.indices.map(idx => {
+ if (idx === 'this') {
+ return target
+ } else if (idx === 'this') {
+ return types[this.thisIdx]
+ } else if (idx === null) {
+ return Object
+ } else {
+ return types[idx] || Object.prototype
+ }
+ })
+ return this.parent.hasImpl(thisType, parentTypes)
+ }
+}
+Constraint.prototype.isConstraint = true