UNPKG

t7m

Version:

Transformer for Elysia and Hono

163 lines (162 loc) 5.93 kB
// src/abstractTransformer.ts class AbstractTransformer { clearCacheOnTransform; constructor(params) { this.clearCacheOnTransform = params?.clearCacheOnTransform ?? true; } includesMap = {}; cache = {}; clearCache = () => this._clearCache(); _clearCache = (clearedFor = new Set) => { if (clearedFor.has(this)) return; Object.keys(this.cache).forEach((key) => this.cache[key]?.clear()); clearedFor.add(this); Object.keys(this.transformers).forEach((key) => { const transformer = this.transformers[key]; if ("call" in transformer) return transformer.call()._clearCache(clearedFor); transformer._clearCache(clearedFor); }); }; originalClearCacheOnTransform = null; disableClearCacheForTransformers = (visited) => { if (visited.has(this)) return; visited.add(this); if (this.originalClearCacheOnTransform === null) this.originalClearCacheOnTransform = this.clearCacheOnTransform; this.clearCacheOnTransform = false; Object.keys(this.transformers).forEach((key) => { const transformer = this.transformers[key]; if ("call" in transformer) { transformer.call().disableClearCacheForTransformers(visited); } else transformer.disableClearCacheForTransformers(visited); }); }; restoreClearCacheForTransformers = (visited) => { if (visited.has(this)) return; visited.add(this); if (this.originalClearCacheOnTransform !== null) { this.clearCacheOnTransform = this.originalClearCacheOnTransform; this.originalClearCacheOnTransform = null; } Object.keys(this.transformers).forEach((key) => { const transformer = this.transformers[key]; if ("call" in transformer) { transformer.call().restoreClearCacheForTransformers(visited); } else transformer.restoreClearCacheForTransformers(visited); }); }; transformers = {}; onBeforeTransform = () => { if (this.originalClearCacheOnTransform !== null) return; const visited = new Set([this]); Object.keys(this.transformers).forEach((key) => { const transformer = this.transformers[key]; if ("call" in transformer) { transformer.call().disableClearCacheForTransformers(visited); } else transformer.disableClearCacheForTransformers(visited); }); }; onAfterTransform = () => { if (this.originalClearCacheOnTransform !== null) return; const visited = new Set([this]); Object.keys(this.transformers).forEach((key) => { const transformer = this.transformers[key]; if ("call" in transformer) { transformer.call().restoreClearCacheForTransformers(visited); } else transformer.restoreClearCacheForTransformers(visited); }); }; async transform(params) { const { input, props, includes, unsafeIncludes } = params; const combinedIncludes = [...includes || [], ...unsafeIncludes || []]; return this.__transform(input, props, combinedIncludes); } async transformMany(params) { const { inputs, props, includes, unsafeIncludes } = params; const combinedIncludes = [...includes || [], ...unsafeIncludes || []]; return Promise.all(inputs.map((input) => this.__transform(input, props, combinedIncludes))); } async _transform(params) { const { input, props, includes, unsafeIncludes } = params; const combinedIncludes = [...includes || [], ...unsafeIncludes || []]; this.onBeforeTransform(); const output = await this.__transform(input, props, combinedIncludes); if (this.clearCacheOnTransform) this.clearCache(); this.onAfterTransform(); return output; } async _transformMany(params) { const { inputs, props, includes, unsafeIncludes } = params; const combinedIncludes = [...includes || [], ...unsafeIncludes || []]; this.onBeforeTransform(); const outputArray = await Promise.all(inputs.map((input) => this.__transform(input, props, combinedIncludes))); if (this.clearCacheOnTransform) this.clearCache(); this.onAfterTransform(); return outputArray; } async __transform(input, props, includes = []) { const data = await this.data(input, props); includes = Array.from(new Set(includes)); if (includes.length > 0 && typeof data === "object" && data !== null) { const otherIncludes = includes.filter((include) => !(include in this.includesMap)); const validIncludes = includes.filter((include) => (include in this.includesMap)).map((include) => include); await Promise.all(validIncludes.map(async (include) => { if (!this.includesMap[include]) throw new Error(`Include function not found in includesMap`); try { data[include] = await this.includesMap[include](input, props, otherIncludes); } catch (error) { throw new Error(`[T7M] Error in include function '${String(include)}': ${error instanceof Error ? error.message : String(error)}`); } })); } return data; } } // src/cache.ts class Cache { fn; cacheOnObjectParams; constructor(fn, ...on) { this.fn = fn; this.cacheOnObjectParams = on.length > 0 ? on : undefined; } cache = new Map; objectCacheKey(keys, arg) { return keys.slice().sort().map((key) => `${key.toString()}:${arg[key]}`).join("-"); } call(...args) { const arg = args[0] ?? "default-key"; let cacheKey; if (typeof arg !== "object") { cacheKey = arg.toString(); } else if (this.cacheOnObjectParams) { cacheKey = this.objectCacheKey(this.cacheOnObjectParams, arg); } else { cacheKey = this.objectCacheKey(Object.keys(arg), arg); } let result = this.cache.get(cacheKey); if (!result) { result = this.fn(...args); this.cache.set(cacheKey, result); } return result; } clear = () => this.cache.clear(); } export { Cache, AbstractTransformer };