@prostojs/mate
Version:
MATE is TS Metadata Organizer
204 lines (200 loc) • 7.81 kB
JavaScript
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;