@aedart/support
Version:
The Ion support package
1,047 lines (1,026 loc) • 32.5 kB
JavaScript
/**
* @aedart/support
*
* BSD-3-Clause, Copyright (c) 2023-present Alin Eugen Deac <aedart@gmail.com>.
*/
'use strict';
var misc = require('@aedart/support/misc');
var meta$1 = require('@aedart/contracts/support/meta');
var objects = require('@aedart/support/objects');
var exceptions = require('@aedart/support/exceptions');
var reflections = require('@aedart/contracts/support/reflections');
/**
* Meta Entry
*
* @see MetaEntry
*/
class Entry {
/**
* Key or path identifier
*
* @type {Key}
*/
key;
/**
* Value to store
*
* @type {unknown}
*/
value;
/**
* Create a new Meta Entry instance
*
* @param {Key} key
* @param {unknown} value
*/
constructor(key, value) {
this.key = key;
this.value = value;
}
/**
* Create a new Meta Entry instance
*
* @param {Key} key
* @param {unknown} value
*
* @return {this|MetaEntry}
*
* @static
*/
static make(key, value) {
return new this(key, value);
}
/**
* Resolves given key and returns a new Meta Entry instance
*
* @param {MetaTargetContext} targetContext
* @param {Key | MetaCallback} key
* @param {any} [value]
*
* @return {this|MetaEntry}
*
* @static
*/
static resolve(targetContext, key, value) {
if (typeof key === 'function') {
return key(targetContext.target, targetContext.context, targetContext.owner);
}
return this.make(key, value);
}
/**
* Resolves given key-value pair and returns a new Meta Entry instance, with prefixed key
*
* @param {MetaTargetContext} targetContext
* @param {Key} prefixKey
* @param {Key|MetaCallback} key
* @param {unknown} [value]
*
* @return {this|MetaEntry}
*
* @static
*/
static resolveWithPrefix(targetContext, prefixKey, key, value) {
const entry = this.resolve(targetContext, key, value);
entry.key = misc.mergeKeys(prefixKey, entry.key);
return entry;
}
}
/**
* Meta Target Context
*
* @see MetaTargetContext
*/
class TargetContext {
/**
* The class that owns the meta
*
* @type {object}
*/
owner;
/**
* "This" argument
*
* @type {any}
*/
thisArg; /* eslint-disable-line @typescript-eslint/no-explicit-any */
/**
* The target class, field, method... that is being decorated
*
* @type {object}
*/
target;
/**
* Decorator context
*
* @type {Context}
*/
context;
/**
* Create a new Meta Target Context instance
*
* @param {object} owner
* @param {any} thisArg
* @param {object} target
* @param {Context} context
*/
constructor(owner, thisArg, /* eslint-disable-line @typescript-eslint/no-explicit-any */ target, context) {
this.owner = owner;
this.thisArg = thisArg;
this.target = target;
this.context = context;
}
/**
* Returns a new Meta Target Context instance
*
* @param {object} owner
* @param {any} thisArg
* @param {object} target
* @param {Context} context
*
* @return {this|MetaTargetContext}
*
* @static
*/
static make(owner, thisArg, /* eslint-disable-line @typescript-eslint/no-explicit-any */ target, context) {
return new this(owner, thisArg, target, context);
}
/**
* Resolves target's owner and returns a new Meta Target Instance
*
* @param {object} target
* @param {object} thisArg
* @param {Context} context
*
* @return {this|MetaTargetContext}
*
* @static
*/
static resolveOwner(target, thisArg, context) {
// Resolve the target's "owner"
// @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#class_context
const owner = (context.kind === 'class' || context.static)
? thisArg
// When target is not static, then it's obtainable via prototype
: Reflect.getPrototypeOf(thisArg).constructor;
return this.make(owner, thisArg, target, context);
}
}
/**
* Fallback registry that contains writable metadata (`context.metadata`).
*
* This registry is only to be used when the system / browser does not support
* `context.metadata`.
*
* **Warning**: _This registry is **NOT intended** to be available for writing,
* outside the scope of a "meta" decorator._
*
* @type {WeakMap<object, MetadataRecord>}
*/
const registry = new WeakMap();
/**
* Meta Repository
*
* @see Repository
*/
class MetaRepository {
/**
* The owner class
*
* @type {object}
*
* @protected
* @readonly
*/
_owner;
/**
* Create a new Meta Repository instance
*
* @param {object} owner
*/
constructor(owner) {
this._owner = owner;
}
/**
* Create a new Meta Repository instance
*
* @param {object} owner
*
* @return {this|Repository}
*/
static make(owner) {
return new this(owner);
}
/**
* The owner class
*
* @type {object}
*/
get owner() {
return this._owner;
}
/**
* Set value for given key
*
* **Caution**: _Method is intended to be invoked inside a decorator!_
*
* @param {object} target Decorator target, e.g. class, field, method...etc
* @param {Context} context
* @param {Key | MetaCallback} key
* @param {any} [value] Value to be stored. Ignored if `key` argument is a callback.
*
* @return {DecoratorResult}
*/
set(target, context, key, value /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
const save = this.save.bind(this);
const resolveTargetContext = this.resolveMetaTargetContext.bind(this);
switch (context.kind) {
// For a class target, the meta can be added directly.
case 'class':
return save(resolveTargetContext(target, target, context), key, value);
// When a field is decorated, we need to rely on the value initialisation to
// obtain correct owner...
case 'field':
return function (initialValue) {
save(
// @ts-expect-error: "this" corresponds to class instance.
resolveTargetContext(target, this, context), key, value);
return initialValue;
};
// For all other kinds of targets, we need to use the initialisation logic
// to obtain the correct owner. This is needed for current implementation
// and until the TC39 proposal is approved and implemented.
// @see https://github.com/tc39/proposal-decorator-metadata
default:
context.addInitializer(function () {
save(
// @ts-expect-error: "this" corresponds to class instance.
resolveTargetContext(target, this, context), key, value);
});
return;
}
}
/**
* Get value for given key
*
* @template T Return value type
* @template D=undefined Type of default value
*
* @param {Key} key
* @param {D} [defaultValue]
*
* @return {T | D}
*/
get(key, defaultValue) {
return objects.get(this.all(), key, defaultValue);
}
/**
* Determine if value exists for key
*
* @param {Key} key
*/
has(key) {
return objects.has(this.all(), key);
}
/**
* Get all metadata
*
* @return {MetadataRecord}
*/
all() {
return this.owner[meta$1.METADATA] || {};
}
/**
* Save metadata
*
* @param {MetaTargetContext} targetContext
* @param {Key | MetaCallback} key
* @param {any} [value]
*
* @return {void}
*
* @protected
*/
save(targetContext, key, value) {
const context = targetContext.context;
const metadata = this.resolveMetadataRecord(targetContext.owner, context);
// Whenever the key is a "meta" callback, for any other kind than a class or a field,
// we overwrite the "context.addInitializer" method, so init callbacks can be invoked
// manually after meta has been defined.
const callbacks = [];
if (typeof key === 'function' && (context.kind !== 'class' && context.kind !== 'field')) {
context.addInitializer = (callback) => {
callbacks.push(callback);
};
}
// Resolve meta entry (key and value). When a "meta callback" is given, it is invoked
// here. Afterward, set the resolved key-value.
const entry = this.resolveEntry(targetContext, key, value);
objects.set(metadata, entry.key, entry.value);
// When the metadata originates from the decorator context, we can stop here.
// Otherwise, we need to save it in the internal registry...
if (this.useMetadataFromContext(context)) {
this.runInitCallbacks(targetContext, callbacks);
return;
}
registry.set(targetContext.owner, metadata);
// Lastly, define the owner[Symbol.metadata] property (only done once for the owner).
// In case that owner is a subclass, then this ensures that it "overwrites" the parent's
// [Symbol.metadata] property and offers its own version thereof.
this.defineMetadataProperty(targetContext.owner);
// Invoke evt. init callbacks...
this.runInitCallbacks(targetContext, callbacks);
}
/**
* Defines the {@link METADATA} property in given owner
*
* @param {object} owner
*
* @return {void}
*
* @protected
*/
defineMetadataProperty(owner) {
Reflect.defineProperty(owner, meta$1.METADATA, {
get: () => {
// To ensure that metadata cannot be changed outside the scope and context of a
// meta decorator, a deep clone of the record is returned here.
return objects.merge()
.using({
arrayMergeOptions: {
transferFunctions: true
}
})
.of(Object.create(null), registry.get(owner) || Object.create(null));
},
// Ensure that the property cannot be deleted
configurable: false
});
}
/**
* Invokes the given initialisation callbacks
*
* @param {MetaTargetContext} targetContext
* @param {InitializerCallback[]} callbacks
*
* @return {void}
*
* @protected
*/
runInitCallbacks(targetContext, callbacks) {
callbacks.forEach((callback) => {
callback.call(targetContext.thisArg);
});
}
/**
* Determine if metadata record can be used from decorator context
*
* @param {Context} context
*
* @return {boolean}
*
* @protected
*/
useMetadataFromContext(context) {
return Reflect.has(context, 'metadata') && typeof context.metadata == 'object';
}
/**
* Resolve the metadata record that must be used when writing new metadata
*
* @param {object} owner
* @param {Context} context
*
* @protected
*/
resolveMetadataRecord(owner, context) {
if (this.useMetadataFromContext(context)) {
return context.metadata;
}
// Obtain record from registry, or create new empty object.
let metadata = registry.get(owner) ?? Object.create(null);
// In case that the owner has Symbol.metadata defined (e.g. from base class),
// then merge it current metadata. This ensures that inheritance works as
// intended, whilst a base class still keeping its original metadata.
if (Reflect.has(owner, meta$1.METADATA)) {
metadata = Object.assign(metadata, owner[meta$1.METADATA]);
}
return metadata;
}
/**
* Resolve the "meta" entry's key and value
*
* @param {MetaTargetContext} targetContext
* @param {Key | MetaCallback} key
* @param {any} [value]
*
* @return {MetaEntry}
*
* @protected
*/
resolveEntry(targetContext, key, value) {
return Entry.resolve(targetContext, key, value);
}
/**
* Resolve the meta target context
*
* **Caution**: _`thisArg` should only be set from an "addInitializer" callback
* function, via decorator context._
*
* @param {object} target Target the is being decorated
* @param {object} thisArg The bound "this" value, from "addInitializer" callback function.
* @param {Context} context
*
* @return {MetaTargetContext}
*
* @protected
*/
resolveMetaTargetContext(target, thisArg, context) {
return TargetContext.resolveOwner(target, thisArg, context);
}
}
/**
* Returns [Meta Repository]{@link Repository} for given owner
*
* @param {object} owner
*
* @return {Repository}
*/
function getMetaRepository(owner) {
return MetaRepository.make(owner);
}
/**
* Determine if owner has metadata for given key
*
* @param {object} owner
* @param {Key} key
*
* @return {boolean}
*/
function hasMeta(owner, key) {
return getMetaRepository(owner).has(key);
}
/**
* Returns all registered metadata for given target, if available
*
* @see getMeta
*
* @param {object} owner Class that owns metadata
*
* @returns {Readonly<MetadataRecord>}
*/
function getAllMeta(owner) {
return getMetaRepository(owner).all();
}
/**
* Return metadata that matches key, for given target
*
* @see getAllMeta
*
* @template T
* @template D=unknown Type of default value
*
* @param {object} owner Class that owns metadata
* @param {Key} key Key or path identifier
* @param {D} [defaultValue=undefined] Default value to return, in case key does not exist
*
* @returns {T | D | undefined}
*/
function getMeta(owner, key, defaultValue) {
return getMetaRepository(owner).get(key, defaultValue);
}
/**
* Store value as metadata, for given key.
*
* **Note**: _Method is intended to be used as a decorator!_
*
* @example
* ```js
* @meta('my-key', 'my-value)
* class A {}
*
* getMeta(A, 'my-key'); // 'my-value'
* ```
*
* @see getMeta
* @see getAllMeta
*
* @param {Key | MetaCallback} key Key or path identifier. If callback is given,
* then its resulting [MetaEntry]{@link import('@aedart/contracts/support/meta').MetaEntry}'s `key`
* and `value` are stored.
* @param {unknown} [value] Value to store. Ignored if `key` argument is a callback.
*
* @returns {Decorator}
*/
function meta(key, value) {
return (target, context) => {
return getMetaRepository({}).set(target, context, key, value);
};
}
/**
* Meta Error
*
* @see MetaException
*/
class MetaError extends Error {
/**
* Create a new Meta Error instance
*
* @param {string} message
* @param {ErrorOptions} [options]
*/
constructor(message, options) {
super(message, options);
exceptions.configureCustomError(this);
}
}
/**
* Element Kind Identifiers
*
* @type {Record<string, symbol>}
*/
const ELEMENT_KIND_IDENTIFIERS = {
[meta$1.Kind.class]: Symbol('class'),
[meta$1.Kind.method]: Symbol('methods'),
[meta$1.Kind.getter]: Symbol('getters'),
[meta$1.Kind.setter]: Symbol('setters'),
[meta$1.Kind.field]: Symbol('fields'),
[meta$1.Kind.accessor]: Symbol('accessors'),
};
/**
* Static element identifier
*
* @type {symbol}
*/
const STATIC_IDENTIFIER = Symbol('static');
/**
* Registry that contains the target object (e.g. a class or a method),
* along with a "meta address" that points to where the actual metadata
* is located.
*
* @see {MetaAddress}
*
* @type {WeakMap<object, MetaAddress>}
*/
const addressRegistry = new WeakMap();
/**
* Target Meta Repository
*
* @see TargetRepository
*/
class TargetMetaRepository {
/**
* Returns a new Target Meta Repository
*
* @return {this|TargetRepository}
*/
static make() {
return new this();
}
/**
* Set value for given key, and associates it directly with the target
*
* **Caution**: _Method is intended to be invoked inside a decorator!_
*
* @param {object} target Class or class method target
* @param {Context} context
* @param {Key | MetaCallback} key
* @param {any} [value] Value to be stored. Ignored if `key` argument is a callback.
*
* @return {ClassDecoratorResult | ClassMethodDecoratorResult}
*
* @throws {MetaError}
*/
set(target, context, key, value /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
return this.makeRepository(target)
.set(target, context, this.makeMetaCallback(key, value));
}
/**
* Get value for given key
*
* @template T Return value type
* @template D=undefined Type of default value
*
* @param {object} target Class or class method target
* @param {Key} key
* @param {D} [defaultValue]
*
* @return {T | D}
*/
get(target, key, defaultValue) {
// Find "target" meta address for given target object
// or return the default value if none is found.
const address = this.find(target);
if (address === undefined) {
return defaultValue;
}
// When an address was found, we must ensure that the meta
// owner class still exists. If not, return default value.
const owner = address[0]?.deref();
if (owner === undefined) {
return defaultValue;
}
// Finally, use getMeta to obtain desired key.
const prefixKey = address[1];
return this.makeRepository(owner).get(misc.mergeKeys(prefixKey, key), defaultValue);
}
/**
* Determine if value exists for key
*
* @param {object} target Class or class method target
* @param {Key} key
*
* @return {boolean}
*/
has(target, key) {
const address = this.find(target);
if (address === undefined) {
return false;
}
const owner = address[0]?.deref();
if (owner === undefined) {
return false;
}
return this.makeRepository(owner).has(misc.mergeKeys(address[1], key));
}
/**
* Determine there is any metadata associated with target
*
* @param {object} target
*
* @return {boolean}
*/
hasAny(target) {
const address = this.find(target);
return address !== undefined && address[0]?.deref() !== undefined;
}
/**
* Inherit "target" meta from a base class.
*
* **Note**: _Method is intended to be used as a decorator for static class methods,
* in situations where you overwrite static methods and wish to inherit
* "target" meta from the parent method._
*
* @param {object} target
* @param {Context} context
*
* @return {ClassMethodDecoratorResult}
*
* @throws {MetaError}
*/
inherit(target, context) {
const makePrefixKey = this.makePrefixKey.bind(this);
const makeRepository = this.makeRepository.bind(this);
return this.set(target, context, (target, context, owner) => {
const name = context.name?.toString() || 'unknown';
// Obtain owner's parent or fail if no parent is available.
if (Reflect.getPrototypeOf(owner) === null) {
throw new MetaError(`Unable to inherit target meta for ${name}: Owner object does not have a parent class.`, { cause: { target: target, context: context } });
}
// Obtain "target" meta from parent, so we can obtain a meta entry and re-set it,
// which will cause the @targetMeta() and @meta() decorators to do the rest.
const parent = Reflect.getPrototypeOf(owner);
const prefixKey = makePrefixKey(context);
const targetMeta = makeRepository(parent)
.get(prefixKey);
// Abort in case that there is nothing to inherit...
if (misc.empty(targetMeta)) {
throw new MetaError(`Unable to inherit target meta for ${name}: parent ${context.kind} does not have target meta.`, { cause: { target: target, context: context } });
}
// Get the first key-value pair (meta entry), from the "target" metadata
const key = Reflect.ownKeys(targetMeta)[0];
const value = targetMeta[key];
// Finally, (re)set the meta-entry. This is needed so that we do not add a "null" entry,
// other kind of useless metadata. All other meta entries are automatically handled by
// the @meta() decorator.
return Entry.make(key, value);
});
}
/**
* Find the address where "target" meta is stored for the given target
*
* @param {object} target
*
* @return {MetaAddress|undefined}
*/
find(target) {
// Return target meta address, if available for target...
let address = addressRegistry.get(target);
if (address !== undefined) {
return address;
}
// When no address is found for the target, and when a class instance is given, the actual
// target must be changed to the constructor
if (typeof target == 'object' && Reflect.has(target, 'constructor')) {
if (addressRegistry.has(target.constructor)) {
return addressRegistry.get(target.constructor);
}
// Otherwise, change the target to the constructor.
target = target.constructor;
}
// When no address is found and the target is a class with metadata,
// then attempt to find address via its parent.
let parent = target;
while (address === undefined && meta$1.METADATA in parent) {
parent = Reflect.getPrototypeOf(parent);
if (parent === null || parent === reflections.FUNCTION_PROTOTYPE) {
break;
}
// Attempt to get meta address from parent.
address = addressRegistry.get(parent);
}
// Recursive version...
// if (address === undefined && METADATA in target) {
// const parent: object | null = Reflect.getPrototypeOf(target);
//
// if (parent !== null && parent !== Reflect.getPrototypeOf(Function)) {
// return this.find(parent);
// }
// }
return address;
}
/**
* Returns a new meta callback for given key-value pair.
*
* **Note**: _Callback is responsible for associating key-value pair with class
* or class method._
*
* @param {Key | MetaCallback} key
* @param {any} [value]
*
* @protected
*/
makeMetaCallback(key, value /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
const makePrefixKey = this.makePrefixKey.bind(this);
const makeMetaTargetContext = this.makeMetaTargetContext.bind(this);
const makeMetaEntry = this.makeMetaEntry.bind(this);
const makeMetaAddress = this.makeMetaAddress.bind(this);
const save = this.save.bind(this);
return (target, context, owner) => {
// Prevent unsupported kinds from being decorated...
if (!['class', 'method'].includes(context.kind)) {
throw new MetaError(` does not support "${context.kind}" (only "class" and "method" are supported)`, { cause: { target: target, context: context } });
}
// Make a "prefix" key, to be used in the final meta entry,
// and a meta address entry.
const prefixKey = makePrefixKey(context);
const address = makeMetaAddress(owner, prefixKey);
// Save the address in the registry...
save(target, address);
// When a method in a base class is decorated, but the method is overwritten in
// a subclass, then we must store another address entry, using the owner's
// method in the registry. This will allow inheriting the meta, but will NOT work
// on static methods.
if (context.kind == 'method' && !context.static && Reflect.has(owner, 'prototype')) {
// @ts-expect-error: TS2339 Owner has a prototype at this point, but Reflect.getPrototypeOf() returns undefined here!
const proto = (owner).prototype;
if (proto !== undefined
&& typeof proto[context.name] == 'function'
&& proto[context.name] !== target) {
save(proto[context.name], address);
}
}
// Finally, return the meta key-value pair that will be stored in the owner's metadata.
return makeMetaEntry(makeMetaTargetContext(owner, null, target, context), prefixKey, key, value);
};
}
/**
* Save metadata address in internal registry, for given target
*
* @param {object} target The target metadata is to be associated with
* @param {MetaAddress} address Location where actual metadata is to be found
*
* @return {void}
*
* @protected
*/
save(target, address) {
addressRegistry.set(target, address);
}
/**
* Returns a "prefix" key (path) where "target" metadata must be stored
*
* @param {Context} context
*
* @return {Key}
*
* @throws {MetaError} If {@link Context.kind} is not supported
*
* @protected
*/
makePrefixKey(context) {
if (!Reflect.has(meta$1.Kind, context.kind)) {
throw new MetaError(`context.kind: "${context.kind}" is unsupported`, { cause: { context: context } });
}
const output = [
meta$1.TARGET_METADATA,
ELEMENT_KIND_IDENTIFIERS[meta$1.Kind[context.kind]]
];
// Ensures that we do not overwrite static / none-static elements with same name!
if (context.kind !== 'class' && context.static) {
output.push(STATIC_IDENTIFIER);
}
// "anonymous" is for anonymous classes (they do not have a name)
const name = context.name ?? 'anonymous';
output.push(name);
return output;
}
/**
* Returns a new Meta Target Context
*
* @param {object} owner
* @param {any} thisArg
* @param {object} target
* @param {Context} context
*
* @return {MetaTargetContext}
*
* @protected
*/
makeMetaTargetContext(owner, thisArg, /* eslint-disable-line @typescript-eslint/no-explicit-any */ target, context) {
return TargetContext.make(owner, thisArg, target, context);
}
/***
* Returns a new metadata entry, with prefixed key
*
* @param {MetaTargetContext} targetContext
* @param {Key} prefixKey
* @param {Key|MetaCallback} key User provided key or callback
* @param {unknown} [value] Value to store. Ignored if `key` argument is
* a callback.
*
* @return {MetaEntry}
*
* @protected
*/
makeMetaEntry(targetContext, prefixKey, key, value) {
return Entry.resolveWithPrefix(targetContext, prefixKey, key, value);
}
/**
* Returns a new meta address
*
* @param {object|MetaOwnerReference} owner
* @param {Key} key
*
* @return {MetaAddress}
*
* @protected
*/
makeMetaAddress(owner, key) {
return [
misc.toWeakRef(owner),
key
];
}
/**
* Returns a new Repository instance for given owner
*
* @param {object} owner
*
* @return {Repository}
*
* @protected
*/
makeRepository(owner) {
return getMetaRepository(owner);
}
}
/**
* Returns a new Target Meta Repository
*
* @return {TargetRepository}
*/
function getTargetMetaRepository() {
return TargetMetaRepository.make();
}
/**
* Determine there is any metadata associated with target
*
* @param {object} target
*
* @return {boolean}
*/
function hasAnyTargetMeta(target) {
return getTargetMetaRepository().hasAny(target);
}
/**
* Return metadata that matches key, that belongs to the given target
*
* **Note**: _Unlike the {@link getMeta} method, this method does not require you
* to know the owner object (e.g. the class) that holds metadata, provided
* that metadata has been associated with given target, via {@link targetMeta}._
*
* @see targetMeta
* @see getMeta
*
* @template T
* @template D=unknown Type of default value
*
* @param {object} target Class or method that owns metadata
* @param {Key} key Key or path identifier
* @param {D} [defaultValue=undefined] Default value to return, in case key does not exist
*
* @returns {T | D | undefined}
*/
function getTargetMeta(target, key, defaultValue) {
return getTargetMetaRepository().get(target, key, defaultValue);
}
/**
* Determine if value exists for key, in given target
*
* @param {object} target
* @param {Key} key
*
* @return {boolean}
*/
function hasTargetMeta(target, key) {
return getTargetMetaRepository().has(target, key);
}
/**
* Inherit "target" meta from a base class.
*
* **Note**: _Method is intended to be used as a static method decorator!_
*
* **Note**: _To be used in situations where you overwrite static methods and wish to inherit
* "target" meta from the parent method._
*
* @see targetMeta
*
* @example
* ```ts
* class A {
* @targetMeta('bar', 'zaz')
* static foo() {}
* }
*
* class B extends A {
*
* @inheritTargetMeta()
* static foo() {
* // ...overwritten static method...//
* }
* }
*
* getTargetMeta(B.foo, 'bar'); // 'zaz'
* ```
*
* @returns {ClassMethodDecorator}
*
* @throws {MetaError} When decorated element's owner class has no parent, or when no "target" metadata available
* on parent element.
*/
function inheritTargetMeta() {
return (target, context) => {
return getTargetMetaRepository().inherit(target, context);
};
}
/**
* Stores value for given key, and associates it directly with the target
*
* **Note**: _Method is intended to be used as a class or method decorator!_
*
* @example
* ```js
* class A {
* @targetMeta('my-key', 'my-value')
* foo() {}
* }
*
* const a: A = new A();
* getTargetMeta(a.foo, 'my-key'); // 'my-value'
* ```
*
* @see getTargetMeta
*
* @param {Key | MetaCallback} key Key or path identifier. If callback is given,
* then its resulting [MetaEntry]{@link import('@aedart/contracts/support/meta').MetaEntry}'s `key`
* and `value` are stored.
* @param {unknown} [value] Value to store. Ignored if `key` argument is
* a callback.
* @returns {ClassDecorator | ClassMethodDecorator}
*
* @throws {MetaError} When decorated element is not supported
*/
function targetMeta(key, value) {
return (target, context) => {
return getTargetMetaRepository().set(target, context, key, value);
};
}
exports.ELEMENT_KIND_IDENTIFIERS = ELEMENT_KIND_IDENTIFIERS;
exports.Entry = Entry;
exports.MetaError = MetaError;
exports.MetaRepository = MetaRepository;
exports.STATIC_IDENTIFIER = STATIC_IDENTIFIER;
exports.TargetContext = TargetContext;
exports.TargetMetaRepository = TargetMetaRepository;
exports.getAllMeta = getAllMeta;
exports.getMeta = getMeta;
exports.getMetaRepository = getMetaRepository;
exports.getTargetMeta = getTargetMeta;
exports.getTargetMetaRepository = getTargetMetaRepository;
exports.hasAnyTargetMeta = hasAnyTargetMeta;
exports.hasMeta = hasMeta;
exports.hasTargetMeta = hasTargetMeta;
exports.inheritTargetMeta = inheritTargetMeta;
exports.meta = meta;
exports.targetMeta = targetMeta;
module.exports = Object.assign(exports.default, exports);
//# sourceMappingURL=meta.cjs.map