UNPKG

@prostojs/mate

Version:

MATE is TS Metadata Organizer

204 lines (200 loc) 7.81 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); //#region src/utils/helpers.ts function getConstructor(instance) { return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor; } function isConstructor(v) { return typeof v === "function" && Object.getOwnPropertyDescriptor(v, "prototype") !== void 0 && Object.getOwnPropertyDescriptor(v, "caller") === void 0 && !!v.name; } //#endregion //#region src/reflect.ts let classMetadata = /* @__PURE__ */ new WeakMap(); let paramMetadata = /* @__PURE__ */ new WeakMap(); const root = typeof global === "object" ? global : typeof self === "object" ? self : {}; function getMetaObject(target, prop) { const isParam = typeof prop !== "undefined"; const metadata = isParam ? paramMetadata : classMetadata; const targetKey = getConstructor(target); let meta = metadata.get(targetKey); if (!meta) { meta = {}; metadata.set(targetKey, meta); } if (isParam) meta = meta[prop] = meta[prop] || {}; return meta; } const _reflect = { getOwnMetadata(key, target, prop) { return getMetaObject(target, prop)[key]; }, defineMetadata(key, data, target, prop) { const meta = getMetaObject(target, prop); meta[key] = data; }, metadata(key, data) { return ((target, propKey) => { Reflect$1.defineMetadata(key, data, target, propKey); }); }, _cleanup: (() => { classMetadata = /* @__PURE__ */ new WeakMap(); paramMetadata = /* @__PURE__ */ new WeakMap(); }) }; if (!root.Reflect) root.Reflect = _reflect; else { const funcs = [ "getOwnMetadata", "defineMetadata", "metadata" ]; const target = root.Reflect; for (const func of funcs) if (typeof target[func] !== "function") Object.defineProperty(target, func, { configurable: true, writable: true, value: _reflect[func] }); } const Reflect$1 = _reflect; //#endregion //#region src/mate.ts const Reflect = global?.Reflect || self?.Reflect || Reflect$1; var Mate = class { constructor(workspace, options = {}) { this.workspace = workspace; this.options = options; this.logger = options.logger || console; } /** * Cleanup function to reset metadata * * It is usefull in dev mode when server restarts */ _cleanup() { Reflect._cleanup?.call(Reflect); this._readCache = void 0; } set(args, key, value, isArray) { this._readCache = void 0; let level = "CLASS"; const newArgs = args.level === "CLASS" ? { target: getConstructor(args.target) } : args.level === "PROP" ? { target: args.target, propKey: args.propKey } : args; let meta = Reflect.getOwnMetadata(this.workspace, newArgs.target, newArgs.propKey) || {}; if (newArgs.propKey && this.options.readReturnType && !meta.returnType && args.descriptor) meta.returnType = Reflect.getOwnMetadata("design:returntype", newArgs.target, newArgs.propKey); if (newArgs.propKey && this.options.readType && !meta.type) meta.type = Reflect.getOwnMetadata("design:type", newArgs.target, newArgs.propKey); const { index } = newArgs; const cb = typeof key === "function" ? key : void 0; let data = meta; if (!data.params) { const paramTypes = Reflect.getOwnMetadata("design:paramtypes", newArgs.target, newArgs.propKey); if (paramTypes) { data.params = new Array(paramTypes.length); for (let i = 0; i < paramTypes.length; i++) data.params[i] = { type: paramTypes[i] }; } } if (typeof index === "number") { level = "PARAM"; data.params = data.params || []; data.params[index] = data.params[index] || { type: void 0 }; if (cb) data.params[index] = cb(data.params[index], level, args.propKey, typeof args.index === "number" ? args.index : void 0); else data = data.params[index]; } else if (!index && !args.descriptor && args.propKey && this.options.collectPropKeys && args.level !== "CLASS") this.set({ ...args, level: "CLASS" }, (meta) => { if (!meta.properties) meta.properties = [args.propKey]; else if (!meta.properties.includes(args.propKey)) meta.properties.push(args.propKey); return meta; }); level = typeof index === "number" ? "PARAM" : newArgs.propKey && newArgs.descriptor ? "METHOD" : newArgs.propKey ? "PROP" : "CLASS"; if (typeof key !== "function") if (isArray) { const newArray = data[key] || []; if (!Array.isArray(newArray)) /* istanbul ignore next line */ this.logger.error("Mate.add (isArray=true) called for non-array metadata"); newArray.unshift(value); data[key] = newArray; } else data[key] = value; else if (cb && typeof index !== "number") meta = cb(data, level, args.propKey, typeof args.index === "number" ? args.index : void 0); Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey); } read(target, propKey) { const constructor = isConstructor(target) ? target : getConstructor(target); const proto = constructor.prototype; const propKeyStr = propKey; const ctorCache = this._readCache?.get(constructor); if (ctorCache?.has(propKeyStr)) return ctorCache.get(propKeyStr); let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === "string" ? proto : constructor, propKey); if (ownMeta && propKey === void 0 && ownMeta.params === void 0) { const parent = Object.getPrototypeOf(constructor); if (typeof parent === "function" && parent !== fnProto && parent !== constructor) ownMeta.params = this.read(parent)?.params; } if (this.options.inherit) { const inheritFn = typeof this.options.inherit === "function" ? this.options.inherit : void 0; let shouldInherit = this.options.inherit; if (inheritFn) if (typeof propKey === "string") shouldInherit = inheritFn(Reflect.getOwnMetadata(this.workspace, constructor), ownMeta, "PROP", propKey); else shouldInherit = inheritFn(ownMeta, ownMeta, "CLASS"); if (shouldInherit) { const parent = Object.getPrototypeOf(constructor); if (typeof parent === "function" && parent !== fnProto && parent !== constructor) { const inheritedMeta = this.read(parent, propKey) || {}; const ownParams = ownMeta?.params; ownMeta = { ...inheritedMeta, ...ownMeta }; if (typeof propKey === "string" && ownParams && inheritedMeta?.params) { for (let i = 0; i < ownParams.length; i++) if (typeof inheritedMeta?.params[i] !== "undefined") { const ownParam = ownParams[i]; if (ownMeta.params && inheritFn && inheritFn(ownMeta, ownParam, "PARAM", typeof propKey === "string" ? propKey : void 0)) ownMeta.params[i] = { ...inheritedMeta?.params[i], ...ownParams[i] }; } } } } } const cache = this._readCache ??= /* @__PURE__ */ new WeakMap(); let tc = cache.get(constructor); if (!tc) { tc = /* @__PURE__ */ new Map(); cache.set(constructor, tc); } tc.set(propKeyStr, ownMeta); return ownMeta; } apply(...decorators) { return ((target, propKey, descriptor) => { for (const d of decorators) d(target, propKey, descriptor); }); } decorate(key, value, isArray, level) { return ((target, propKey, descriptor) => { const args = { target, propKey, descriptor: typeof descriptor === "number" ? void 0 : descriptor, index: typeof descriptor === "number" ? descriptor : void 0, level }; this.set(args, key, value, isArray); }); } decorateConditional(ccb) { return ((target, propKey, descriptor) => { const d = ccb(typeof descriptor === "number" ? "PARAM" : propKey && descriptor ? "METHOD" : propKey ? "PROP" : "CLASS"); if (d) d(target, propKey, descriptor); }); } decorateClass(key, value, isArray) { return this.decorate(key, value, isArray, "CLASS"); } }; const fnProto = Object.getPrototypeOf(Function); //#endregion exports.Mate = Mate; exports.getConstructor = getConstructor; exports.isConstructor = isConstructor;