@carbonenginejs/runtime-utils 0.1.1 → 0.1.3
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/LICENSE +21 -21
- package/NOTICE +23 -23
- package/README.md +69 -69
- package/THIRD-PARTY-NOTICES.md +64 -64
- package/docs/README.md +74 -73
- package/docs/architecture.md +101 -101
- package/docs/concepts/foundation-consolidation.md +85 -85
- package/docs/concepts/model-lifecycle.md +111 -0
- package/docs/const-kb.md +85 -87
- package/docs/core-types/DECORATOR-TODOS.md +25 -25
- package/docs/core-types/README.md +229 -168
- package/docs/reference/api.md +105 -102
- package/docs/reference/classes/README.md +135 -135
- package/package.json +139 -139
- package/src/arrays.js +5 -5
- package/src/audio/audioFormats.js +34 -34
- package/src/audio/index.js +1 -1
- package/src/box3.js +331 -331
- package/src/bytes.js +56 -56
- package/src/compression.js +56 -56
- package/src/constants/index.js +7 -7
- package/src/constants/trinity.js +13 -13
- package/src/constants.js +15 -15
- package/src/curve.js +79 -79
- package/src/d3d/dxgiFormats.js +46 -46
- package/src/d3d/index.js +2 -2
- package/src/d3d/primitiveTopology.js +11 -11
- package/src/document/CjsCarbonDocument.js +212 -212
- package/src/document/CjsClassRegistry.js +373 -373
- package/src/document/CjsDocumentDehydrator.js +142 -142
- package/src/document/CjsDocumentHydrator.js +156 -156
- package/src/document/CjsStructRegistry.js +348 -348
- package/src/document/hydrationAdapter.js +129 -129
- package/src/document/index.js +6 -6
- package/src/errors/CjsError.js +286 -286
- package/src/errors/index.js +5 -5
- package/src/geometry/box.js +22 -22
- package/src/geometry/cylinder.js +22 -22
- package/src/geometry/helpers/earcut.js +1 -1
- package/src/geometry/helpers/misc.js +3 -3
- package/src/geometry/index.js +8 -8
- package/src/geometry/json.js +67 -67
- package/src/geometry/lathe.js +44 -44
- package/src/geometry/plane.js +14 -14
- package/src/geometry/shape.js +4 -4
- package/src/geometry/sphere.js +24 -24
- package/src/geometry/torus.js +14 -14
- package/src/graphics/colorSpaces.js +22 -22
- package/src/graphics/index.js +4 -4
- package/src/graphics/pixelFormats.js +158 -158
- package/src/graphics/textureDimensions.js +22 -22
- package/src/graphics/trinityEnums.js +87 -87
- package/src/index.js +62 -62
- package/src/is.js +108 -46
- package/src/json.js +23 -23
- package/src/lifecycle/CjsLifecycleState.js +77 -77
- package/src/lifecycle/index.js +1 -1
- package/src/lne3.js +70 -70
- package/src/lookup.js +48 -48
- package/src/mat3.js +51 -51
- package/src/mat4.js +699 -699
- package/src/math/index.js +25 -25
- package/src/math/scalar.js +63 -63
- package/src/media/index.js +1 -1
- package/src/media/mediaTypes.js +50 -50
- package/src/mesh.js +424 -424
- package/src/model/CjsEventEmitter.js +333 -333
- package/src/model/CjsModel.js +1589 -1544
- package/src/model/CjsModelState.js +72 -72
- package/src/model/index.js +4 -4
- package/src/model/sourceRecordUtils.js +54 -54
- package/src/noise.js +310 -310
- package/src/num.js +827 -827
- package/src/object.js +39 -39
- package/src/path.js +53 -53
- package/src/pln.js +125 -125
- package/src/pool.js +9 -9
- package/src/quat.js +144 -144
- package/src/ray3.js +188 -188
- package/src/renderContext/formats.js +145 -145
- package/src/renderContext/index.js +5 -5
- package/src/renderContext/presentation.js +125 -125
- package/src/renderContext/resources.js +27 -27
- package/src/renderContext/upscaling.js +22 -22
- package/src/renderContext/window.js +20 -20
- package/src/runtime/CjsRuntimeState.js +50 -50
- package/src/schema/CjsSchema.js +555 -318
- package/src/schema/index.js +4 -4
- package/src/shader/index.js +1 -1
- package/src/shader/shaderStages.js +37 -37
- package/src/sph3.js +181 -181
- package/src/tangent.js +288 -288
- package/src/text.js +40 -40
- package/src/tri3.js +98 -98
- package/src/types/carbonTypes.js +635 -635
- package/src/types/index.js +2 -2
- package/src/utils.js +58 -58
- package/src/validation.js +46 -46
- package/src/vec2.js +229 -229
- package/src/vec3.js +1188 -1172
- package/src/vec4.js +347 -347
- package/src/vertex.js +108 -108
- package/src/webgpu/index.js +1 -1
- package/src/webgpu/textureFormats.js +121 -121
|
@@ -1,373 +1,373 @@
|
|
|
1
|
-
import { CjsSchema } from "../schema/index.js";
|
|
2
|
-
|
|
3
|
-
/** Maps serialized Carbon class names to explicit runtime constructors. */
|
|
4
|
-
export class CjsClassRegistry
|
|
5
|
-
{
|
|
6
|
-
constructor(options = {})
|
|
7
|
-
{
|
|
8
|
-
const {
|
|
9
|
-
name = "registry",
|
|
10
|
-
family = "",
|
|
11
|
-
constructors = null,
|
|
12
|
-
sourceShapes = null,
|
|
13
|
-
modules = null,
|
|
14
|
-
entries = [],
|
|
15
|
-
aliases = null,
|
|
16
|
-
metadata = {}
|
|
17
|
-
} = options;
|
|
18
|
-
|
|
19
|
-
this.name = String(name || "registry");
|
|
20
|
-
this.family = String(family || "");
|
|
21
|
-
this.metadata = { ...metadata };
|
|
22
|
-
this.entries = new Map();
|
|
23
|
-
this.aliases = new Map();
|
|
24
|
-
this.reports = [];
|
|
25
|
-
|
|
26
|
-
if (constructors || sourceShapes || modules)
|
|
27
|
-
{
|
|
28
|
-
this.RegisterMaps({ constructors, sourceShapes, modules, aliases });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
this.RegisterMany(entries);
|
|
32
|
-
this.RegisterAliases(aliases);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get size()
|
|
36
|
-
{
|
|
37
|
-
return this.entries.size;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
RegisterMaps(options = {})
|
|
41
|
-
{
|
|
42
|
-
const {
|
|
43
|
-
constructors = {},
|
|
44
|
-
sourceShapes = {},
|
|
45
|
-
modules = {},
|
|
46
|
-
aliases = {}
|
|
47
|
-
} = options;
|
|
48
|
-
|
|
49
|
-
const names = new Set([
|
|
50
|
-
...Object.keys(constructors || {}).filter(name => typeof constructors[name] === "function"),
|
|
51
|
-
...Object.keys(sourceShapes || {}),
|
|
52
|
-
...Object.keys(modules || {})
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
for (const className of names)
|
|
56
|
-
{
|
|
57
|
-
const constructor = typeof constructors?.[className] === "function" ? constructors[className] : null;
|
|
58
|
-
const sourceShape = sourceShapes?.[className] || null;
|
|
59
|
-
const moduleEntry = modules?.[className] || null;
|
|
60
|
-
|
|
61
|
-
this.Register({
|
|
62
|
-
className,
|
|
63
|
-
constructor,
|
|
64
|
-
sourceShape,
|
|
65
|
-
folder: moduleEntry?.folder || "",
|
|
66
|
-
modulePath: moduleEntry?.modulePath || "",
|
|
67
|
-
registryEntry: moduleEntry,
|
|
68
|
-
aliases: aliasesForClassName(className, aliases),
|
|
69
|
-
family: sourceShape?.family || this.family
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
RegisterMany(entries = [])
|
|
77
|
-
{
|
|
78
|
-
const list = Array.isArray(entries) ? entries : Object.values(entries || {});
|
|
79
|
-
for (const entry of list)
|
|
80
|
-
{
|
|
81
|
-
this.Register(entry);
|
|
82
|
-
}
|
|
83
|
-
return this;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
Register(entry)
|
|
87
|
-
{
|
|
88
|
-
const normalized = normalizeRegistryEntry(entry, this.family);
|
|
89
|
-
const existing = this.entries.get(normalized.className);
|
|
90
|
-
|
|
91
|
-
if (existing)
|
|
92
|
-
{
|
|
93
|
-
this.entries.set(normalized.className, mergeRegistryEntries(existing, normalized));
|
|
94
|
-
this.ReportEntryClashes(existing, normalized);
|
|
95
|
-
}
|
|
96
|
-
else
|
|
97
|
-
{
|
|
98
|
-
this.entries.set(normalized.className, normalized);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
for (const alias of normalized.aliases)
|
|
102
|
-
{
|
|
103
|
-
this.RegisterAlias(alias, normalized.className);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
RegisterAliases(aliases = null)
|
|
110
|
-
{
|
|
111
|
-
if (!aliases) return this;
|
|
112
|
-
|
|
113
|
-
if (Array.isArray(aliases))
|
|
114
|
-
{
|
|
115
|
-
for (const item of aliases)
|
|
116
|
-
{
|
|
117
|
-
if (Array.isArray(item)) this.RegisterAlias(item[0], item[1]);
|
|
118
|
-
else this.RegisterAlias(item.alias, item.className || item.target);
|
|
119
|
-
}
|
|
120
|
-
return this;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
for (const [key, value] of Object.entries(aliases))
|
|
124
|
-
{
|
|
125
|
-
if (Array.isArray(value))
|
|
126
|
-
{
|
|
127
|
-
for (const alias of value)
|
|
128
|
-
{
|
|
129
|
-
this.RegisterAlias(alias, key);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else
|
|
133
|
-
{
|
|
134
|
-
this.RegisterAlias(key, value);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return this;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
RegisterAlias(alias, className)
|
|
142
|
-
{
|
|
143
|
-
if (!alias || !className) return this;
|
|
144
|
-
|
|
145
|
-
const normalizedAlias = String(alias);
|
|
146
|
-
const normalizedClassName = String(className);
|
|
147
|
-
const existing = this.aliases.get(normalizedAlias);
|
|
148
|
-
|
|
149
|
-
if (existing && existing !== normalizedClassName)
|
|
150
|
-
{
|
|
151
|
-
this.reports.push({
|
|
152
|
-
level: "warning",
|
|
153
|
-
code: "alias-clash",
|
|
154
|
-
alias: normalizedAlias,
|
|
155
|
-
existingClassName: existing,
|
|
156
|
-
className: normalizedClassName,
|
|
157
|
-
message: `Alias ${normalizedAlias} already points to ${existing}`
|
|
158
|
-
});
|
|
159
|
-
return this;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (this.entries.has(normalizedAlias) && normalizedAlias !== normalizedClassName)
|
|
163
|
-
{
|
|
164
|
-
this.reports.push({
|
|
165
|
-
level: "warning",
|
|
166
|
-
code: "alias-class-clash",
|
|
167
|
-
alias: normalizedAlias,
|
|
168
|
-
className: normalizedClassName,
|
|
169
|
-
message: `Alias ${normalizedAlias} also names a registered class`
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
this.aliases.set(normalizedAlias, normalizedClassName);
|
|
174
|
-
return this;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
ResolveName(name)
|
|
178
|
-
{
|
|
179
|
-
let current = String(name || "");
|
|
180
|
-
const seen = new Set();
|
|
181
|
-
|
|
182
|
-
while (this.aliases.has(current) && !seen.has(current))
|
|
183
|
-
{
|
|
184
|
-
seen.add(current);
|
|
185
|
-
current = this.aliases.get(current);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return current;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
GetEntry(name)
|
|
192
|
-
{
|
|
193
|
-
return this.entries.get(this.ResolveName(name)) || null;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
Has(name)
|
|
197
|
-
{
|
|
198
|
-
return Boolean(this.GetEntry(name));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
GetConstructor(name)
|
|
202
|
-
{
|
|
203
|
-
return this.GetEntry(name)?.constructor || null;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
ResolveClass(name)
|
|
207
|
-
{
|
|
208
|
-
return this.GetConstructor(name);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
GetSourceShape(name)
|
|
212
|
-
{
|
|
213
|
-
return this.GetEntry(name)?.sourceShape || null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
GetModulePath(name)
|
|
217
|
-
{
|
|
218
|
-
return this.GetEntry(name)?.modulePath || null;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
Create(name, values)
|
|
222
|
-
{
|
|
223
|
-
const ClassConstructor = this.GetConstructor(name);
|
|
224
|
-
return ClassConstructor ? new ClassConstructor(values) : null;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
GetReports()
|
|
228
|
-
{
|
|
229
|
-
return this.reports.map(report => ({ ...report }));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
ToJSON()
|
|
233
|
-
{
|
|
234
|
-
return {
|
|
235
|
-
name: this.name,
|
|
236
|
-
family: this.family,
|
|
237
|
-
metadata: { ...this.metadata },
|
|
238
|
-
entries: Array.from(this.entries.values()).map(entry => ({
|
|
239
|
-
className: entry.className,
|
|
240
|
-
family: entry.family,
|
|
241
|
-
folder: entry.folder,
|
|
242
|
-
modulePath: entry.modulePath,
|
|
243
|
-
aliases: [...entry.aliases],
|
|
244
|
-
hasConstructor: Boolean(entry.constructor),
|
|
245
|
-
hasSourceShape: Boolean(entry.sourceShape)
|
|
246
|
-
})),
|
|
247
|
-
aliases: Object.fromEntries(this.aliases),
|
|
248
|
-
reports: this.GetReports()
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
[Symbol.iterator]()
|
|
253
|
-
{
|
|
254
|
-
return this.entries.values();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
ReportEntryClashes(existing, incoming)
|
|
258
|
-
{
|
|
259
|
-
if (existing.constructor && incoming.constructor && existing.constructor !== incoming.constructor)
|
|
260
|
-
{
|
|
261
|
-
this.reports.push(createEntryClash("constructor-clash", existing, incoming));
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (existing.sourceShape && incoming.sourceShape && existing.sourceShape !== incoming.sourceShape)
|
|
265
|
-
{
|
|
266
|
-
this.reports.push(createEntryClash("source-shape-clash", existing, incoming));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (existing.modulePath && incoming.modulePath && existing.modulePath !== incoming.modulePath)
|
|
270
|
-
{
|
|
271
|
-
this.reports.push(createEntryClash("module-path-clash", existing, incoming));
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
static from(options = {})
|
|
276
|
-
{
|
|
277
|
-
return options instanceof CjsClassRegistry ? options : new CjsClassRegistry(options);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
static fromMaps(options = {})
|
|
281
|
-
{
|
|
282
|
-
return new CjsClassRegistry(options);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function normalizeRegistryEntry(entry, defaultFamily)
|
|
287
|
-
{
|
|
288
|
-
if (!entry || typeof entry !== "object")
|
|
289
|
-
{
|
|
290
|
-
throw new TypeError("Class registry entry must be an object");
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const entryConstructor = Object.hasOwn(entry, "constructor") ? entry.constructor : null;
|
|
294
|
-
const constructor = typeof entryConstructor === "function" ? entryConstructor : null;
|
|
295
|
-
const sourceShape = entry.sourceShape || null;
|
|
296
|
-
const className = String(entry.className || entry.name || sourceShape?.className || (constructor ? CjsSchema.getClassName(constructor) : null) || "");
|
|
297
|
-
|
|
298
|
-
if (!className)
|
|
299
|
-
{
|
|
300
|
-
throw new TypeError("Class registry entry is missing a className");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
className,
|
|
305
|
-
constructor,
|
|
306
|
-
sourceShape,
|
|
307
|
-
folder: String(entry.folder || ""),
|
|
308
|
-
modulePath: String(entry.modulePath || ""),
|
|
309
|
-
registryEntry: entry.registryEntry || null,
|
|
310
|
-
aliases: normalizeAliases(entry.aliases),
|
|
311
|
-
family: String(entry.family || sourceShape?.family || defaultFamily || ""),
|
|
312
|
-
metadata: { ...(entry.metadata || {}) }
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function mergeRegistryEntries(existing, incoming)
|
|
317
|
-
{
|
|
318
|
-
return {
|
|
319
|
-
className: existing.className,
|
|
320
|
-
constructor: existing.constructor || incoming.constructor,
|
|
321
|
-
sourceShape: existing.sourceShape || incoming.sourceShape,
|
|
322
|
-
folder: existing.folder || incoming.folder,
|
|
323
|
-
modulePath: existing.modulePath || incoming.modulePath,
|
|
324
|
-
registryEntry: existing.registryEntry || incoming.registryEntry,
|
|
325
|
-
aliases: Array.from(new Set([...existing.aliases, ...incoming.aliases])),
|
|
326
|
-
family: existing.family || incoming.family,
|
|
327
|
-
metadata: { ...existing.metadata, ...incoming.metadata }
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function normalizeAliases(aliases)
|
|
332
|
-
{
|
|
333
|
-
if (!aliases) return [];
|
|
334
|
-
if (Array.isArray(aliases)) return aliases.map(String).filter(Boolean);
|
|
335
|
-
return [String(aliases)].filter(Boolean);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function aliasesForClassName(className, aliases)
|
|
339
|
-
{
|
|
340
|
-
if (!aliases || Array.isArray(aliases)) return [];
|
|
341
|
-
|
|
342
|
-
const direct = aliases[className];
|
|
343
|
-
if (Array.isArray(direct)) return direct;
|
|
344
|
-
|
|
345
|
-
const matched = [];
|
|
346
|
-
for (const [alias, target] of Object.entries(aliases))
|
|
347
|
-
{
|
|
348
|
-
if (target === className) matched.push(alias);
|
|
349
|
-
}
|
|
350
|
-
return matched;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function createEntryClash(code, existing, incoming)
|
|
354
|
-
{
|
|
355
|
-
return {
|
|
356
|
-
level: "warning",
|
|
357
|
-
code,
|
|
358
|
-
className: existing.className,
|
|
359
|
-
message: `${existing.className} has conflicting registry metadata`,
|
|
360
|
-
existing: summarizeEntry(existing),
|
|
361
|
-
incoming: summarizeEntry(incoming)
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function summarizeEntry(entry)
|
|
366
|
-
{
|
|
367
|
-
return {
|
|
368
|
-
className: entry.className,
|
|
369
|
-
modulePath: entry.modulePath,
|
|
370
|
-
hasConstructor: Boolean(entry.constructor),
|
|
371
|
-
hasSourceShape: Boolean(entry.sourceShape)
|
|
372
|
-
};
|
|
373
|
-
}
|
|
1
|
+
import { CjsSchema } from "../schema/index.js";
|
|
2
|
+
|
|
3
|
+
/** Maps serialized Carbon class names to explicit runtime constructors. */
|
|
4
|
+
export class CjsClassRegistry
|
|
5
|
+
{
|
|
6
|
+
constructor(options = {})
|
|
7
|
+
{
|
|
8
|
+
const {
|
|
9
|
+
name = "registry",
|
|
10
|
+
family = "",
|
|
11
|
+
constructors = null,
|
|
12
|
+
sourceShapes = null,
|
|
13
|
+
modules = null,
|
|
14
|
+
entries = [],
|
|
15
|
+
aliases = null,
|
|
16
|
+
metadata = {}
|
|
17
|
+
} = options;
|
|
18
|
+
|
|
19
|
+
this.name = String(name || "registry");
|
|
20
|
+
this.family = String(family || "");
|
|
21
|
+
this.metadata = { ...metadata };
|
|
22
|
+
this.entries = new Map();
|
|
23
|
+
this.aliases = new Map();
|
|
24
|
+
this.reports = [];
|
|
25
|
+
|
|
26
|
+
if (constructors || sourceShapes || modules)
|
|
27
|
+
{
|
|
28
|
+
this.RegisterMaps({ constructors, sourceShapes, modules, aliases });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.RegisterMany(entries);
|
|
32
|
+
this.RegisterAliases(aliases);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get size()
|
|
36
|
+
{
|
|
37
|
+
return this.entries.size;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
RegisterMaps(options = {})
|
|
41
|
+
{
|
|
42
|
+
const {
|
|
43
|
+
constructors = {},
|
|
44
|
+
sourceShapes = {},
|
|
45
|
+
modules = {},
|
|
46
|
+
aliases = {}
|
|
47
|
+
} = options;
|
|
48
|
+
|
|
49
|
+
const names = new Set([
|
|
50
|
+
...Object.keys(constructors || {}).filter(name => typeof constructors[name] === "function"),
|
|
51
|
+
...Object.keys(sourceShapes || {}),
|
|
52
|
+
...Object.keys(modules || {})
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
for (const className of names)
|
|
56
|
+
{
|
|
57
|
+
const constructor = typeof constructors?.[className] === "function" ? constructors[className] : null;
|
|
58
|
+
const sourceShape = sourceShapes?.[className] || null;
|
|
59
|
+
const moduleEntry = modules?.[className] || null;
|
|
60
|
+
|
|
61
|
+
this.Register({
|
|
62
|
+
className,
|
|
63
|
+
constructor,
|
|
64
|
+
sourceShape,
|
|
65
|
+
folder: moduleEntry?.folder || "",
|
|
66
|
+
modulePath: moduleEntry?.modulePath || "",
|
|
67
|
+
registryEntry: moduleEntry,
|
|
68
|
+
aliases: aliasesForClassName(className, aliases),
|
|
69
|
+
family: sourceShape?.family || this.family
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
RegisterMany(entries = [])
|
|
77
|
+
{
|
|
78
|
+
const list = Array.isArray(entries) ? entries : Object.values(entries || {});
|
|
79
|
+
for (const entry of list)
|
|
80
|
+
{
|
|
81
|
+
this.Register(entry);
|
|
82
|
+
}
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Register(entry)
|
|
87
|
+
{
|
|
88
|
+
const normalized = normalizeRegistryEntry(entry, this.family);
|
|
89
|
+
const existing = this.entries.get(normalized.className);
|
|
90
|
+
|
|
91
|
+
if (existing)
|
|
92
|
+
{
|
|
93
|
+
this.entries.set(normalized.className, mergeRegistryEntries(existing, normalized));
|
|
94
|
+
this.ReportEntryClashes(existing, normalized);
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
{
|
|
98
|
+
this.entries.set(normalized.className, normalized);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const alias of normalized.aliases)
|
|
102
|
+
{
|
|
103
|
+
this.RegisterAlias(alias, normalized.className);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
RegisterAliases(aliases = null)
|
|
110
|
+
{
|
|
111
|
+
if (!aliases) return this;
|
|
112
|
+
|
|
113
|
+
if (Array.isArray(aliases))
|
|
114
|
+
{
|
|
115
|
+
for (const item of aliases)
|
|
116
|
+
{
|
|
117
|
+
if (Array.isArray(item)) this.RegisterAlias(item[0], item[1]);
|
|
118
|
+
else this.RegisterAlias(item.alias, item.className || item.target);
|
|
119
|
+
}
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const [key, value] of Object.entries(aliases))
|
|
124
|
+
{
|
|
125
|
+
if (Array.isArray(value))
|
|
126
|
+
{
|
|
127
|
+
for (const alias of value)
|
|
128
|
+
{
|
|
129
|
+
this.RegisterAlias(alias, key);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
{
|
|
134
|
+
this.RegisterAlias(key, value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
RegisterAlias(alias, className)
|
|
142
|
+
{
|
|
143
|
+
if (!alias || !className) return this;
|
|
144
|
+
|
|
145
|
+
const normalizedAlias = String(alias);
|
|
146
|
+
const normalizedClassName = String(className);
|
|
147
|
+
const existing = this.aliases.get(normalizedAlias);
|
|
148
|
+
|
|
149
|
+
if (existing && existing !== normalizedClassName)
|
|
150
|
+
{
|
|
151
|
+
this.reports.push({
|
|
152
|
+
level: "warning",
|
|
153
|
+
code: "alias-clash",
|
|
154
|
+
alias: normalizedAlias,
|
|
155
|
+
existingClassName: existing,
|
|
156
|
+
className: normalizedClassName,
|
|
157
|
+
message: `Alias ${normalizedAlias} already points to ${existing}`
|
|
158
|
+
});
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (this.entries.has(normalizedAlias) && normalizedAlias !== normalizedClassName)
|
|
163
|
+
{
|
|
164
|
+
this.reports.push({
|
|
165
|
+
level: "warning",
|
|
166
|
+
code: "alias-class-clash",
|
|
167
|
+
alias: normalizedAlias,
|
|
168
|
+
className: normalizedClassName,
|
|
169
|
+
message: `Alias ${normalizedAlias} also names a registered class`
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this.aliases.set(normalizedAlias, normalizedClassName);
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
ResolveName(name)
|
|
178
|
+
{
|
|
179
|
+
let current = String(name || "");
|
|
180
|
+
const seen = new Set();
|
|
181
|
+
|
|
182
|
+
while (this.aliases.has(current) && !seen.has(current))
|
|
183
|
+
{
|
|
184
|
+
seen.add(current);
|
|
185
|
+
current = this.aliases.get(current);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return current;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
GetEntry(name)
|
|
192
|
+
{
|
|
193
|
+
return this.entries.get(this.ResolveName(name)) || null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
Has(name)
|
|
197
|
+
{
|
|
198
|
+
return Boolean(this.GetEntry(name));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
GetConstructor(name)
|
|
202
|
+
{
|
|
203
|
+
return this.GetEntry(name)?.constructor || null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
ResolveClass(name)
|
|
207
|
+
{
|
|
208
|
+
return this.GetConstructor(name);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
GetSourceShape(name)
|
|
212
|
+
{
|
|
213
|
+
return this.GetEntry(name)?.sourceShape || null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
GetModulePath(name)
|
|
217
|
+
{
|
|
218
|
+
return this.GetEntry(name)?.modulePath || null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Create(name, values)
|
|
222
|
+
{
|
|
223
|
+
const ClassConstructor = this.GetConstructor(name);
|
|
224
|
+
return ClassConstructor ? new ClassConstructor(values) : null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
GetReports()
|
|
228
|
+
{
|
|
229
|
+
return this.reports.map(report => ({ ...report }));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
ToJSON()
|
|
233
|
+
{
|
|
234
|
+
return {
|
|
235
|
+
name: this.name,
|
|
236
|
+
family: this.family,
|
|
237
|
+
metadata: { ...this.metadata },
|
|
238
|
+
entries: Array.from(this.entries.values()).map(entry => ({
|
|
239
|
+
className: entry.className,
|
|
240
|
+
family: entry.family,
|
|
241
|
+
folder: entry.folder,
|
|
242
|
+
modulePath: entry.modulePath,
|
|
243
|
+
aliases: [...entry.aliases],
|
|
244
|
+
hasConstructor: Boolean(entry.constructor),
|
|
245
|
+
hasSourceShape: Boolean(entry.sourceShape)
|
|
246
|
+
})),
|
|
247
|
+
aliases: Object.fromEntries(this.aliases),
|
|
248
|
+
reports: this.GetReports()
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
[Symbol.iterator]()
|
|
253
|
+
{
|
|
254
|
+
return this.entries.values();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
ReportEntryClashes(existing, incoming)
|
|
258
|
+
{
|
|
259
|
+
if (existing.constructor && incoming.constructor && existing.constructor !== incoming.constructor)
|
|
260
|
+
{
|
|
261
|
+
this.reports.push(createEntryClash("constructor-clash", existing, incoming));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (existing.sourceShape && incoming.sourceShape && existing.sourceShape !== incoming.sourceShape)
|
|
265
|
+
{
|
|
266
|
+
this.reports.push(createEntryClash("source-shape-clash", existing, incoming));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (existing.modulePath && incoming.modulePath && existing.modulePath !== incoming.modulePath)
|
|
270
|
+
{
|
|
271
|
+
this.reports.push(createEntryClash("module-path-clash", existing, incoming));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static from(options = {})
|
|
276
|
+
{
|
|
277
|
+
return options instanceof CjsClassRegistry ? options : new CjsClassRegistry(options);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static fromMaps(options = {})
|
|
281
|
+
{
|
|
282
|
+
return new CjsClassRegistry(options);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function normalizeRegistryEntry(entry, defaultFamily)
|
|
287
|
+
{
|
|
288
|
+
if (!entry || typeof entry !== "object")
|
|
289
|
+
{
|
|
290
|
+
throw new TypeError("Class registry entry must be an object");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const entryConstructor = Object.hasOwn(entry, "constructor") ? entry.constructor : null;
|
|
294
|
+
const constructor = typeof entryConstructor === "function" ? entryConstructor : null;
|
|
295
|
+
const sourceShape = entry.sourceShape || null;
|
|
296
|
+
const className = String(entry.className || entry.name || sourceShape?.className || (constructor ? CjsSchema.getClassName(constructor) : null) || "");
|
|
297
|
+
|
|
298
|
+
if (!className)
|
|
299
|
+
{
|
|
300
|
+
throw new TypeError("Class registry entry is missing a className");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
className,
|
|
305
|
+
constructor,
|
|
306
|
+
sourceShape,
|
|
307
|
+
folder: String(entry.folder || ""),
|
|
308
|
+
modulePath: String(entry.modulePath || ""),
|
|
309
|
+
registryEntry: entry.registryEntry || null,
|
|
310
|
+
aliases: normalizeAliases(entry.aliases),
|
|
311
|
+
family: String(entry.family || sourceShape?.family || defaultFamily || ""),
|
|
312
|
+
metadata: { ...(entry.metadata || {}) }
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function mergeRegistryEntries(existing, incoming)
|
|
317
|
+
{
|
|
318
|
+
return {
|
|
319
|
+
className: existing.className,
|
|
320
|
+
constructor: existing.constructor || incoming.constructor,
|
|
321
|
+
sourceShape: existing.sourceShape || incoming.sourceShape,
|
|
322
|
+
folder: existing.folder || incoming.folder,
|
|
323
|
+
modulePath: existing.modulePath || incoming.modulePath,
|
|
324
|
+
registryEntry: existing.registryEntry || incoming.registryEntry,
|
|
325
|
+
aliases: Array.from(new Set([...existing.aliases, ...incoming.aliases])),
|
|
326
|
+
family: existing.family || incoming.family,
|
|
327
|
+
metadata: { ...existing.metadata, ...incoming.metadata }
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function normalizeAliases(aliases)
|
|
332
|
+
{
|
|
333
|
+
if (!aliases) return [];
|
|
334
|
+
if (Array.isArray(aliases)) return aliases.map(String).filter(Boolean);
|
|
335
|
+
return [String(aliases)].filter(Boolean);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function aliasesForClassName(className, aliases)
|
|
339
|
+
{
|
|
340
|
+
if (!aliases || Array.isArray(aliases)) return [];
|
|
341
|
+
|
|
342
|
+
const direct = aliases[className];
|
|
343
|
+
if (Array.isArray(direct)) return direct;
|
|
344
|
+
|
|
345
|
+
const matched = [];
|
|
346
|
+
for (const [alias, target] of Object.entries(aliases))
|
|
347
|
+
{
|
|
348
|
+
if (target === className) matched.push(alias);
|
|
349
|
+
}
|
|
350
|
+
return matched;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function createEntryClash(code, existing, incoming)
|
|
354
|
+
{
|
|
355
|
+
return {
|
|
356
|
+
level: "warning",
|
|
357
|
+
code,
|
|
358
|
+
className: existing.className,
|
|
359
|
+
message: `${existing.className} has conflicting registry metadata`,
|
|
360
|
+
existing: summarizeEntry(existing),
|
|
361
|
+
incoming: summarizeEntry(incoming)
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function summarizeEntry(entry)
|
|
366
|
+
{
|
|
367
|
+
return {
|
|
368
|
+
className: entry.className,
|
|
369
|
+
modulePath: entry.modulePath,
|
|
370
|
+
hasConstructor: Boolean(entry.constructor),
|
|
371
|
+
hasSourceShape: Boolean(entry.sourceShape)
|
|
372
|
+
};
|
|
373
|
+
}
|