allow default interface impl

This commit is contained in:
Rowan 2025-04-05 22:50:38 -05:00
parent 699a8e6a7c
commit e213666051

View file

@ -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)