@prostojs/mate 0.4.0 → 0.5.1
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/dist/index.cjs +62 -7
- package/dist/index.d.ts +38 -1
- package/dist/index.mjs +60 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
|
+
//#region src/module-identity.ts
|
|
4
|
+
const MATE_MODULE_IDENTITY_KEY = Symbol.for("prostojs:mate:module-identity");
|
|
5
|
+
function getModulePath() {
|
|
6
|
+
try {
|
|
7
|
+
return require("url").pathToFileURL(__filename).href;
|
|
8
|
+
} catch {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function formatIdentity(identity) {
|
|
13
|
+
const version = identity.version ? `v${identity.version}` : "unknown version";
|
|
14
|
+
return identity.path ? `${version} at ${identity.path}` : version;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Stamps `globalThis` with this copy's identity and warns if another
|
|
18
|
+
* copy of @prostojs/mate was already loaded.
|
|
19
|
+
*
|
|
20
|
+
* Invoked once at module scope from index.ts, so importing the package
|
|
21
|
+
* performs the check.
|
|
22
|
+
*/
|
|
23
|
+
function warnOnDuplicateMate() {
|
|
24
|
+
const g = globalThis;
|
|
25
|
+
const identity = {};
|
|
26
|
+
identity.version = "0.5.0";
|
|
27
|
+
const path = getModulePath();
|
|
28
|
+
if (path) identity.path = path;
|
|
29
|
+
const first = g[MATE_MODULE_IDENTITY_KEY];
|
|
30
|
+
if (first) console.warn(`[mate] A second copy of @prostojs/mate was loaded (${formatIdentity(first)}, now ${formatIdentity(identity)}). Decorator metadata is stored per-copy and will NOT be visible across copies. Check your bundler/dedupe settings.`);
|
|
31
|
+
else g[MATE_MODULE_IDENTITY_KEY] = identity;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
3
35
|
//#region src/utils/helpers.ts
|
|
36
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
4
37
|
function getConstructor(instance) {
|
|
5
38
|
return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor;
|
|
6
39
|
}
|
|
7
40
|
function isConstructor(v) {
|
|
8
|
-
return typeof v === "function" &&
|
|
41
|
+
return typeof v === "function" && hasOwn.call(v, "prototype") && !hasOwn.call(v, "caller") && !!v.name;
|
|
9
42
|
}
|
|
10
43
|
|
|
11
44
|
//#endregion
|
|
@@ -76,9 +109,11 @@ var Mate = class {
|
|
|
76
109
|
_cleanup() {
|
|
77
110
|
Reflect._cleanup?.call(Reflect);
|
|
78
111
|
this._readCache = void 0;
|
|
112
|
+
this._readCacheNonCtor = void 0;
|
|
79
113
|
}
|
|
80
114
|
set(args, key, value, isArray) {
|
|
81
115
|
this._readCache = void 0;
|
|
116
|
+
this._readCacheNonCtor = void 0;
|
|
82
117
|
let level = "CLASS";
|
|
83
118
|
const newArgs = args.level === "CLASS" ? { target: getConstructor(args.target) } : args.level === "PROP" ? {
|
|
84
119
|
target: args.target,
|
|
@@ -124,11 +159,19 @@ var Mate = class {
|
|
|
124
159
|
Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey);
|
|
125
160
|
}
|
|
126
161
|
read(target, propKey) {
|
|
127
|
-
const constructor = isConstructor(target) ? target : getConstructor(target);
|
|
128
|
-
const proto = constructor.prototype;
|
|
129
162
|
const propKeyStr = propKey;
|
|
130
|
-
const
|
|
131
|
-
if (
|
|
163
|
+
const ctorCacheRoot = this._readCache;
|
|
164
|
+
if (ctorCacheRoot !== void 0 && typeof target === "function") {
|
|
165
|
+
const hit = readCached(ctorCacheRoot.get(target), propKeyStr);
|
|
166
|
+
if (hit !== MISS) return hit;
|
|
167
|
+
}
|
|
168
|
+
const isConstr = isConstructor(target);
|
|
169
|
+
const constructor = isConstr ? target : getConstructor(target);
|
|
170
|
+
if (!isConstr) {
|
|
171
|
+
const hit = readCached(ctorCacheRoot?.get(constructor) ?? this._readCacheNonCtor?.get(constructor), propKeyStr);
|
|
172
|
+
if (hit !== MISS) return hit;
|
|
173
|
+
}
|
|
174
|
+
const proto = constructor.prototype;
|
|
132
175
|
let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === "string" ? proto : constructor, propKey);
|
|
133
176
|
if (ownMeta && propKey === void 0 && ownMeta.params === void 0) {
|
|
134
177
|
const parent = Object.getPrototypeOf(constructor);
|
|
@@ -160,7 +203,7 @@ var Mate = class {
|
|
|
160
203
|
}
|
|
161
204
|
}
|
|
162
205
|
}
|
|
163
|
-
const cache = this._readCache ??= /* @__PURE__ */ new WeakMap();
|
|
206
|
+
const cache = isConstr || typeof constructor !== "function" || isConstructor(constructor) ? this._readCache ??= /* @__PURE__ */ new WeakMap() : this._readCacheNonCtor ??= /* @__PURE__ */ new WeakMap();
|
|
164
207
|
let tc = cache.get(constructor);
|
|
165
208
|
if (!tc) {
|
|
166
209
|
tc = /* @__PURE__ */ new Map();
|
|
@@ -197,8 +240,20 @@ var Mate = class {
|
|
|
197
240
|
}
|
|
198
241
|
};
|
|
199
242
|
const fnProto = Object.getPrototypeOf(Function);
|
|
243
|
+
const MISS = Symbol("mate.read.miss");
|
|
244
|
+
function readCached(tc, propKey) {
|
|
245
|
+
if (tc === void 0) return MISS;
|
|
246
|
+
const v = tc.get(propKey);
|
|
247
|
+
return v !== void 0 || tc.has(propKey) ? v : MISS;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/index.ts
|
|
252
|
+
warnOnDuplicateMate();
|
|
200
253
|
|
|
201
254
|
//#endregion
|
|
255
|
+
exports.MATE_MODULE_IDENTITY_KEY = MATE_MODULE_IDENTITY_KEY;
|
|
202
256
|
exports.Mate = Mate;
|
|
203
257
|
exports.getConstructor = getConstructor;
|
|
204
|
-
exports.isConstructor = isConstructor;
|
|
258
|
+
exports.isConstructor = isConstructor;
|
|
259
|
+
exports.warnOnDuplicateMate = warnOnDuplicateMate;
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,19 @@ declare class Mate<TClass extends TObject = TMateClassMeta<TMateParamMeta>, TPro
|
|
|
46
46
|
protected workspace: string;
|
|
47
47
|
protected options: TMateOptions<TClass, TProp>;
|
|
48
48
|
protected logger: TConsoleBase;
|
|
49
|
+
/**
|
|
50
|
+
* Read cache keyed by the resolved constructor. Invariant: every function
|
|
51
|
+
* key here passed `isConstructor` when stored, so a hit on a function
|
|
52
|
+
* `target` itself proves `target` is that constructor — `read` probes
|
|
53
|
+
* it before running `isConstructor`.
|
|
54
|
+
*/
|
|
49
55
|
protected _readCache?: WeakMap<object, Map<string | undefined, unknown>>;
|
|
56
|
+
/**
|
|
57
|
+
* Read cache for resolved "constructors" that are functions failing
|
|
58
|
+
* `isConstructor` (e.g. an anonymous class reached through an instance's
|
|
59
|
+
* `.constructor`). Kept apart so they cannot satisfy the fast probe.
|
|
60
|
+
*/
|
|
61
|
+
protected _readCacheNonCtor?: WeakMap<object, Map<string | undefined, unknown>>;
|
|
50
62
|
constructor(workspace: string, options?: TMateOptions<TClass, TProp>);
|
|
51
63
|
/**
|
|
52
64
|
* Cleanup function to reset metadata
|
|
@@ -70,8 +82,33 @@ declare class Mate<TClass extends TObject = TMateClassMeta<TMateParamMeta>, TPro
|
|
|
70
82
|
}
|
|
71
83
|
type ArrayElementType<T> = T extends (infer E)[] ? E : never;
|
|
72
84
|
//#endregion
|
|
85
|
+
//#region dts-build/module-identity.d.ts
|
|
86
|
+
/**
|
|
87
|
+
* Duplicate-copy detection for @prostojs/mate
|
|
88
|
+
*
|
|
89
|
+
* Mate stores class metadata in WeakMaps keyed by constructor reference.
|
|
90
|
+
* If a bundler loads two copies of mate (or of a decorated class),
|
|
91
|
+
* decorators run against one copy while lookups hit the other, and
|
|
92
|
+
* metadata silently "disappears". The first loaded copy stamps
|
|
93
|
+
* `globalThis` under a global symbol; any subsequent copy finds the
|
|
94
|
+
* stamp and warns.
|
|
95
|
+
*/
|
|
96
|
+
interface TMateModuleIdentity {
|
|
97
|
+
version?: string;
|
|
98
|
+
path?: string;
|
|
99
|
+
}
|
|
100
|
+
declare const MATE_MODULE_IDENTITY_KEY: unique symbol;
|
|
101
|
+
/**
|
|
102
|
+
* Stamps `globalThis` with this copy's identity and warns if another
|
|
103
|
+
* copy of @prostojs/mate was already loaded.
|
|
104
|
+
*
|
|
105
|
+
* Invoked once at module scope from index.ts, so importing the package
|
|
106
|
+
* performs the check.
|
|
107
|
+
*/
|
|
108
|
+
declare function warnOnDuplicateMate(): void;
|
|
109
|
+
//#endregion
|
|
73
110
|
//#region dts-build/utils/helpers.d.ts
|
|
74
111
|
declare function getConstructor<T = TAny>(instance: T): TFunction;
|
|
75
112
|
declare function isConstructor<T = TAny>(v: T): v is T & TClassConstructor;
|
|
76
113
|
//#endregion
|
|
77
|
-
export { Mate, TMateClassMeta, TMateOptions, TMateParamMeta, TMatePropMeta, TMergedDecoratorArgs, getConstructor, isConstructor };
|
|
114
|
+
export { MATE_MODULE_IDENTITY_KEY, Mate, TMateClassMeta, TMateModuleIdentity, TMateOptions, TMateParamMeta, TMatePropMeta, TMergedDecoratorArgs, getConstructor, isConstructor, warnOnDuplicateMate };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
|
+
//#region src/module-identity.ts
|
|
2
|
+
const MATE_MODULE_IDENTITY_KEY = Symbol.for("prostojs:mate:module-identity");
|
|
3
|
+
function getModulePath() {
|
|
4
|
+
try {
|
|
5
|
+
return import.meta.url;
|
|
6
|
+
} catch {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function formatIdentity(identity) {
|
|
11
|
+
const version = identity.version ? `v${identity.version}` : "unknown version";
|
|
12
|
+
return identity.path ? `${version} at ${identity.path}` : version;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Stamps `globalThis` with this copy's identity and warns if another
|
|
16
|
+
* copy of @prostojs/mate was already loaded.
|
|
17
|
+
*
|
|
18
|
+
* Invoked once at module scope from index.ts, so importing the package
|
|
19
|
+
* performs the check.
|
|
20
|
+
*/
|
|
21
|
+
function warnOnDuplicateMate() {
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
const identity = {};
|
|
24
|
+
identity.version = "0.5.0";
|
|
25
|
+
const path = getModulePath();
|
|
26
|
+
if (path) identity.path = path;
|
|
27
|
+
const first = g[MATE_MODULE_IDENTITY_KEY];
|
|
28
|
+
if (first) console.warn(`[mate] A second copy of @prostojs/mate was loaded (${formatIdentity(first)}, now ${formatIdentity(identity)}). Decorator metadata is stored per-copy and will NOT be visible across copies. Check your bundler/dedupe settings.`);
|
|
29
|
+
else g[MATE_MODULE_IDENTITY_KEY] = identity;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
1
33
|
//#region src/utils/helpers.ts
|
|
34
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
2
35
|
function getConstructor(instance) {
|
|
3
36
|
return isConstructor(instance) ? instance : instance.constructor ? instance.constructor : Object.getPrototypeOf(instance).constructor;
|
|
4
37
|
}
|
|
5
38
|
function isConstructor(v) {
|
|
6
|
-
return typeof v === "function" &&
|
|
39
|
+
return typeof v === "function" && hasOwn.call(v, "prototype") && !hasOwn.call(v, "caller") && !!v.name;
|
|
7
40
|
}
|
|
8
41
|
|
|
9
42
|
//#endregion
|
|
@@ -74,9 +107,11 @@ var Mate = class {
|
|
|
74
107
|
_cleanup() {
|
|
75
108
|
Reflect._cleanup?.call(Reflect);
|
|
76
109
|
this._readCache = void 0;
|
|
110
|
+
this._readCacheNonCtor = void 0;
|
|
77
111
|
}
|
|
78
112
|
set(args, key, value, isArray) {
|
|
79
113
|
this._readCache = void 0;
|
|
114
|
+
this._readCacheNonCtor = void 0;
|
|
80
115
|
let level = "CLASS";
|
|
81
116
|
const newArgs = args.level === "CLASS" ? { target: getConstructor(args.target) } : args.level === "PROP" ? {
|
|
82
117
|
target: args.target,
|
|
@@ -122,11 +157,19 @@ var Mate = class {
|
|
|
122
157
|
Reflect.defineMetadata(this.workspace, meta, newArgs.target, newArgs.propKey);
|
|
123
158
|
}
|
|
124
159
|
read(target, propKey) {
|
|
125
|
-
const constructor = isConstructor(target) ? target : getConstructor(target);
|
|
126
|
-
const proto = constructor.prototype;
|
|
127
160
|
const propKeyStr = propKey;
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
161
|
+
const ctorCacheRoot = this._readCache;
|
|
162
|
+
if (ctorCacheRoot !== void 0 && typeof target === "function") {
|
|
163
|
+
const hit = readCached(ctorCacheRoot.get(target), propKeyStr);
|
|
164
|
+
if (hit !== MISS) return hit;
|
|
165
|
+
}
|
|
166
|
+
const isConstr = isConstructor(target);
|
|
167
|
+
const constructor = isConstr ? target : getConstructor(target);
|
|
168
|
+
if (!isConstr) {
|
|
169
|
+
const hit = readCached(ctorCacheRoot?.get(constructor) ?? this._readCacheNonCtor?.get(constructor), propKeyStr);
|
|
170
|
+
if (hit !== MISS) return hit;
|
|
171
|
+
}
|
|
172
|
+
const proto = constructor.prototype;
|
|
130
173
|
let ownMeta = Reflect.getOwnMetadata(this.workspace, typeof propKey === "string" ? proto : constructor, propKey);
|
|
131
174
|
if (ownMeta && propKey === void 0 && ownMeta.params === void 0) {
|
|
132
175
|
const parent = Object.getPrototypeOf(constructor);
|
|
@@ -158,7 +201,7 @@ var Mate = class {
|
|
|
158
201
|
}
|
|
159
202
|
}
|
|
160
203
|
}
|
|
161
|
-
const cache = this._readCache ??= /* @__PURE__ */ new WeakMap();
|
|
204
|
+
const cache = isConstr || typeof constructor !== "function" || isConstructor(constructor) ? this._readCache ??= /* @__PURE__ */ new WeakMap() : this._readCacheNonCtor ??= /* @__PURE__ */ new WeakMap();
|
|
162
205
|
let tc = cache.get(constructor);
|
|
163
206
|
if (!tc) {
|
|
164
207
|
tc = /* @__PURE__ */ new Map();
|
|
@@ -195,6 +238,16 @@ var Mate = class {
|
|
|
195
238
|
}
|
|
196
239
|
};
|
|
197
240
|
const fnProto = Object.getPrototypeOf(Function);
|
|
241
|
+
const MISS = Symbol("mate.read.miss");
|
|
242
|
+
function readCached(tc, propKey) {
|
|
243
|
+
if (tc === void 0) return MISS;
|
|
244
|
+
const v = tc.get(propKey);
|
|
245
|
+
return v !== void 0 || tc.has(propKey) ? v : MISS;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/index.ts
|
|
250
|
+
warnOnDuplicateMate();
|
|
198
251
|
|
|
199
252
|
//#endregion
|
|
200
|
-
export { Mate, getConstructor, isConstructor };
|
|
253
|
+
export { MATE_MODULE_IDENTITY_KEY, Mate, getConstructor, isConstructor, warnOnDuplicateMate };
|