@prostojs/mate 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -30
- package/dist/index.cjs +204 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.mjs +200 -0
- package/package.json +68 -79
- package/dist/mate.cjs.prod.js +0 -232
- package/dist/mate.d.ts +0 -83
- package/dist/mate.esm-bundler.js +0 -226
- package/dist/src/index.d.ts +0 -3
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/mate.d.ts +0 -61
- package/dist/src/mate.d.ts.map +0 -1
- package/dist/src/reflect.d.ts +0 -7
- package/dist/src/reflect.d.ts.map +0 -1
- package/dist/src/tests/mate.artifacts.d.ts +0 -70
- package/dist/src/tests/mate.artifacts.d.ts.map +0 -1
- package/dist/src/tests/mate.spec.d.ts +0 -2
- package/dist/src/tests/mate.spec.d.ts.map +0 -1
- package/dist/src/tests/reflect.artifacts.d.ts +0 -5
- package/dist/src/tests/reflect.artifacts.d.ts.map +0 -1
- package/dist/src/tests/reflect.spec.d.ts +0 -2
- package/dist/src/tests/reflect.spec.d.ts.map +0 -1
- package/dist/src/types.d.ts +0 -5
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils/helpers.d.ts +0 -4
- package/dist/src/utils/helpers.d.ts.map +0 -1
- package/index.js +0 -2
package/README.md
CHANGED
|
@@ -19,27 +19,27 @@ npm install @prostojs/mate
|
|
|
19
19
|
After installation, you can start using Mate to define and handle metadata in your TypeScript project. Below is an example that showcases different levels of metadata usage.
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import { TMateParamMeta } from '@prostojs/mate'
|
|
23
|
-
import { Mate } from '@prostojs/mate'
|
|
22
|
+
import { TMateParamMeta } from '@prostojs/mate'
|
|
23
|
+
import { Mate } from '@prostojs/mate'
|
|
24
24
|
|
|
25
25
|
// Define your metadata interfaces
|
|
26
26
|
interface TClassMeta {
|
|
27
|
-
name: string
|
|
28
|
-
model: string
|
|
29
|
-
fromParam: string
|
|
30
|
-
manufacturer: string
|
|
31
|
-
data: string[]
|
|
32
|
-
inherit?: bolean
|
|
27
|
+
name: string
|
|
28
|
+
model: string
|
|
29
|
+
fromParam: string
|
|
30
|
+
manufacturer: string
|
|
31
|
+
data: string[]
|
|
32
|
+
inherit?: bolean
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
interface TPropMeta<TParamMeta> {
|
|
36
|
-
description: string
|
|
37
|
-
params: (TMateParamMeta & TParamMeta)[]
|
|
36
|
+
description: string
|
|
37
|
+
params: (TMateParamMeta & TParamMeta)[]
|
|
38
38
|
inherit?: bolean
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
interface TParamMeta {
|
|
42
|
-
required: boolean
|
|
42
|
+
required: boolean
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
const mate = new Mate<TClassMeta, TPropMeta<TParamMeta>>('robot-meta', {
|
|
@@ -47,32 +47,32 @@ const mate = new Mate<TClassMeta, TPropMeta<TParamMeta>>('robot-meta', {
|
|
|
47
47
|
readType: true,
|
|
48
48
|
collectPropKeys: true,
|
|
49
49
|
inherit(classMeta, targetMeta, level, prop) {
|
|
50
|
-
return !!targetMeta?.inherit || !!classMeta?.inherit
|
|
50
|
+
return !!targetMeta?.inherit || !!classMeta?.inherit
|
|
51
51
|
},
|
|
52
|
-
})
|
|
52
|
+
})
|
|
53
53
|
|
|
54
54
|
// Annotate your class
|
|
55
|
-
@mate.decorate('name', 'NXT')
|
|
56
|
-
@mate.decorate('model', 'EV3')
|
|
55
|
+
@mate.decorate('name', 'NXT')
|
|
56
|
+
@mate.decorate('model', 'EV3')
|
|
57
57
|
@mate.decorate('manufacturer', 'LEGO')
|
|
58
|
-
@mate.decorate('data', 'NXT-0001', true)
|
|
58
|
+
@mate.decorate('data', 'NXT-0001', true)
|
|
59
59
|
class Robot {
|
|
60
60
|
@mate.decorate('description', 'Robotic arm for grabbing objects')
|
|
61
|
-
arm: string
|
|
61
|
+
arm: string
|
|
62
62
|
|
|
63
|
-
@mate.decorate('description', 'Sensors to detect objects')
|
|
63
|
+
@mate.decorate('description', 'Sensors to detect objects')
|
|
64
64
|
sensors(
|
|
65
|
-
@mate.decorateClass('fromParam', 'hoised value')
|
|
66
|
-
@mate.decorate('required', true)
|
|
67
|
-
input: string
|
|
65
|
+
@mate.decorateClass('fromParam', 'hoised value')
|
|
66
|
+
@mate.decorate('required', true)
|
|
67
|
+
input: string,
|
|
68
68
|
): string {
|
|
69
|
-
return 'Activated sensors with input: ' + input
|
|
69
|
+
return 'Activated sensors with input: ' + input
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Read the metadata
|
|
74
|
-
let classMeta = mate.read(Robot)
|
|
75
|
-
console.log(classMeta)
|
|
74
|
+
let classMeta = mate.read(Robot)
|
|
75
|
+
console.log(classMeta)
|
|
76
76
|
// Expected Output:
|
|
77
77
|
// {
|
|
78
78
|
// name: 'NXT',
|
|
@@ -86,8 +86,8 @@ console.log(classMeta);
|
|
|
86
86
|
// }
|
|
87
87
|
|
|
88
88
|
// read the property metadata
|
|
89
|
-
let armMeta = mate.read(Robot, 'arm')
|
|
90
|
-
console.log(armMeta)
|
|
89
|
+
let armMeta = mate.read(Robot, 'arm')
|
|
90
|
+
console.log(armMeta)
|
|
91
91
|
// Expected Output:
|
|
92
92
|
// {
|
|
93
93
|
// description: 'Robotic arm for grabbing objects',
|
|
@@ -97,8 +97,8 @@ console.log(armMeta);
|
|
|
97
97
|
// }
|
|
98
98
|
|
|
99
99
|
// read the method metadata
|
|
100
|
-
let sensorsMeta = mate.read(Robot, 'sensors')
|
|
101
|
-
console.log(sensorsMeta)
|
|
100
|
+
let sensorsMeta = mate.read(Robot, 'sensors')
|
|
101
|
+
console.log(sensorsMeta)
|
|
102
102
|
// Expected Output:
|
|
103
103
|
// {
|
|
104
104
|
// description: 'Sensors to detect objects',
|
|
@@ -132,12 +132,14 @@ const mate = new Mate<MyMeta>('my-metadata-key', {
|
|
|
132
132
|
if (prop) {
|
|
133
133
|
// if it is a method metadata
|
|
134
134
|
// we require a key `inherit` to be true for inheritance
|
|
135
|
-
return
|
|
135
|
+
return (
|
|
136
|
+
!!methodMeta?.inherit || !!(classMeta?.inherit && !methodMeta)
|
|
137
|
+
)
|
|
136
138
|
}
|
|
137
139
|
// otherwise (in case of class metadata) we require a key `inherit`
|
|
138
140
|
// to be true for inheritance on class metadata
|
|
139
141
|
return !!classMeta?.inherit
|
|
140
|
-
}
|
|
142
|
+
},
|
|
141
143
|
})
|
|
142
144
|
```
|
|
143
145
|
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region src/utils/helpers.ts
|
|
4
|
+
function getConstructor(instance) {
|
|
5
|
+
return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor;
|
|
6
|
+
}
|
|
7
|
+
function isConstructor(v) {
|
|
8
|
+
return typeof v === "function" && Object.getOwnPropertyDescriptor(v, "prototype") !== void 0 && Object.getOwnPropertyDescriptor(v, "caller") === void 0 && !!v.name;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/reflect.ts
|
|
13
|
+
let classMetadata = /* @__PURE__ */ new WeakMap();
|
|
14
|
+
let paramMetadata = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
const root = typeof global === "object" ? global : typeof self === "object" ? self : {};
|
|
16
|
+
function getMetaObject(target, prop) {
|
|
17
|
+
const isParam = typeof prop !== "undefined";
|
|
18
|
+
const metadata = isParam ? paramMetadata : classMetadata;
|
|
19
|
+
const targetKey = getConstructor(target);
|
|
20
|
+
let meta = metadata.get(targetKey);
|
|
21
|
+
if (!meta) {
|
|
22
|
+
meta = {};
|
|
23
|
+
metadata.set(targetKey, meta);
|
|
24
|
+
}
|
|
25
|
+
if (isParam) meta = meta[prop] = meta[prop] || {};
|
|
26
|
+
return meta;
|
|
27
|
+
}
|
|
28
|
+
const _reflect = {
|
|
29
|
+
getOwnMetadata(key, target, prop) {
|
|
30
|
+
return getMetaObject(target, prop)[key];
|
|
31
|
+
},
|
|
32
|
+
defineMetadata(key, data, target, prop) {
|
|
33
|
+
const meta = getMetaObject(target, prop);
|
|
34
|
+
meta[key] = data;
|
|
35
|
+
},
|
|
36
|
+
metadata(key, data) {
|
|
37
|
+
return ((target, propKey) => {
|
|
38
|
+
Reflect$1.defineMetadata(key, data, target, propKey);
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
_cleanup: (() => {
|
|
42
|
+
classMetadata = /* @__PURE__ */ new WeakMap();
|
|
43
|
+
paramMetadata = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
if (!root.Reflect) root.Reflect = _reflect;
|
|
47
|
+
else {
|
|
48
|
+
const funcs = [
|
|
49
|
+
"getOwnMetadata",
|
|
50
|
+
"defineMetadata",
|
|
51
|
+
"metadata"
|
|
52
|
+
];
|
|
53
|
+
const target = root.Reflect;
|
|
54
|
+
for (const func of funcs) if (typeof target[func] !== "function") Object.defineProperty(target, func, {
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true,
|
|
57
|
+
value: _reflect[func]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const Reflect$1 = _reflect;
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/mate.ts
|
|
64
|
+
const Reflect = global?.Reflect || self?.Reflect || Reflect$1;
|
|
65
|
+
var Mate = class {
|
|
66
|
+
constructor(workspace, options = {}) {
|
|
67
|
+
this.workspace = workspace;
|
|
68
|
+
this.options = options;
|
|
69
|
+
this.logger = options.logger || console;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Cleanup function to reset metadata
|
|
73
|
+
*
|
|
74
|
+
* It is usefull in dev mode when server restarts
|
|
75
|
+
*/
|
|
76
|
+
_cleanup() {
|
|
77
|
+
Reflect._cleanup?.call(Reflect);
|
|
78
|
+
this._readCache = void 0;
|
|
79
|
+
}
|
|
80
|
+
set(args, key, value, isArray) {
|
|
81
|
+
this._readCache = void 0;
|
|
82
|
+
let level = "CLASS";
|
|
83
|
+
const newArgs = args.level === "CLASS" ? { target: getConstructor(args.target) } : args.level === "PROP" ? {
|
|
84
|
+
target: args.target,
|
|
85
|
+
propKey: args.propKey
|
|
86
|
+
} : args;
|
|
87
|
+
let meta = Reflect.getOwnMetadata(this.workspace, newArgs.target, newArgs.propKey) || {};
|
|
88
|
+
if (newArgs.propKey && this.options.readReturnType && !meta.returnType && args.descriptor) meta.returnType = Reflect.getOwnMetadata("design:returntype", newArgs.target, newArgs.propKey);
|
|
89
|
+
if (newArgs.propKey && this.options.readType && !meta.type) meta.type = Reflect.getOwnMetadata("design:type", newArgs.target, newArgs.propKey);
|
|
90
|
+
const { index } = newArgs;
|
|
91
|
+
const cb = typeof key === "function" ? key : void 0;
|
|
92
|
+
let data = meta;
|
|
93
|
+
if (!data.params) {
|
|
94
|
+
const paramTypes = Reflect.getOwnMetadata("design:paramtypes", newArgs.target, newArgs.propKey);
|
|
95
|
+
if (paramTypes) {
|
|
96
|
+
data.params = new Array(paramTypes.length);
|
|
97
|
+
for (let i = 0; i < paramTypes.length; i++) data.params[i] = { type: paramTypes[i] };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (typeof index === "number") {
|
|
101
|
+
level = "PARAM";
|
|
102
|
+
data.params = data.params || [];
|
|
103
|
+
data.params[index] = data.params[index] || { type: void 0 };
|
|
104
|
+
if (cb) data.params[index] = cb(data.params[index], level, args.propKey, typeof args.index === "number" ? args.index : void 0);
|
|
105
|
+
else data = data.params[index];
|
|
106
|
+
} else if (!index && !args.descriptor && args.propKey && this.options.collectPropKeys && args.level !== "CLASS") this.set({
|
|
107
|
+
...args,
|
|
108
|
+
level: "CLASS"
|
|
109
|
+
}, (meta) => {
|
|
110
|
+
if (!meta.properties) meta.properties = [args.propKey];
|
|
111
|
+
else if (!meta.properties.includes(args.propKey)) meta.properties.push(args.propKey);
|
|
112
|
+
return meta;
|
|
113
|
+
});
|
|
114
|
+
level = typeof index === "number" ? "PARAM" : newArgs.propKey && newArgs.descriptor ? "METHOD" : newArgs.propKey ? "PROP" : "CLASS";
|
|
115
|
+
if (typeof key !== "function") if (isArray) {
|
|
116
|
+
const newArray = data[key] || [];
|
|
117
|
+
if (!Array.isArray(newArray))
|
|
118
|
+
/* istanbul ignore next line */
|
|
119
|
+
this.logger.error("Mate.add (isArray=true) called for non-array metadata");
|
|
120
|
+
newArray.unshift(value);
|
|
121
|
+
data[key] = newArray;
|
|
122
|
+
} else data[key] = value;
|
|
123
|
+
else if (cb && typeof index !== "number") meta = cb(data, level, args.propKey, typeof args.index === "number" ? args.index : void 0);
|
|
124
|
+
Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey);
|
|
125
|
+
}
|
|
126
|
+
read(target, propKey) {
|
|
127
|
+
const constructor = isConstructor(target) ? target : getConstructor(target);
|
|
128
|
+
const proto = constructor.prototype;
|
|
129
|
+
const propKeyStr = propKey;
|
|
130
|
+
const ctorCache = this._readCache?.get(constructor);
|
|
131
|
+
if (ctorCache?.has(propKeyStr)) return ctorCache.get(propKeyStr);
|
|
132
|
+
let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === "string" ? proto : constructor, propKey);
|
|
133
|
+
if (ownMeta && propKey === void 0 && ownMeta.params === void 0) {
|
|
134
|
+
const parent = Object.getPrototypeOf(constructor);
|
|
135
|
+
if (typeof parent === "function" && parent !== fnProto && parent !== constructor) ownMeta.params = this.read(parent)?.params;
|
|
136
|
+
}
|
|
137
|
+
if (this.options.inherit) {
|
|
138
|
+
const inheritFn = typeof this.options.inherit === "function" ? this.options.inherit : void 0;
|
|
139
|
+
let shouldInherit = this.options.inherit;
|
|
140
|
+
if (inheritFn) if (typeof propKey === "string") shouldInherit = inheritFn(Reflect.getOwnMetadata(this.workspace, constructor), ownMeta, "PROP", propKey);
|
|
141
|
+
else shouldInherit = inheritFn(ownMeta, ownMeta, "CLASS");
|
|
142
|
+
if (shouldInherit) {
|
|
143
|
+
const parent = Object.getPrototypeOf(constructor);
|
|
144
|
+
if (typeof parent === "function" && parent !== fnProto && parent !== constructor) {
|
|
145
|
+
const inheritedMeta = this.read(parent, propKey) || {};
|
|
146
|
+
const ownParams = ownMeta?.params;
|
|
147
|
+
ownMeta = {
|
|
148
|
+
...inheritedMeta,
|
|
149
|
+
...ownMeta
|
|
150
|
+
};
|
|
151
|
+
if (typeof propKey === "string" && ownParams && inheritedMeta?.params) {
|
|
152
|
+
for (let i = 0; i < ownParams.length; i++) if (typeof inheritedMeta?.params[i] !== "undefined") {
|
|
153
|
+
const ownParam = ownParams[i];
|
|
154
|
+
if (ownMeta.params && inheritFn && inheritFn(ownMeta, ownParam, "PARAM", typeof propKey === "string" ? propKey : void 0)) ownMeta.params[i] = {
|
|
155
|
+
...inheritedMeta?.params[i],
|
|
156
|
+
...ownParams[i]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const cache = this._readCache ??= /* @__PURE__ */ new WeakMap();
|
|
164
|
+
let tc = cache.get(constructor);
|
|
165
|
+
if (!tc) {
|
|
166
|
+
tc = /* @__PURE__ */ new Map();
|
|
167
|
+
cache.set(constructor, tc);
|
|
168
|
+
}
|
|
169
|
+
tc.set(propKeyStr, ownMeta);
|
|
170
|
+
return ownMeta;
|
|
171
|
+
}
|
|
172
|
+
apply(...decorators) {
|
|
173
|
+
return ((target, propKey, descriptor) => {
|
|
174
|
+
for (const d of decorators) d(target, propKey, descriptor);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
decorate(key, value, isArray, level) {
|
|
178
|
+
return ((target, propKey, descriptor) => {
|
|
179
|
+
const args = {
|
|
180
|
+
target,
|
|
181
|
+
propKey,
|
|
182
|
+
descriptor: typeof descriptor === "number" ? void 0 : descriptor,
|
|
183
|
+
index: typeof descriptor === "number" ? descriptor : void 0,
|
|
184
|
+
level
|
|
185
|
+
};
|
|
186
|
+
this.set(args, key, value, isArray);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
decorateConditional(ccb) {
|
|
190
|
+
return ((target, propKey, descriptor) => {
|
|
191
|
+
const d = ccb(typeof descriptor === "number" ? "PARAM" : propKey && descriptor ? "METHOD" : propKey ? "PROP" : "CLASS");
|
|
192
|
+
if (d) d(target, propKey, descriptor);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
decorateClass(key, value, isArray) {
|
|
196
|
+
return this.decorate(key, value, isArray, "CLASS");
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const fnProto = Object.getPrototypeOf(Function);
|
|
200
|
+
|
|
201
|
+
//#endregion
|
|
202
|
+
exports.Mate = Mate;
|
|
203
|
+
exports.getConstructor = getConstructor;
|
|
204
|
+
exports.isConstructor = isConstructor;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region dts-build/types.d.ts
|
|
2
|
+
type TAny = any;
|
|
3
|
+
type TObject = object;
|
|
4
|
+
type TFunction = Function;
|
|
5
|
+
type TClassConstructor<T = unknown> = new (...args: TAny[]) => T;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region dts-build/mate.d.ts
|
|
8
|
+
type TLevels = 'CLASS' | 'METHOD' | 'PROP' | 'PARAM';
|
|
9
|
+
interface TMergedDecoratorArgs {
|
|
10
|
+
target: TFunction | TObject;
|
|
11
|
+
propKey?: string;
|
|
12
|
+
descriptor?: TypedPropertyDescriptor<TAny>;
|
|
13
|
+
index?: number;
|
|
14
|
+
level?: TLevels;
|
|
15
|
+
}
|
|
16
|
+
interface TMateParamMeta {
|
|
17
|
+
type?: TFunction;
|
|
18
|
+
}
|
|
19
|
+
interface TMatePropMeta<TParam extends TObject = TEmpty> {
|
|
20
|
+
params?: (TParam & TMateParamMeta)[];
|
|
21
|
+
}
|
|
22
|
+
interface TMateClassMeta<TParam> {
|
|
23
|
+
properties?: string[];
|
|
24
|
+
type?: TFunction;
|
|
25
|
+
returnType?: TFunction;
|
|
26
|
+
params?: (TParam & TMateParamMeta)[];
|
|
27
|
+
}
|
|
28
|
+
type TCommonMate<TParam extends TObject> = TMateClassMeta<TParam> & TMatePropMeta<TParam>;
|
|
29
|
+
type TCommonMateWithParam<TParam extends TObject> = TMateClassMeta<TParam> & TMatePropMeta<TParam> & TParam;
|
|
30
|
+
interface TConsoleBase {
|
|
31
|
+
error: (...args: any) => void;
|
|
32
|
+
}
|
|
33
|
+
interface TMateOptions<TClass extends TObject = TMateClassMeta<TMateParamMeta>, TProp extends {
|
|
34
|
+
params: TMateParamMeta[];
|
|
35
|
+
} = Required<TMatePropMeta<TMateParamMeta>>> {
|
|
36
|
+
logger?: TConsoleBase;
|
|
37
|
+
readReturnType?: boolean;
|
|
38
|
+
readType?: boolean;
|
|
39
|
+
collectPropKeys?: boolean;
|
|
40
|
+
inherit?: boolean | ((classMeta: TClass & TMateClassMeta<TMateParamMeta>, targetMeta: (TMatePropMeta<TProp['params'][0]> & TProp) | (TMateParamMeta & TProp['params'][0]), level: 'CLASS' | 'PROP' | 'PARAM', key?: string) => boolean);
|
|
41
|
+
}
|
|
42
|
+
interface TEmpty {}
|
|
43
|
+
declare class Mate<TClass extends TObject = TMateClassMeta<TMateParamMeta>, TProp extends {
|
|
44
|
+
params: TMateParamMeta[];
|
|
45
|
+
} = Required<TMatePropMeta<TMateParamMeta>>> {
|
|
46
|
+
protected workspace: string;
|
|
47
|
+
protected options: TMateOptions<TClass, TProp>;
|
|
48
|
+
protected logger: TConsoleBase;
|
|
49
|
+
protected _readCache?: WeakMap<object, Map<string | undefined, unknown>>;
|
|
50
|
+
constructor(workspace: string, options?: TMateOptions<TClass, TProp>);
|
|
51
|
+
/**
|
|
52
|
+
* Cleanup function to reset metadata
|
|
53
|
+
*
|
|
54
|
+
* It is usefull in dev mode when server restarts
|
|
55
|
+
*/
|
|
56
|
+
_cleanup(): void;
|
|
57
|
+
set<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>>(args: TMergedDecoratorArgs, cb: (meta: T, level: TLevels, propKey?: string, index?: number) => T): void;
|
|
58
|
+
set<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>, K extends keyof T = keyof T>(args: TMergedDecoratorArgs, key: keyof T, value: T[K]): void;
|
|
59
|
+
set<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>, K extends keyof T = keyof T>(args: TMergedDecoratorArgs, key: keyof T, value: T[K], isArray: boolean | undefined): void;
|
|
60
|
+
read<PK>(target: TFunction | TObject, propKey?: PK): PK extends string ? (TClass & TProp & TCommonMate<TProp['params'][0]>) | undefined : TClass | undefined;
|
|
61
|
+
apply(...decorators: (MethodDecorator | ClassDecorator | ParameterDecorator | PropertyDecorator)[]): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
62
|
+
decorate<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>>(cb: (meta: T, level: TLevels, propKey?: string, index?: number) => T): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
63
|
+
decorate<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>, K extends keyof T = keyof T>(key: K, value: T[K]): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
64
|
+
decorate<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>, K extends keyof T = keyof T, TIsArray extends boolean = false>(key: K, value: TIsArray extends true ? ArrayElementType<T[K]> : T[K], isArray: TIsArray): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
65
|
+
decorate<T = TClass & TProp & TCommonMateWithParam<TProp['params'][0]>, K extends keyof T = keyof T, TIsArray extends boolean = false>(key: K | ((meta: T, level: TLevels, propKey?: string, index?: number) => T), value: TIsArray extends true ? ArrayElementType<T[K]> : T[K], isArray: TIsArray, level: TMergedDecoratorArgs['level']): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
66
|
+
decorateConditional(ccb: (level: TLevels) => (MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator) | void | undefined): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
67
|
+
decorateClass<T = TClass>(cb: (meta: T, level: TLevels, propKey?: string, index?: number) => T): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
68
|
+
decorateClass<T = TClass, K extends keyof T = keyof T, TIsArray extends boolean = false>(key: K, value: TIsArray extends true ? ArrayElementType<T[K]> : T[K]): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
69
|
+
decorateClass<T = TClass, K extends keyof T = keyof T, TIsArray extends boolean = false>(key: K, value: TIsArray extends true ? ArrayElementType<T[K]> : T[K], isArray: boolean | undefined): MethodDecorator & ClassDecorator & ParameterDecorator & PropertyDecorator;
|
|
70
|
+
}
|
|
71
|
+
type ArrayElementType<T> = T extends (infer E)[] ? E : never;
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region dts-build/utils/helpers.d.ts
|
|
74
|
+
declare function getConstructor<T = TAny>(instance: T): TFunction;
|
|
75
|
+
declare function isConstructor<T = TAny>(v: T): v is T & TClassConstructor;
|
|
76
|
+
//#endregion
|
|
77
|
+
export { Mate, TMateClassMeta, TMateOptions, TMateParamMeta, TMatePropMeta, TMergedDecoratorArgs, getConstructor, isConstructor };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
//#region src/utils/helpers.ts
|
|
2
|
+
function getConstructor(instance) {
|
|
3
|
+
return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor;
|
|
4
|
+
}
|
|
5
|
+
function isConstructor(v) {
|
|
6
|
+
return typeof v === "function" && Object.getOwnPropertyDescriptor(v, "prototype") !== void 0 && Object.getOwnPropertyDescriptor(v, "caller") === void 0 && !!v.name;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/reflect.ts
|
|
11
|
+
let classMetadata = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
let paramMetadata = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
const root = typeof global === "object" ? global : typeof self === "object" ? self : {};
|
|
14
|
+
function getMetaObject(target, prop) {
|
|
15
|
+
const isParam = typeof prop !== "undefined";
|
|
16
|
+
const metadata = isParam ? paramMetadata : classMetadata;
|
|
17
|
+
const targetKey = getConstructor(target);
|
|
18
|
+
let meta = metadata.get(targetKey);
|
|
19
|
+
if (!meta) {
|
|
20
|
+
meta = {};
|
|
21
|
+
metadata.set(targetKey, meta);
|
|
22
|
+
}
|
|
23
|
+
if (isParam) meta = meta[prop] = meta[prop] || {};
|
|
24
|
+
return meta;
|
|
25
|
+
}
|
|
26
|
+
const _reflect = {
|
|
27
|
+
getOwnMetadata(key, target, prop) {
|
|
28
|
+
return getMetaObject(target, prop)[key];
|
|
29
|
+
},
|
|
30
|
+
defineMetadata(key, data, target, prop) {
|
|
31
|
+
const meta = getMetaObject(target, prop);
|
|
32
|
+
meta[key] = data;
|
|
33
|
+
},
|
|
34
|
+
metadata(key, data) {
|
|
35
|
+
return ((target, propKey) => {
|
|
36
|
+
Reflect$1.defineMetadata(key, data, target, propKey);
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
_cleanup: (() => {
|
|
40
|
+
classMetadata = /* @__PURE__ */ new WeakMap();
|
|
41
|
+
paramMetadata = /* @__PURE__ */ new WeakMap();
|
|
42
|
+
})
|
|
43
|
+
};
|
|
44
|
+
if (!root.Reflect) root.Reflect = _reflect;
|
|
45
|
+
else {
|
|
46
|
+
const funcs = [
|
|
47
|
+
"getOwnMetadata",
|
|
48
|
+
"defineMetadata",
|
|
49
|
+
"metadata"
|
|
50
|
+
];
|
|
51
|
+
const target = root.Reflect;
|
|
52
|
+
for (const func of funcs) if (typeof target[func] !== "function") Object.defineProperty(target, func, {
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
value: _reflect[func]
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const Reflect$1 = _reflect;
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/mate.ts
|
|
62
|
+
const Reflect = global?.Reflect || self?.Reflect || Reflect$1;
|
|
63
|
+
var Mate = class {
|
|
64
|
+
constructor(workspace, options = {}) {
|
|
65
|
+
this.workspace = workspace;
|
|
66
|
+
this.options = options;
|
|
67
|
+
this.logger = options.logger || console;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Cleanup function to reset metadata
|
|
71
|
+
*
|
|
72
|
+
* It is usefull in dev mode when server restarts
|
|
73
|
+
*/
|
|
74
|
+
_cleanup() {
|
|
75
|
+
Reflect._cleanup?.call(Reflect);
|
|
76
|
+
this._readCache = void 0;
|
|
77
|
+
}
|
|
78
|
+
set(args, key, value, isArray) {
|
|
79
|
+
this._readCache = void 0;
|
|
80
|
+
let level = "CLASS";
|
|
81
|
+
const newArgs = args.level === "CLASS" ? { target: getConstructor(args.target) } : args.level === "PROP" ? {
|
|
82
|
+
target: args.target,
|
|
83
|
+
propKey: args.propKey
|
|
84
|
+
} : args;
|
|
85
|
+
let meta = Reflect.getOwnMetadata(this.workspace, newArgs.target, newArgs.propKey) || {};
|
|
86
|
+
if (newArgs.propKey && this.options.readReturnType && !meta.returnType && args.descriptor) meta.returnType = Reflect.getOwnMetadata("design:returntype", newArgs.target, newArgs.propKey);
|
|
87
|
+
if (newArgs.propKey && this.options.readType && !meta.type) meta.type = Reflect.getOwnMetadata("design:type", newArgs.target, newArgs.propKey);
|
|
88
|
+
const { index } = newArgs;
|
|
89
|
+
const cb = typeof key === "function" ? key : void 0;
|
|
90
|
+
let data = meta;
|
|
91
|
+
if (!data.params) {
|
|
92
|
+
const paramTypes = Reflect.getOwnMetadata("design:paramtypes", newArgs.target, newArgs.propKey);
|
|
93
|
+
if (paramTypes) {
|
|
94
|
+
data.params = new Array(paramTypes.length);
|
|
95
|
+
for (let i = 0; i < paramTypes.length; i++) data.params[i] = { type: paramTypes[i] };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (typeof index === "number") {
|
|
99
|
+
level = "PARAM";
|
|
100
|
+
data.params = data.params || [];
|
|
101
|
+
data.params[index] = data.params[index] || { type: void 0 };
|
|
102
|
+
if (cb) data.params[index] = cb(data.params[index], level, args.propKey, typeof args.index === "number" ? args.index : void 0);
|
|
103
|
+
else data = data.params[index];
|
|
104
|
+
} else if (!index && !args.descriptor && args.propKey && this.options.collectPropKeys && args.level !== "CLASS") this.set({
|
|
105
|
+
...args,
|
|
106
|
+
level: "CLASS"
|
|
107
|
+
}, (meta) => {
|
|
108
|
+
if (!meta.properties) meta.properties = [args.propKey];
|
|
109
|
+
else if (!meta.properties.includes(args.propKey)) meta.properties.push(args.propKey);
|
|
110
|
+
return meta;
|
|
111
|
+
});
|
|
112
|
+
level = typeof index === "number" ? "PARAM" : newArgs.propKey && newArgs.descriptor ? "METHOD" : newArgs.propKey ? "PROP" : "CLASS";
|
|
113
|
+
if (typeof key !== "function") if (isArray) {
|
|
114
|
+
const newArray = data[key] || [];
|
|
115
|
+
if (!Array.isArray(newArray))
|
|
116
|
+
/* istanbul ignore next line */
|
|
117
|
+
this.logger.error("Mate.add (isArray=true) called for non-array metadata");
|
|
118
|
+
newArray.unshift(value);
|
|
119
|
+
data[key] = newArray;
|
|
120
|
+
} else data[key] = value;
|
|
121
|
+
else if (cb && typeof index !== "number") meta = cb(data, level, args.propKey, typeof args.index === "number" ? args.index : void 0);
|
|
122
|
+
Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey);
|
|
123
|
+
}
|
|
124
|
+
read(target, propKey) {
|
|
125
|
+
const constructor = isConstructor(target) ? target : getConstructor(target);
|
|
126
|
+
const proto = constructor.prototype;
|
|
127
|
+
const propKeyStr = propKey;
|
|
128
|
+
const ctorCache = this._readCache?.get(constructor);
|
|
129
|
+
if (ctorCache?.has(propKeyStr)) return ctorCache.get(propKeyStr);
|
|
130
|
+
let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === "string" ? proto : constructor, propKey);
|
|
131
|
+
if (ownMeta && propKey === void 0 && ownMeta.params === void 0) {
|
|
132
|
+
const parent = Object.getPrototypeOf(constructor);
|
|
133
|
+
if (typeof parent === "function" && parent !== fnProto && parent !== constructor) ownMeta.params = this.read(parent)?.params;
|
|
134
|
+
}
|
|
135
|
+
if (this.options.inherit) {
|
|
136
|
+
const inheritFn = typeof this.options.inherit === "function" ? this.options.inherit : void 0;
|
|
137
|
+
let shouldInherit = this.options.inherit;
|
|
138
|
+
if (inheritFn) if (typeof propKey === "string") shouldInherit = inheritFn(Reflect.getOwnMetadata(this.workspace, constructor), ownMeta, "PROP", propKey);
|
|
139
|
+
else shouldInherit = inheritFn(ownMeta, ownMeta, "CLASS");
|
|
140
|
+
if (shouldInherit) {
|
|
141
|
+
const parent = Object.getPrototypeOf(constructor);
|
|
142
|
+
if (typeof parent === "function" && parent !== fnProto && parent !== constructor) {
|
|
143
|
+
const inheritedMeta = this.read(parent, propKey) || {};
|
|
144
|
+
const ownParams = ownMeta?.params;
|
|
145
|
+
ownMeta = {
|
|
146
|
+
...inheritedMeta,
|
|
147
|
+
...ownMeta
|
|
148
|
+
};
|
|
149
|
+
if (typeof propKey === "string" && ownParams && inheritedMeta?.params) {
|
|
150
|
+
for (let i = 0; i < ownParams.length; i++) if (typeof inheritedMeta?.params[i] !== "undefined") {
|
|
151
|
+
const ownParam = ownParams[i];
|
|
152
|
+
if (ownMeta.params && inheritFn && inheritFn(ownMeta, ownParam, "PARAM", typeof propKey === "string" ? propKey : void 0)) ownMeta.params[i] = {
|
|
153
|
+
...inheritedMeta?.params[i],
|
|
154
|
+
...ownParams[i]
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const cache = this._readCache ??= /* @__PURE__ */ new WeakMap();
|
|
162
|
+
let tc = cache.get(constructor);
|
|
163
|
+
if (!tc) {
|
|
164
|
+
tc = /* @__PURE__ */ new Map();
|
|
165
|
+
cache.set(constructor, tc);
|
|
166
|
+
}
|
|
167
|
+
tc.set(propKeyStr, ownMeta);
|
|
168
|
+
return ownMeta;
|
|
169
|
+
}
|
|
170
|
+
apply(...decorators) {
|
|
171
|
+
return ((target, propKey, descriptor) => {
|
|
172
|
+
for (const d of decorators) d(target, propKey, descriptor);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
decorate(key, value, isArray, level) {
|
|
176
|
+
return ((target, propKey, descriptor) => {
|
|
177
|
+
const args = {
|
|
178
|
+
target,
|
|
179
|
+
propKey,
|
|
180
|
+
descriptor: typeof descriptor === "number" ? void 0 : descriptor,
|
|
181
|
+
index: typeof descriptor === "number" ? descriptor : void 0,
|
|
182
|
+
level
|
|
183
|
+
};
|
|
184
|
+
this.set(args, key, value, isArray);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
decorateConditional(ccb) {
|
|
188
|
+
return ((target, propKey, descriptor) => {
|
|
189
|
+
const d = ccb(typeof descriptor === "number" ? "PARAM" : propKey && descriptor ? "METHOD" : propKey ? "PROP" : "CLASS");
|
|
190
|
+
if (d) d(target, propKey, descriptor);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
decorateClass(key, value, isArray) {
|
|
194
|
+
return this.decorate(key, value, isArray, "CLASS");
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const fnProto = Object.getPrototypeOf(Function);
|
|
198
|
+
|
|
199
|
+
//#endregion
|
|
200
|
+
export { Mate, getConstructor, isConstructor };
|