@player-tools/xlr-sdk 0.0.2-next.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.
@@ -0,0 +1,480 @@
1
+ import { isPrimitiveTypeNode, resolveConditional, makePropertyMap, isGenericNodeType, fillInGenerics } from '@player-tools/xlr-utils';
2
+ import { TSWriter } from '@player-tools/xlr-converters';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import ts from 'typescript';
6
+
7
+ var __defProp$1 = Object.defineProperty;
8
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
9
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues$1 = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp$1.call(b, prop))
15
+ __defNormalProp$1(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols$1)
17
+ for (var prop of __getOwnPropSymbols$1(b)) {
18
+ if (__propIsEnum$1.call(b, prop))
19
+ __defNormalProp$1(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ class BasicXLRRegistry {
24
+ constructor() {
25
+ this.typeMap = new Map();
26
+ this.pluginMap = new Map();
27
+ this.infoMap = new Map();
28
+ }
29
+ get(id) {
30
+ const value = this.typeMap.get(id);
31
+ return value ? __spreadValues$1({}, value) : void 0;
32
+ }
33
+ add(type, plugin, capability) {
34
+ this.typeMap.set(type.name, type);
35
+ this.infoMap.set(type.name, { plugin, capability });
36
+ if (!this.pluginMap.has(plugin)) {
37
+ this.pluginMap.set(plugin, new Map());
38
+ }
39
+ const pluginsCapabilities = this.pluginMap.get(plugin);
40
+ if (!pluginsCapabilities.has(capability)) {
41
+ pluginsCapabilities.set(capability, []);
42
+ }
43
+ const providedCapabilities = pluginsCapabilities.get(capability);
44
+ providedCapabilities.push(type.name);
45
+ }
46
+ has(id) {
47
+ return this.typeMap.has(id);
48
+ }
49
+ list(filterArgs) {
50
+ const validTypes = [];
51
+ this.pluginMap.forEach((manifest, pluginName) => {
52
+ if (!(filterArgs == null ? void 0 : filterArgs.pluginFilter) || !pluginName.match(filterArgs.pluginFilter)) {
53
+ manifest.forEach((types, capabilityName) => {
54
+ if (!(filterArgs == null ? void 0 : filterArgs.capabilityFilter) || !capabilityName.match(filterArgs.capabilityFilter)) {
55
+ types.forEach((type) => {
56
+ if (!(filterArgs == null ? void 0 : filterArgs.typeFilter) || !type.match(filterArgs.typeFilter)) {
57
+ validTypes.push(type);
58
+ }
59
+ });
60
+ }
61
+ });
62
+ }
63
+ });
64
+ return validTypes.map((type) => this.get(type));
65
+ }
66
+ info(id) {
67
+ return this.infoMap.get(id);
68
+ }
69
+ }
70
+
71
+ var __defProp = Object.defineProperty;
72
+ var __defProps = Object.defineProperties;
73
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
74
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
75
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
76
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
77
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
78
+ var __spreadValues = (a, b) => {
79
+ for (var prop in b || (b = {}))
80
+ if (__hasOwnProp.call(b, prop))
81
+ __defNormalProp(a, prop, b[prop]);
82
+ if (__getOwnPropSymbols)
83
+ for (var prop of __getOwnPropSymbols(b)) {
84
+ if (__propIsEnum.call(b, prop))
85
+ __defNormalProp(a, prop, b[prop]);
86
+ }
87
+ return a;
88
+ };
89
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
90
+ class XLRValidator {
91
+ constructor(typeMap) {
92
+ this.typeMap = typeMap;
93
+ this.regexCache = new Map();
94
+ }
95
+ validateType(rootNode, xlrNode) {
96
+ var _a;
97
+ const validationIssues = new Array();
98
+ if (xlrNode.type === "object") {
99
+ if (rootNode.type === "object") {
100
+ validationIssues.push(...this.validateObject(xlrNode, rootNode));
101
+ } else {
102
+ validationIssues.push({
103
+ type: "type",
104
+ node: rootNode,
105
+ message: `Expected an object but got an '${rootNode.type}'`
106
+ });
107
+ }
108
+ } else if (xlrNode.type === "array") {
109
+ if (rootNode.type === "array") {
110
+ validationIssues.push(...this.validateArray(rootNode, xlrNode));
111
+ } else {
112
+ validationIssues.push({
113
+ type: "type",
114
+ node: rootNode,
115
+ message: `Expected an array but got an '${rootNode.type}'`
116
+ });
117
+ }
118
+ } else if (xlrNode.type === "template") {
119
+ this.validateTemplate(rootNode, xlrNode);
120
+ } else if (xlrNode.type === "or") {
121
+ for (const potentialType of xlrNode.or) {
122
+ const potentialErrors = this.validateType(rootNode, potentialType);
123
+ if (potentialErrors.length === 0) {
124
+ return validationIssues;
125
+ }
126
+ }
127
+ validationIssues.push({
128
+ type: "value",
129
+ node: rootNode,
130
+ message: `Does not match any of the expected types for type: '${xlrNode.name}'`
131
+ });
132
+ } else if (xlrNode.type === "and") {
133
+ const effectiveType = this.computeIntersectionType(xlrNode.and);
134
+ validationIssues.push(...this.validateType(rootNode, effectiveType));
135
+ } else if (xlrNode.type === "record") {
136
+ (_a = rootNode.children) == null ? void 0 : _a.forEach((child) => {
137
+ var _a2, _b;
138
+ validationIssues.push(...this.validateType((_a2 = child.children) == null ? void 0 : _a2[0], xlrNode.keyType));
139
+ validationIssues.push(...this.validateType((_b = child.children) == null ? void 0 : _b[1], xlrNode.valueType));
140
+ });
141
+ } else if (xlrNode.type === "ref") {
142
+ const refType = this.getRefType(xlrNode);
143
+ if (refType === void 0) {
144
+ validationIssues.push({
145
+ type: "unknown",
146
+ node: rootNode,
147
+ message: `Type '${xlrNode.ref}' is not defined in provided bundles`
148
+ });
149
+ } else {
150
+ validationIssues.push(...this.validateType(rootNode, refType));
151
+ }
152
+ } else if (isPrimitiveTypeNode(xlrNode)) {
153
+ if (!this.validateLiteralType(xlrNode, rootNode)) {
154
+ if ((xlrNode.type === "string" || xlrNode.type === "number" || xlrNode.type === "boolean") && xlrNode.const) {
155
+ validationIssues.push({
156
+ type: "type",
157
+ node: rootNode.parent,
158
+ message: `Expected '${xlrNode.const}' but got '${rootNode.value}'`
159
+ });
160
+ } else {
161
+ validationIssues.push({
162
+ type: "type",
163
+ node: rootNode.parent,
164
+ message: `Expected type '${xlrNode.type}' but got '${rootNode.type}'`
165
+ });
166
+ }
167
+ }
168
+ } else if (xlrNode.type === "conditional") {
169
+ const resolvedType = resolveConditional(xlrNode);
170
+ if (resolvedType === xlrNode) {
171
+ throw Error(`Unable to resolve conditional type at runtime: ${xlrNode.name}`);
172
+ }
173
+ validationIssues.push(...this.validateType(rootNode, resolvedType));
174
+ } else {
175
+ throw Error(`Unknown type ${xlrNode.type}`);
176
+ }
177
+ return validationIssues;
178
+ }
179
+ validateTemplate(node, xlrNode) {
180
+ if (node.type !== "string") {
181
+ return {
182
+ type: "type",
183
+ node: node.parent,
184
+ message: `Expected type '${xlrNode.type}' but got '${typeof node}'`
185
+ };
186
+ }
187
+ const regex = this.getRegex(xlrNode.format);
188
+ const valid = regex.exec(node.value);
189
+ if (!valid) {
190
+ return {
191
+ type: "value",
192
+ node: node.parent,
193
+ message: `Does not match expected format: ${xlrNode.format}`
194
+ };
195
+ }
196
+ }
197
+ validateArray(rootNode, xlrNode) {
198
+ var _a;
199
+ const issues = [];
200
+ (_a = rootNode.children) == null ? void 0 : _a.forEach((child) => issues.push(...this.validateType(child, xlrNode.elementType)));
201
+ return issues;
202
+ }
203
+ validateObject(xlrNode, node) {
204
+ const issues = [];
205
+ const objectProps = makePropertyMap(node);
206
+ for (const prop in xlrNode.properties) {
207
+ const expectedType = xlrNode.properties[prop];
208
+ const valueNode = objectProps.get(prop);
209
+ if (expectedType.required && valueNode === void 0) {
210
+ issues.push({
211
+ type: "missing",
212
+ node,
213
+ message: `Property '${prop}' missing from type '${xlrNode.name}'`
214
+ });
215
+ }
216
+ if (valueNode) {
217
+ issues.push(...this.validateType(valueNode, expectedType.node));
218
+ }
219
+ }
220
+ const extraKeys = Array.from(objectProps.keys()).filter((key) => xlrNode.properties[key] === void 0);
221
+ if (xlrNode.additionalProperties === false && extraKeys.length > 0) {
222
+ issues.push({
223
+ type: "value",
224
+ node,
225
+ message: `Unexpected properties on '${xlrNode.name}': ${extraKeys.join(", ")}`
226
+ });
227
+ } else {
228
+ issues.push(...extraKeys.flatMap((key) => this.validateType(objectProps.get(key), xlrNode.additionalProperties)));
229
+ }
230
+ return issues;
231
+ }
232
+ validateLiteralType(expectedType, literalType) {
233
+ switch (expectedType.type) {
234
+ case "boolean":
235
+ if (expectedType.const) {
236
+ return expectedType.const === literalType.value;
237
+ }
238
+ return typeof literalType.value === "boolean";
239
+ case "number":
240
+ if (expectedType.const) {
241
+ return expectedType.const === literalType.value;
242
+ }
243
+ return typeof literalType.value === "number";
244
+ case "string":
245
+ if (expectedType.const) {
246
+ return expectedType.const === literalType.value;
247
+ }
248
+ return typeof literalType.value === "string";
249
+ case "null":
250
+ return literalType.value === "null";
251
+ case "never":
252
+ return literalType === void 0;
253
+ case "any":
254
+ return literalType !== void 0;
255
+ case "unknown":
256
+ return literalType !== void 0;
257
+ case "undefined":
258
+ return true;
259
+ default:
260
+ return false;
261
+ }
262
+ }
263
+ getRefType(ref) {
264
+ let refName = ref.ref;
265
+ const { genericArguments } = ref;
266
+ if (refName.indexOf("<") > 0) {
267
+ [refName] = refName.split("<");
268
+ }
269
+ const actualType = this.typeMap.get(refName);
270
+ const genericMap = new Map();
271
+ if (genericArguments && isGenericNodeType(actualType)) {
272
+ actualType.genericTokens.forEach((token, index) => {
273
+ var _a, _b;
274
+ genericMap.set(token.symbol, (_b = (_a = genericArguments[index]) != null ? _a : token.default) != null ? _b : token.constraints);
275
+ });
276
+ }
277
+ return fillInGenerics(actualType, genericMap);
278
+ }
279
+ getRegex(expString) {
280
+ if (this.regexCache.has(expString)) {
281
+ return this.regexCache.get(expString);
282
+ }
283
+ const exp = new RegExp(expString);
284
+ this.regexCache.set(expString, exp);
285
+ return exp;
286
+ }
287
+ computeIntersectionType(types) {
288
+ let firstElement = types[0];
289
+ let effectiveType;
290
+ if (firstElement.type === "ref") {
291
+ firstElement = this.getRefType(firstElement);
292
+ }
293
+ if (firstElement.type === "and") {
294
+ effectiveType = this.computeIntersectionType(firstElement.and);
295
+ } else if (firstElement.type !== "or" && firstElement.type !== "object") {
296
+ throw new Error(`Can't compute a union with a non-object type ${firstElement.type} (${firstElement.name})`);
297
+ } else {
298
+ effectiveType = firstElement;
299
+ }
300
+ types.slice(1).forEach((type) => {
301
+ let typeToApply = type;
302
+ if (type.type === "ref") {
303
+ typeToApply = this.getRefType(type);
304
+ }
305
+ if (typeToApply.type === "and") {
306
+ typeToApply = this.computeIntersectionType([type, effectiveType]);
307
+ }
308
+ if (typeToApply.type === "object") {
309
+ if (effectiveType.type === "object") {
310
+ effectiveType = this.computeEffectiveObject(effectiveType, typeToApply);
311
+ } else {
312
+ effectiveType = __spreadProps(__spreadValues({}, effectiveType), {
313
+ or: effectiveType.or.map((y) => this.computeIntersectionType([y, typeToApply]))
314
+ });
315
+ }
316
+ } else if (typeToApply.type === "or") {
317
+ if (effectiveType.type === "object") {
318
+ effectiveType = __spreadProps(__spreadValues({}, typeToApply), {
319
+ or: typeToApply.or.map((y) => this.computeIntersectionType([y, effectiveType]))
320
+ });
321
+ } else {
322
+ throw new Error("unimplemented operation or x or projection");
323
+ }
324
+ } else {
325
+ throw new Error(`Can't compute a union with a non-object type ${typeToApply.type} (${typeToApply.name})`);
326
+ }
327
+ });
328
+ return effectiveType;
329
+ }
330
+ computeEffectiveObject(base, operand, errorOnOverlap = true) {
331
+ var _a, _b;
332
+ const newObject = __spreadProps(__spreadValues({}, base), {
333
+ name: `${base.name} & ${operand.name}`,
334
+ description: `Effective type combining ${base.name} and ${operand.name}`
335
+ });
336
+ for (const property in operand.properties) {
337
+ if (newObject.properties[property] !== void 0 && newObject.properties[property].node.type !== operand.properties[property].node.type && errorOnOverlap) {
338
+ throw new Error(`Can't compute effective type for ${(_a = base.name) != null ? _a : "object literal"} and ${(_b = operand.name) != null ? _b : "object literal"} because of conflicting properties ${property}`);
339
+ }
340
+ newObject.properties[property] = operand.properties[property];
341
+ }
342
+ if (newObject.additionalProperties && operand.additionalProperties) {
343
+ newObject.additionalProperties = {
344
+ type: "and",
345
+ and: [newObject.additionalProperties, operand.additionalProperties]
346
+ };
347
+ } else if (operand.additionalProperties) {
348
+ newObject.additionalProperties = operand.additionalProperties;
349
+ }
350
+ return newObject;
351
+ }
352
+ }
353
+
354
+ var __async = (__this, __arguments, generator) => {
355
+ return new Promise((resolve, reject) => {
356
+ var fulfilled = (value) => {
357
+ try {
358
+ step(generator.next(value));
359
+ } catch (e) {
360
+ reject(e);
361
+ }
362
+ };
363
+ var rejected = (value) => {
364
+ try {
365
+ step(generator.throw(value));
366
+ } catch (e) {
367
+ reject(e);
368
+ }
369
+ };
370
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
371
+ step((generator = generator.apply(__this, __arguments)).next());
372
+ });
373
+ };
374
+ class XLRSDK {
375
+ constructor(customRegistry) {
376
+ this.registry = customRegistry != null ? customRegistry : new BasicXLRRegistry();
377
+ this.validator = new XLRValidator(this.registry);
378
+ this.tsWriter = new TSWriter();
379
+ }
380
+ loadDefinitionsFromDisk(inputPath, filters, transforms) {
381
+ var _a;
382
+ const manifest = JSON.parse(fs.readFileSync(path.join(inputPath, "xlr", "manifest.json")).toString(), (key, value) => {
383
+ if (typeof value === "object" && value !== null) {
384
+ if (key === "capabilities") {
385
+ return new Map(Object.entries(value));
386
+ }
387
+ }
388
+ return value;
389
+ });
390
+ (_a = manifest.capabilities) == null ? void 0 : _a.forEach((capabilityList, capabilityName) => {
391
+ if ((filters == null ? void 0 : filters.capabilityFilter) && capabilityName.match(filters == null ? void 0 : filters.capabilityFilter))
392
+ return;
393
+ capabilityList.forEach((extensionName) => {
394
+ if (!(filters == null ? void 0 : filters.typeFilter) || !extensionName.match(filters == null ? void 0 : filters.typeFilter)) {
395
+ const cType = JSON.parse(fs.readFileSync(path.join(inputPath, "xlr", `${extensionName}.json`)).toString());
396
+ transforms == null ? void 0 : transforms.forEach((transform) => transform(cType, capabilityName));
397
+ const resolvedType = fillInGenerics(cType);
398
+ this.registry.add(resolvedType, manifest.pluginName, capabilityName);
399
+ }
400
+ });
401
+ });
402
+ }
403
+ loadDefinitionsFromModule(inputPath, filters, transforms) {
404
+ return __async(this, null, function* () {
405
+ var _a;
406
+ const importManifest = yield import(path.join(inputPath, "xlr", "manifest.js"));
407
+ const manifest = importManifest.default;
408
+ (_a = Object.keys(manifest.capabilities)) == null ? void 0 : _a.forEach((capabilityName) => {
409
+ if ((filters == null ? void 0 : filters.capabilityFilter) && capabilityName.match(filters == null ? void 0 : filters.capabilityFilter))
410
+ return;
411
+ const capabilityList = manifest.capabilities[capabilityName];
412
+ capabilityList.forEach((extension) => {
413
+ if (!(filters == null ? void 0 : filters.typeFilter) || !extension.name.match(filters == null ? void 0 : filters.typeFilter)) {
414
+ transforms == null ? void 0 : transforms.forEach((transform) => transform(extension, extension.name));
415
+ const resolvedType = fillInGenerics(extension);
416
+ this.registry.add(resolvedType, manifest.pluginName, extension.name);
417
+ }
418
+ });
419
+ });
420
+ });
421
+ }
422
+ getType(id) {
423
+ return this.registry.get(id);
424
+ }
425
+ hasType(id) {
426
+ return this.registry.has(id);
427
+ }
428
+ listTypes(filters) {
429
+ return this.registry.list(filters);
430
+ }
431
+ validate(typeName, rootNode) {
432
+ const xlr = this.registry.get(typeName);
433
+ if (!xlr) {
434
+ throw new Error(`Type ${typeName} does not exist in registry, can't validate`);
435
+ }
436
+ return this.validator.validateType(rootNode, xlr);
437
+ }
438
+ exportRegistry(exportType, importMap, filters, transforms) {
439
+ const typesToExport = this.registry.list(filters).map((type) => {
440
+ transforms == null ? void 0 : transforms.forEach((transformFunction) => {
441
+ var _a;
442
+ return transformFunction(type, (_a = this.registry.info(type.name)) == null ? void 0 : _a.capability);
443
+ });
444
+ return type;
445
+ });
446
+ if (exportType === "TypeScript") {
447
+ const outputString = this.exportToTypeScript(typesToExport, importMap);
448
+ return [["out.d.ts", outputString]];
449
+ }
450
+ throw new Error(`Unknown export format ${exportType}`);
451
+ }
452
+ exportToTypeScript(typesToExport, importMap) {
453
+ const referencedImports = new Set();
454
+ const exportedTypes = new Map();
455
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
456
+ let resultFile = ts.createSourceFile("output.d.ts", "", ts.ScriptTarget.ES2017, false, ts.ScriptKind.TS);
457
+ typesToExport.forEach((typeNode) => {
458
+ const { type, referencedTypes, additionalTypes } = this.tsWriter.convertNamedType(typeNode);
459
+ exportedTypes.set(typeNode.name, type);
460
+ additionalTypes == null ? void 0 : additionalTypes.forEach((additionalType, name) => exportedTypes.set(name, additionalType));
461
+ referencedTypes == null ? void 0 : referencedTypes.forEach((referencedType) => referencedImports.add(referencedType));
462
+ });
463
+ const typesToPrint = [];
464
+ exportedTypes.forEach((type) => typesToPrint.push(printer.printNode(ts.EmitHint.Unspecified, type, resultFile)));
465
+ importMap.forEach((imports, packageName) => {
466
+ const applicableImports = imports.filter((i) => referencedImports.has(i));
467
+ resultFile = ts.factory.updateSourceFile(resultFile, [
468
+ ts.factory.createImportDeclaration(void 0, void 0, ts.factory.createImportClause(false, void 0, ts.factory.createNamedImports(applicableImports.map((i) => ts.factory.createImportSpecifier(void 0, ts.factory.createIdentifier(i))))), ts.factory.createStringLiteral(packageName)),
469
+ ...resultFile.statements
470
+ ]);
471
+ });
472
+ const headerText = printer.printFile(resultFile);
473
+ const nodeText = typesToPrint.join("\n");
474
+ return `${headerText}
475
+ ${nodeText}`;
476
+ }
477
+ }
478
+
479
+ export { BasicXLRRegistry, XLRSDK };
480
+ //# sourceMappingURL=index.esm.js.map
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@player-tools/xlr-sdk",
3
+ "version": "0.0.2-next.0",
4
+ "private": false,
5
+ "publishConfig": {
6
+ "registry": "https://registry.npmjs.org"
7
+ },
8
+ "peerDependencies": {
9
+ "typescript": "4.4.4"
10
+ },
11
+ "dependencies": {
12
+ "@player-tools/xlr": "0.0.2-next.0",
13
+ "@player-tools/xlr-utils": "0.0.2-next.0",
14
+ "@player-tools/xlr-converters": "0.0.2-next.0",
15
+ "jsonc-parser": "^2.3.1",
16
+ "@types/node": "^16.11.12",
17
+ "@types/fs-extra": "^9.0.13",
18
+ "fs-extra": "^10.0.0",
19
+ "@babel/runtime": "7.15.4"
20
+ },
21
+ "main": "dist/index.cjs.js",
22
+ "module": "dist/index.esm.js",
23
+ "typings": "dist/index.d.ts",
24
+ "sideEffects": false,
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/player-ui/tools"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/player-ui/tools/issues"
32
+ },
33
+ "homepage": "https://player-ui.github.io",
34
+ "contributors": [
35
+ {
36
+ "name": "Ketan Reddy",
37
+ "url": "https://github.com/KetanReddy"
38
+ }
39
+ ]
40
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './sdk';
2
+ export * from './types';
3
+ export * from './registry';
@@ -0,0 +1,83 @@
1
+ import type { NamedType, NodeType } from '@player-tools/xlr';
2
+ import type { XLRRegistry, Filters, TypeMetadata } from './types';
3
+
4
+ /**
5
+ * Basic example of a XLRs Registry
6
+ */
7
+ export class BasicXLRRegistry implements XLRRegistry {
8
+ private typeMap: Map<string, NamedType<NodeType>>;
9
+ private pluginMap: Map<string, Map<string, Array<string>>>;
10
+ private infoMap: Map<string, TypeMetadata>;
11
+
12
+ constructor() {
13
+ this.typeMap = new Map();
14
+ this.pluginMap = new Map();
15
+ this.infoMap = new Map();
16
+ }
17
+
18
+ /** Returns a copy of the XLR to guard against unexpected type modification */
19
+ get(id: string): NamedType<NodeType> | undefined {
20
+ const value = this.typeMap.get(id);
21
+ return value ? { ...value } : undefined;
22
+ }
23
+
24
+ add(type: NamedType<NodeType>, plugin: string, capability: string): void {
25
+ this.typeMap.set(type.name, type);
26
+ this.infoMap.set(type.name, { plugin, capability });
27
+
28
+ if (!this.pluginMap.has(plugin)) {
29
+ this.pluginMap.set(plugin, new Map());
30
+ }
31
+
32
+ const pluginsCapabilities = this.pluginMap.get(plugin) as Map<
33
+ string,
34
+ Array<string>
35
+ >;
36
+
37
+ if (!pluginsCapabilities.has(capability)) {
38
+ pluginsCapabilities.set(capability, []);
39
+ }
40
+
41
+ const providedCapabilities = pluginsCapabilities.get(
42
+ capability
43
+ ) as string[];
44
+ providedCapabilities.push(type.name);
45
+ }
46
+
47
+ has(id: string): boolean {
48
+ return this.typeMap.has(id);
49
+ }
50
+
51
+ list(filterArgs?: Filters): NamedType<NodeType>[] {
52
+ const validTypes: Array<string> = [];
53
+
54
+ this.pluginMap.forEach((manifest, pluginName) => {
55
+ if (
56
+ !filterArgs?.pluginFilter ||
57
+ !pluginName.match(filterArgs.pluginFilter)
58
+ ) {
59
+ manifest.forEach((types, capabilityName) => {
60
+ if (
61
+ !filterArgs?.capabilityFilter ||
62
+ !capabilityName.match(filterArgs.capabilityFilter)
63
+ ) {
64
+ types.forEach((type) => {
65
+ if (
66
+ !filterArgs?.typeFilter ||
67
+ !type.match(filterArgs.typeFilter)
68
+ ) {
69
+ validTypes.push(type);
70
+ }
71
+ });
72
+ }
73
+ });
74
+ }
75
+ });
76
+
77
+ return validTypes.map((type) => this.get(type) as NamedType);
78
+ }
79
+
80
+ info(id: string): TypeMetadata | undefined {
81
+ return this.infoMap.get(id);
82
+ }
83
+ }
@@ -0,0 +1,2 @@
1
+ export * from './basic-registry';
2
+ export * from './types';
@@ -0,0 +1,28 @@
1
+ import type { NamedType } from '@player-tools/xlr';
2
+
3
+ export interface Filters {
4
+ /** filter based on plugin name */
5
+ pluginFilter?: string | RegExp;
6
+
7
+ /** filter based on capability name */
8
+ capabilityFilter?: string | RegExp;
9
+
10
+ /** filter based on type name */
11
+ typeFilter?: string | RegExp;
12
+ }
13
+
14
+ export interface TypeMetadata {
15
+ /** The Plugin the Type comes from */
16
+ plugin: string;
17
+
18
+ /** The Capability of the Type */
19
+ capability: string;
20
+ }
21
+
22
+ export interface XLRRegistry {
23
+ get(id: string): NamedType | undefined;
24
+ add(type: NamedType, from: string, capability: string): void;
25
+ has(id: string): boolean;
26
+ list(filterArgs?: Filters): Array<NamedType>;
27
+ info(id: string): TypeMetadata | undefined;
28
+ }