import * as ObjectUtil from '../util/ObjectUtil.js'; import type { Schema } from '../schema/Schema.js'; import type { Resource } from './Resource.js'; import { resourceDef, ResourceDefinition } from './Resource.js'; import type { StorableSpec } from './StorablePromise.js'; import { isStorable, makeStorable } from './StorablePromise.js'; // Resource method utilities type ResourceMethodOptions = { storable ?: boolean | Partial>, }; type ResourceMethod, R> = ( this : Resource, resourceDef: ResourceDefinition, ...args : A ) => R; export const decorateMethod = , R>( method: ResourceMethod, { storable = true }: Partial> = {}, ) => function(this : Resource, ...args : A): R { const resourceDefinition = this[resourceDef]; let result = Function.prototype.apply.call(method, this, [resourceDefinition, ...args]); if (storable && result instanceof Promise && !isStorable(result)) { const storableSpecDefaults : Partial> = { accessor: (result : R) : R => result, location: resourceDefinition.store, operation: 'put', }; const storableSpec : Partial> = typeof storable === 'object' && storable !== null ? { ...storableSpecDefaults, ...storable } : storableSpecDefaults; result = makeStorable(result, storableSpec); } return result; }; // Decorator, for (legacy-style) `@decorator` syntax on object literal methods export const decorator = (options : ResourceMethodOptions = {}) => >( _target : unknown, _key : PropertyKey, descriptor : TypedPropertyDescriptor>, ) : TypedPropertyDescriptor<(this : Resource, ...args : A) => R> => { // A valid descriptor must have *either* `value` *or* `get` + `set`, currently we only support `value`. The // properties `get`/`set` must be completely absent (not just `undefined`), otherwise we get a runtime error. if (ObjectUtil.hasProp(descriptor, 'get') || ObjectUtil.hasProp(descriptor, 'set')) { throw new TypeError(`Given descriptor with getter/setter, expected value-based descriptor`); } let descriptorWithValue : Omit>, 'get' | 'set'> = descriptor; if (typeof descriptorWithValue.value !== 'function') { throw new TypeError(`Invalid value for @RestApi.method decorator, expected a function`); } const method = descriptorWithValue.value; return { ...descriptorWithValue, value: decorateMethod(method, options), }; };