allow default interface impl
This commit is contained in:
parent
699a8e6a7c
commit
e213666051
1 changed files with 39 additions and 8 deletions
|
@ -1,6 +1,7 @@
|
||||||
import { mix } from '../mixin.js'
|
import { mix } from '../mixin.js'
|
||||||
|
|
||||||
/** @import { MixinFunction } from '../mixin.js' */
|
/** @import { MixinFunction } from '../mixin.js' */
|
||||||
|
/** @import { Fn } from './types.js' */
|
||||||
|
|
||||||
export const ProtectedConstructor = Symbol('ProtectedConstructor')
|
export const ProtectedConstructor = Symbol('ProtectedConstructor')
|
||||||
export class ProtectedConstructorError extends Error {
|
export class ProtectedConstructorError extends Error {
|
||||||
|
@ -76,6 +77,9 @@ class Method {
|
||||||
/** @type {MethodType} */
|
/** @type {MethodType} */
|
||||||
#type = MethodType.Instance
|
#type = MethodType.Instance
|
||||||
|
|
||||||
|
/** @type {Fn} */
|
||||||
|
#implementation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string | Method} name
|
* @param {string | Method} name
|
||||||
*/
|
*/
|
||||||
|
@ -104,6 +108,23 @@ class Method {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {Fn} f */
|
||||||
|
implementation(f) {
|
||||||
|
this.#implementation = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} interfaceName
|
||||||
|
*/
|
||||||
|
_defaultImplementation(interfaceName) {
|
||||||
|
const err = new NotImplementedError(
|
||||||
|
`${interfaceName}::${this.#name}`
|
||||||
|
)
|
||||||
|
|
||||||
|
return function() { throw err }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Function} target
|
* @param {Function} target
|
||||||
*/
|
*/
|
||||||
|
@ -120,13 +141,10 @@ class Method {
|
||||||
* @param {Function} target
|
* @param {Function} target
|
||||||
*/
|
*/
|
||||||
implement(builder, target) {
|
implement(builder, target) {
|
||||||
const err = new NotImplementedError(
|
|
||||||
`${builder.name}::${this.#name}`
|
|
||||||
)
|
|
||||||
|
|
||||||
this._getInstallationPoint(target)[this.#name] = function() {
|
const impl = this.#implementation || this._defaultImplementation(builder.name)
|
||||||
throw err
|
|
||||||
}
|
this._getInstallationPoint(target)[this.#name] = impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +214,15 @@ class Interface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseSet { }
|
/** @template T*/
|
||||||
|
class BaseSet {
|
||||||
|
_value
|
||||||
|
|
||||||
|
/** @param {T} value */
|
||||||
|
constructor(value) {
|
||||||
|
this._value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PropertyKey} key
|
* @param {PropertyKey} key
|
||||||
|
@ -301,7 +327,12 @@ export const Traversable = new Interface('Traversable')
|
||||||
|
|
||||||
export const Chain = new Interface('Chain')
|
export const Chain = new Interface('Chain')
|
||||||
.extends(Apply)
|
.extends(Apply)
|
||||||
.specifies('chain')
|
.specifies(
|
||||||
|
Method.from('chain')
|
||||||
|
.implementation(function(f) {
|
||||||
|
return f(this._value)
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
export const ChainRef = new Interface('ChainRec')
|
export const ChainRef = new Interface('ChainRec')
|
||||||
.extends(Chain)
|
.extends(Chain)
|
||||||
|
|
Loading…
Add table
Reference in a new issue