UNPKG

@prostojs/mate

Version:

MATE is TS Metadata Organizer

258 lines (254 loc) 10.3 kB
function getConstructor(instance) { return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor; } function isConstructor(v) { return typeof v === 'function' && Object.getOwnPropertyNames(v).includes('prototype') && !Object.getOwnPropertyNames(v).includes('caller') && !!v.name; } let classMetadata = new WeakMap(); let paramMetadata = 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 = new WeakMap(); paramMetadata = 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; const Reflect = ((global === null || global === void 0 ? void 0 : global.Reflect) || (self === null || self === void 0 ? void 0 : self.Reflect) || Reflect$1); class Mate { constructor(workspace, options = {}) { this.workspace = workspace; this.options = options; this.logger = options.logger || console; } _cleanup() { var _a; (_a = Reflect._cleanup) === null || _a === void 0 ? void 0 : _a.call(Reflect); } set(args, key, value, isArray) { var _a; let level = 'CLASS'; const newArgs = args.level === 'CLASS' ? { target: 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 : undefined; let data = meta; if (!data.params) { data.params = (_a = Reflect.getOwnMetadata('design:paramtypes', newArgs.target, newArgs.propKey)) === null || _a === void 0 ? void 0 : _a.map((f) => ({ type: f })); } if (typeof index === 'number') { level = 'PARAM'; data.params = data.params || []; data.params[index] = data.params[index] || { type: undefined, }; if (cb) { data.params[index] = cb(data.params[index], level, args.propKey, typeof args.index === 'number' ? args.index : undefined); } 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)) { 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 : undefined); } Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey); } read(target, propKey) { var _a; const isConstr = isConstructor(target); const constructor = isConstr ? target : getConstructor(target); const proto = constructor.prototype; let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === 'string' ? proto : constructor, propKey); if (ownMeta && propKey === undefined && ownMeta.params === undefined) { const parent = Object.getPrototypeOf(constructor); if (typeof parent === 'function' && parent !== fnProto && parent !== constructor) { ownMeta.params = (_a = this.read(parent)) === null || _a === void 0 ? void 0 : _a.params; } } if (this.options.inherit) { const inheritFn = typeof this.options.inherit === 'function' ? this.options.inherit : undefined; let shouldInherit = this.options.inherit; if (inheritFn) { if (typeof propKey === 'string') { const classMeta = Reflect.getOwnMetadata(this.workspace, constructor); shouldInherit = inheritFn(classMeta, 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 === null || ownMeta === void 0 ? void 0 : ownMeta.params; ownMeta = { ...inheritedMeta, ...ownMeta }; if (typeof propKey === 'string' && ownParams && (inheritedMeta === null || inheritedMeta === void 0 ? void 0 : inheritedMeta.params)) { for (let i = 0; i < ownParams.length; i++) { if (typeof (inheritedMeta === null || inheritedMeta === void 0 ? void 0 : inheritedMeta.params[i]) !== 'undefined') { const ownParam = ownParams[i]; if (ownMeta.params && inheritFn && inheritFn(ownMeta, ownParam, 'PARAM', typeof propKey === 'string' ? propKey : undefined)) { ownMeta.params[i] = { ...inheritedMeta === null || inheritedMeta === void 0 ? void 0 : inheritedMeta.params[i], ...ownParams[i], }; } } } } } } } 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' ? undefined : descriptor, index: typeof descriptor === 'number' ? descriptor : undefined, level, }; this.set(args, key, value, isArray); }); } decorateConditional(ccb) { return ((target, propKey, descriptor) => { const hasIndex = typeof descriptor === 'number'; const decoratorLevel = hasIndex ? 'PARAM' : propKey && descriptor ? 'METHOD' : propKey ? 'PROP' : 'CLASS'; const d = ccb(decoratorLevel); if (d) { d(target, propKey, descriptor); } }); } decorateClass(key, value, isArray) { return this.decorate(key, value, isArray, 'CLASS'); } } const fnProto = Object.getPrototypeOf(Function); export { Mate, getConstructor, isConstructor };