@player-tools/xlr-sdk 0.4.2--canary.69.1573 → 0.4.2-next.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.js CHANGED
@@ -14,22 +14,6 @@ var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
14
14
  var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
15
15
  var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
16
16
 
17
- var __defProp$3 = Object.defineProperty;
18
- var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
19
- var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
20
- var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
21
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
22
- var __spreadValues$3 = (a, b) => {
23
- for (var prop in b || (b = {}))
24
- if (__hasOwnProp$3.call(b, prop))
25
- __defNormalProp$3(a, prop, b[prop]);
26
- if (__getOwnPropSymbols$3)
27
- for (var prop of __getOwnPropSymbols$3(b)) {
28
- if (__propIsEnum$3.call(b, prop))
29
- __defNormalProp$3(a, prop, b[prop]);
30
- }
31
- return a;
32
- };
33
17
  class BasicXLRRegistry {
34
18
  constructor() {
35
19
  this.typeMap = new Map();
@@ -38,7 +22,7 @@ class BasicXLRRegistry {
38
22
  }
39
23
  get(id) {
40
24
  const value = this.typeMap.get(id);
41
- return value ? __spreadValues$3({}, value) : void 0;
25
+ return value ? JSON.parse(JSON.stringify(value)) : void 0;
42
26
  }
43
27
  add(type, plugin, capability) {
44
28
  this.typeMap.set(type.name, type);
@@ -137,10 +121,21 @@ class XLRValidator {
137
121
  return validationIssues;
138
122
  }
139
123
  }
124
+ let message;
125
+ if (xlrNode.name) {
126
+ message = `Does not match any of the expected types for type: '${xlrNode.name}'`;
127
+ } else if (xlrNode.title) {
128
+ message = `Does not match any of the expected types for property: '${xlrNode.title}'`;
129
+ } else {
130
+ message = `Does not match any of the types ${xlrNode.or.map((node) => {
131
+ var _a2, _b;
132
+ return (_b = (_a2 = node.name) != null ? _a2 : node.title) != null ? _b : "<unnamed type>";
133
+ }).join(" | ")}`;
134
+ }
140
135
  validationIssues.push({
141
136
  type: "value",
142
137
  node: rootNode,
143
- message: `Does not match any of the expected types for type: '${xlrNode.name}'`
138
+ message
144
139
  });
145
140
  } else if (xlrNode.type === "and") {
146
141
  const effectiveType = __spreadValues$2(__spreadValues$2({}, this.computeIntersectionType(xlrNode.and)), xlrNode.name ? { name: xlrNode.name } : {});
@@ -382,10 +377,16 @@ var __spreadValues$1 = (a, b) => {
382
377
  return a;
383
378
  };
384
379
  var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
380
+ const isMatchingCapability = (capability, capabilitiesToMatch) => {
381
+ if (Array.isArray(capabilitiesToMatch)) {
382
+ return capabilitiesToMatch.includes(capability);
383
+ }
384
+ return capability === capabilitiesToMatch;
385
+ };
385
386
  function simpleTransformGenerator(typeToTransform, capabilityToTransform, functionToRun) {
386
387
  const walker = (n, capability) => {
387
388
  var _a;
388
- if (capability === capabilityToTransform) {
389
+ if (isMatchingCapability(capability, capabilityToTransform)) {
389
390
  let node = __spreadValues$1({}, n);
390
391
  if (node.type === typeToTransform) {
391
392
  node = functionToRun(node);
@@ -399,8 +400,16 @@ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functi
399
400
  node: walker(value.node, capability)
400
401
  };
401
402
  }
402
- return __spreadProps$1(__spreadValues$1({}, node), {
403
- properties: __spreadValues$1({}, newObjectProperties),
403
+ return __spreadProps$1(__spreadValues$1(__spreadProps$1(__spreadValues$1({}, node), {
404
+ properties: __spreadValues$1({}, newObjectProperties)
405
+ }), xlrUtils.isGenericNamedType(node) ? {
406
+ genericTokens: node.genericTokens.map((token) => {
407
+ return __spreadProps$1(__spreadValues$1({}, token), {
408
+ constraints: token.constraints ? walker(token.constraints, capability) : void 0,
409
+ default: token.default ? walker(token.default, capability) : void 0
410
+ });
411
+ })
412
+ } : {}), {
404
413
  extends: node.extends ? walker(node.extends, capability) : void 0,
405
414
  additionalProperties: node.additionalProperties ? walker(node.additionalProperties, capability) : false
406
415
  });
@@ -421,9 +430,9 @@ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functi
421
430
  });
422
431
  }
423
432
  if (node.type === "ref") {
424
- return __spreadProps$1(__spreadValues$1({}, node), {
433
+ return __spreadValues$1(__spreadValues$1({}, node), node.genericArguments ? {
425
434
  genericArguments: (_a = node.genericArguments) == null ? void 0 : _a.map((arg) => walker(arg, capability))
426
- });
435
+ } : {});
427
436
  }
428
437
  if (node.type === "tuple") {
429
438
  return __spreadProps$1(__spreadValues$1({}, node), {
@@ -517,10 +526,15 @@ class XLRSDK {
517
526
  this.validator = new XLRValidator(this.getType.bind(this));
518
527
  this.tsWriter = new xlrConverters.TSWriter();
519
528
  this.computedNodeCache = new Map();
529
+ this.externalTransformFunctions = new Map();
520
530
  }
521
531
  loadDefinitionsFromDisk(inputPath, filters, transforms) {
522
532
  var _a;
523
533
  this.computedNodeCache.clear();
534
+ const transformsToRun = [
535
+ ...this.externalTransformFunctions.values(),
536
+ ...transforms != null ? transforms : []
537
+ ];
524
538
  const manifest = JSON.parse(fs__default["default"].readFileSync(path__default["default"].join(inputPath, "xlr", "manifest.json")).toString(), (key, value) => {
525
539
  if (typeof value === "object" && value !== null) {
526
540
  if (key === "capabilities") {
@@ -536,7 +550,7 @@ class XLRSDK {
536
550
  var _a2;
537
551
  if (!(filters == null ? void 0 : filters.typeFilter) || !extensionName.match(filters == null ? void 0 : filters.typeFilter)) {
538
552
  const cType = JSON.parse(fs__default["default"].readFileSync(path__default["default"].join(inputPath, "xlr", `${extensionName}.json`)).toString());
539
- const effectiveType = (_a2 = transforms == null ? void 0 : transforms.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), cType)) != null ? _a2 : cType;
553
+ const effectiveType = (_a2 = transformsToRun == null ? void 0 : transformsToRun.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), cType)) != null ? _a2 : cType;
540
554
  this.registry.add(effectiveType, manifest.pluginName, capabilityName);
541
555
  }
542
556
  });
@@ -546,6 +560,10 @@ class XLRSDK {
546
560
  return __async(this, null, function* () {
547
561
  var _a;
548
562
  this.computedNodeCache.clear();
563
+ const transformsToRun = [
564
+ ...this.externalTransformFunctions.values(),
565
+ ...transforms != null ? transforms : []
566
+ ];
549
567
  (_a = Object.keys(manifest.capabilities)) == null ? void 0 : _a.forEach((capabilityName) => {
550
568
  if ((filters == null ? void 0 : filters.capabilityFilter) && capabilityName.match(filters == null ? void 0 : filters.capabilityFilter))
551
569
  return;
@@ -553,20 +571,26 @@ class XLRSDK {
553
571
  capabilityList.forEach((extension) => {
554
572
  var _a2;
555
573
  if (!(filters == null ? void 0 : filters.typeFilter) || !extension.name.match(filters == null ? void 0 : filters.typeFilter)) {
556
- const effectiveType = (_a2 = transforms == null ? void 0 : transforms.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), extension)) != null ? _a2 : extension;
574
+ const effectiveType = (_a2 = transformsToRun == null ? void 0 : transformsToRun.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), extension)) != null ? _a2 : extension;
557
575
  this.registry.add(effectiveType, manifest.pluginName, capabilityName);
558
576
  }
559
577
  });
560
578
  });
561
579
  });
562
580
  }
581
+ addTransformFunction(name, fn) {
582
+ this.externalTransformFunctions.set(name, fn);
583
+ }
584
+ removeTransformFunction(name) {
585
+ this.externalTransformFunctions.delete(name);
586
+ }
563
587
  getType(id, options) {
564
588
  let type = this.registry.get(id);
565
589
  if ((options == null ? void 0 : options.getRawType) === true || !type) {
566
590
  return type;
567
591
  }
568
592
  if (this.computedNodeCache.has(id)) {
569
- return this.computedNodeCache.get(id);
593
+ return JSON.parse(JSON.stringify(this.computedNodeCache.get(id)));
570
594
  }
571
595
  type = xlrUtils.fillInGenerics(this.resolveType(type));
572
596
  this.computedNodeCache.set(id, type);
@@ -616,10 +640,22 @@ class XLRSDK {
616
640
  throw new Error(`Error resolving ${objectNode.name}: can't find extended type ${refName}`);
617
641
  }
618
642
  extendedType = xlrUtils.resolveReferenceNode(objectNode.extends, extendedType);
619
- return __spreadProps(__spreadValues({}, xlrUtils.computeEffectiveObject(extendedType, objectNode, false)), {
643
+ if (extendedType.type === "object") {
644
+ return __spreadProps(__spreadValues({}, xlrUtils.computeEffectiveObject(extendedType, objectNode, false)), {
645
+ name: objectNode.name,
646
+ description: objectNode.description
647
+ });
648
+ }
649
+ return {
620
650
  name: objectNode.name,
621
- description: objectNode.description
622
- });
651
+ type: "and",
652
+ and: [
653
+ __spreadProps(__spreadValues({}, objectNode), {
654
+ extends: void 0
655
+ }),
656
+ extendedType
657
+ ]
658
+ };
623
659
  }
624
660
  return objectNode;
625
661
  })(type, "any");
package/dist/index.d.ts CHANGED
@@ -62,6 +62,7 @@ declare class XLRSDK {
62
62
  private validator;
63
63
  private tsWriter;
64
64
  private computedNodeCache;
65
+ private externalTransformFunctions;
65
66
  constructor(customRegistry?: XLRRegistry);
66
67
  /**
67
68
  * Loads definitions from a path on the filesystem
@@ -79,6 +80,14 @@ declare class XLRSDK {
79
80
  * @param transforms - any transforms to apply to the types being loaded
80
81
  */
81
82
  loadDefinitionsFromModule(manifest: TSManifest, filters?: Omit<Filters, 'pluginFilter'>, transforms?: Array<TransformFunction>): Promise<void>;
83
+ /**
84
+ * Statically load transform function that should be applied to every XLR bundle that is imported
85
+ */
86
+ addTransformFunction(name: string, fn: TransformFunction): void;
87
+ /**
88
+ * Remove any transform function loaded via the `addTransformFunction` method by name
89
+ */
90
+ removeTransformFunction(name: string): void;
82
91
  /**
83
92
  * Returns a Type that has been previously loaded
84
93
  *
@@ -142,6 +151,6 @@ declare class XLRSDK {
142
151
  * Helper function for simple transforms
143
152
  * Walks an XLR tree looking for the specified node type calls the supplied function when called
144
153
  */
145
- declare function simpleTransformGenerator<T extends NodeTypeStrings = NodeTypeStrings>(typeToTransform: T, capabilityToTransform: string, functionToRun: (input: NodeTypeMap[T]) => NodeTypeMap[T]): TransformFunction;
154
+ declare function simpleTransformGenerator<T extends NodeTypeStrings = NodeTypeStrings>(typeToTransform: T, capabilityToTransform: string | Array<string>, functionToRun: (input: NodeTypeMap[T]) => NodeTypeMap[T]): TransformFunction;
146
155
 
147
156
  export { BasicXLRRegistry, ExportTypes, Filters, GetTypeOptions, TypeMetadata, ValidationError, XLRRegistry, XLRSDK, simpleTransformGenerator };
package/dist/index.esm.js CHANGED
@@ -1,25 +1,9 @@
1
- import { isPrimitiveTypeNode, resolveConditional, makePropertyMap, resolveReferenceNode, computeEffectiveObject, fillInGenerics } from '@player-tools/xlr-utils';
1
+ import { isPrimitiveTypeNode, resolveConditional, makePropertyMap, resolveReferenceNode, computeEffectiveObject, isGenericNamedType, fillInGenerics } from '@player-tools/xlr-utils';
2
2
  import { TSWriter } from '@player-tools/xlr-converters';
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
  import ts from 'typescript';
6
6
 
7
- var __defProp$3 = Object.defineProperty;
8
- var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
9
- var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
10
- var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
11
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
- var __spreadValues$3 = (a, b) => {
13
- for (var prop in b || (b = {}))
14
- if (__hasOwnProp$3.call(b, prop))
15
- __defNormalProp$3(a, prop, b[prop]);
16
- if (__getOwnPropSymbols$3)
17
- for (var prop of __getOwnPropSymbols$3(b)) {
18
- if (__propIsEnum$3.call(b, prop))
19
- __defNormalProp$3(a, prop, b[prop]);
20
- }
21
- return a;
22
- };
23
7
  class BasicXLRRegistry {
24
8
  constructor() {
25
9
  this.typeMap = new Map();
@@ -28,7 +12,7 @@ class BasicXLRRegistry {
28
12
  }
29
13
  get(id) {
30
14
  const value = this.typeMap.get(id);
31
- return value ? __spreadValues$3({}, value) : void 0;
15
+ return value ? JSON.parse(JSON.stringify(value)) : void 0;
32
16
  }
33
17
  add(type, plugin, capability) {
34
18
  this.typeMap.set(type.name, type);
@@ -127,10 +111,21 @@ class XLRValidator {
127
111
  return validationIssues;
128
112
  }
129
113
  }
114
+ let message;
115
+ if (xlrNode.name) {
116
+ message = `Does not match any of the expected types for type: '${xlrNode.name}'`;
117
+ } else if (xlrNode.title) {
118
+ message = `Does not match any of the expected types for property: '${xlrNode.title}'`;
119
+ } else {
120
+ message = `Does not match any of the types ${xlrNode.or.map((node) => {
121
+ var _a2, _b;
122
+ return (_b = (_a2 = node.name) != null ? _a2 : node.title) != null ? _b : "<unnamed type>";
123
+ }).join(" | ")}`;
124
+ }
130
125
  validationIssues.push({
131
126
  type: "value",
132
127
  node: rootNode,
133
- message: `Does not match any of the expected types for type: '${xlrNode.name}'`
128
+ message
134
129
  });
135
130
  } else if (xlrNode.type === "and") {
136
131
  const effectiveType = __spreadValues$2(__spreadValues$2({}, this.computeIntersectionType(xlrNode.and)), xlrNode.name ? { name: xlrNode.name } : {});
@@ -372,10 +367,16 @@ var __spreadValues$1 = (a, b) => {
372
367
  return a;
373
368
  };
374
369
  var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
370
+ const isMatchingCapability = (capability, capabilitiesToMatch) => {
371
+ if (Array.isArray(capabilitiesToMatch)) {
372
+ return capabilitiesToMatch.includes(capability);
373
+ }
374
+ return capability === capabilitiesToMatch;
375
+ };
375
376
  function simpleTransformGenerator(typeToTransform, capabilityToTransform, functionToRun) {
376
377
  const walker = (n, capability) => {
377
378
  var _a;
378
- if (capability === capabilityToTransform) {
379
+ if (isMatchingCapability(capability, capabilityToTransform)) {
379
380
  let node = __spreadValues$1({}, n);
380
381
  if (node.type === typeToTransform) {
381
382
  node = functionToRun(node);
@@ -389,8 +390,16 @@ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functi
389
390
  node: walker(value.node, capability)
390
391
  };
391
392
  }
392
- return __spreadProps$1(__spreadValues$1({}, node), {
393
- properties: __spreadValues$1({}, newObjectProperties),
393
+ return __spreadProps$1(__spreadValues$1(__spreadProps$1(__spreadValues$1({}, node), {
394
+ properties: __spreadValues$1({}, newObjectProperties)
395
+ }), isGenericNamedType(node) ? {
396
+ genericTokens: node.genericTokens.map((token) => {
397
+ return __spreadProps$1(__spreadValues$1({}, token), {
398
+ constraints: token.constraints ? walker(token.constraints, capability) : void 0,
399
+ default: token.default ? walker(token.default, capability) : void 0
400
+ });
401
+ })
402
+ } : {}), {
394
403
  extends: node.extends ? walker(node.extends, capability) : void 0,
395
404
  additionalProperties: node.additionalProperties ? walker(node.additionalProperties, capability) : false
396
405
  });
@@ -411,9 +420,9 @@ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functi
411
420
  });
412
421
  }
413
422
  if (node.type === "ref") {
414
- return __spreadProps$1(__spreadValues$1({}, node), {
423
+ return __spreadValues$1(__spreadValues$1({}, node), node.genericArguments ? {
415
424
  genericArguments: (_a = node.genericArguments) == null ? void 0 : _a.map((arg) => walker(arg, capability))
416
- });
425
+ } : {});
417
426
  }
418
427
  if (node.type === "tuple") {
419
428
  return __spreadProps$1(__spreadValues$1({}, node), {
@@ -507,10 +516,15 @@ class XLRSDK {
507
516
  this.validator = new XLRValidator(this.getType.bind(this));
508
517
  this.tsWriter = new TSWriter();
509
518
  this.computedNodeCache = new Map();
519
+ this.externalTransformFunctions = new Map();
510
520
  }
511
521
  loadDefinitionsFromDisk(inputPath, filters, transforms) {
512
522
  var _a;
513
523
  this.computedNodeCache.clear();
524
+ const transformsToRun = [
525
+ ...this.externalTransformFunctions.values(),
526
+ ...transforms != null ? transforms : []
527
+ ];
514
528
  const manifest = JSON.parse(fs.readFileSync(path.join(inputPath, "xlr", "manifest.json")).toString(), (key, value) => {
515
529
  if (typeof value === "object" && value !== null) {
516
530
  if (key === "capabilities") {
@@ -526,7 +540,7 @@ class XLRSDK {
526
540
  var _a2;
527
541
  if (!(filters == null ? void 0 : filters.typeFilter) || !extensionName.match(filters == null ? void 0 : filters.typeFilter)) {
528
542
  const cType = JSON.parse(fs.readFileSync(path.join(inputPath, "xlr", `${extensionName}.json`)).toString());
529
- const effectiveType = (_a2 = transforms == null ? void 0 : transforms.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), cType)) != null ? _a2 : cType;
543
+ const effectiveType = (_a2 = transformsToRun == null ? void 0 : transformsToRun.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), cType)) != null ? _a2 : cType;
530
544
  this.registry.add(effectiveType, manifest.pluginName, capabilityName);
531
545
  }
532
546
  });
@@ -536,6 +550,10 @@ class XLRSDK {
536
550
  return __async(this, null, function* () {
537
551
  var _a;
538
552
  this.computedNodeCache.clear();
553
+ const transformsToRun = [
554
+ ...this.externalTransformFunctions.values(),
555
+ ...transforms != null ? transforms : []
556
+ ];
539
557
  (_a = Object.keys(manifest.capabilities)) == null ? void 0 : _a.forEach((capabilityName) => {
540
558
  if ((filters == null ? void 0 : filters.capabilityFilter) && capabilityName.match(filters == null ? void 0 : filters.capabilityFilter))
541
559
  return;
@@ -543,20 +561,26 @@ class XLRSDK {
543
561
  capabilityList.forEach((extension) => {
544
562
  var _a2;
545
563
  if (!(filters == null ? void 0 : filters.typeFilter) || !extension.name.match(filters == null ? void 0 : filters.typeFilter)) {
546
- const effectiveType = (_a2 = transforms == null ? void 0 : transforms.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), extension)) != null ? _a2 : extension;
564
+ const effectiveType = (_a2 = transformsToRun == null ? void 0 : transformsToRun.reduce((typeAccumulator, transformFn) => transformFn(typeAccumulator, capabilityName), extension)) != null ? _a2 : extension;
547
565
  this.registry.add(effectiveType, manifest.pluginName, capabilityName);
548
566
  }
549
567
  });
550
568
  });
551
569
  });
552
570
  }
571
+ addTransformFunction(name, fn) {
572
+ this.externalTransformFunctions.set(name, fn);
573
+ }
574
+ removeTransformFunction(name) {
575
+ this.externalTransformFunctions.delete(name);
576
+ }
553
577
  getType(id, options) {
554
578
  let type = this.registry.get(id);
555
579
  if ((options == null ? void 0 : options.getRawType) === true || !type) {
556
580
  return type;
557
581
  }
558
582
  if (this.computedNodeCache.has(id)) {
559
- return this.computedNodeCache.get(id);
583
+ return JSON.parse(JSON.stringify(this.computedNodeCache.get(id)));
560
584
  }
561
585
  type = fillInGenerics(this.resolveType(type));
562
586
  this.computedNodeCache.set(id, type);
@@ -606,10 +630,22 @@ class XLRSDK {
606
630
  throw new Error(`Error resolving ${objectNode.name}: can't find extended type ${refName}`);
607
631
  }
608
632
  extendedType = resolveReferenceNode(objectNode.extends, extendedType);
609
- return __spreadProps(__spreadValues({}, computeEffectiveObject(extendedType, objectNode, false)), {
633
+ if (extendedType.type === "object") {
634
+ return __spreadProps(__spreadValues({}, computeEffectiveObject(extendedType, objectNode, false)), {
635
+ name: objectNode.name,
636
+ description: objectNode.description
637
+ });
638
+ }
639
+ return {
610
640
  name: objectNode.name,
611
- description: objectNode.description
612
- });
641
+ type: "and",
642
+ and: [
643
+ __spreadProps(__spreadValues({}, objectNode), {
644
+ extends: void 0
645
+ }),
646
+ extendedType
647
+ ]
648
+ };
613
649
  }
614
650
  return objectNode;
615
651
  })(type, "any");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@player-tools/xlr-sdk",
3
- "version": "0.4.2--canary.69.1573",
3
+ "version": "0.4.2-next.1",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org"
@@ -9,9 +9,9 @@
9
9
  "typescript": "4.8.4"
10
10
  },
11
11
  "dependencies": {
12
- "@player-tools/xlr": "0.4.2--canary.69.1573",
13
- "@player-tools/xlr-utils": "0.4.2--canary.69.1573",
14
- "@player-tools/xlr-converters": "0.4.2--canary.69.1573",
12
+ "@player-tools/xlr": "0.4.2-next.1",
13
+ "@player-tools/xlr-utils": "0.4.2-next.1",
14
+ "@player-tools/xlr-converters": "0.4.2-next.1",
15
15
  "jsonc-parser": "^2.3.1",
16
16
  "@types/node": "^16.11.12",
17
17
  "@types/fs-extra": "^9.0.13",
@@ -18,7 +18,7 @@ export class BasicXLRRegistry implements XLRRegistry {
18
18
  /** Returns a copy of the XLR to guard against unexpected type modification */
19
19
  get(id: string): NamedType<NodeType> | undefined {
20
20
  const value = this.typeMap.get(id);
21
- return value ? { ...value } : undefined;
21
+ return value ? JSON.parse(JSON.stringify(value)) : undefined;
22
22
  }
23
23
 
24
24
  add(type: NamedType<NodeType>, plugin: string, capability: string): void {
package/src/sdk.ts CHANGED
@@ -2,6 +2,7 @@ import type {
2
2
  Manifest,
3
3
  NamedType,
4
4
  NodeType,
5
+ ObjectNode,
5
6
  ObjectType,
6
7
  TransformFunction,
7
8
  TSManifest,
@@ -37,12 +38,14 @@ export class XLRSDK {
37
38
  private validator: XLRValidator;
38
39
  private tsWriter: TSWriter;
39
40
  private computedNodeCache: Map<string, NodeType>;
41
+ private externalTransformFunctions: Map<string, TransformFunction>;
40
42
 
41
43
  constructor(customRegistry?: XLRRegistry) {
42
44
  this.registry = customRegistry ?? new BasicXLRRegistry();
43
45
  this.validator = new XLRValidator(this.getType.bind(this));
44
46
  this.tsWriter = new TSWriter();
45
47
  this.computedNodeCache = new Map();
48
+ this.externalTransformFunctions = new Map();
46
49
  }
47
50
 
48
51
  /**
@@ -59,6 +62,11 @@ export class XLRSDK {
59
62
  ) {
60
63
  this.computedNodeCache.clear();
61
64
 
65
+ const transformsToRun = [
66
+ ...this.externalTransformFunctions.values(),
67
+ ...(transforms ?? []),
68
+ ];
69
+
62
70
  const manifest = JSON.parse(
63
71
  fs.readFileSync(path.join(inputPath, 'xlr', 'manifest.json')).toString(),
64
72
  (key: unknown, value: unknown) => {
@@ -89,7 +97,7 @@ export class XLRSDK {
89
97
  .toString()
90
98
  );
91
99
  const effectiveType =
92
- transforms?.reduce(
100
+ transformsToRun?.reduce(
93
101
  (typeAccumulator: NamedType<NodeType>, transformFn) =>
94
102
  transformFn(
95
103
  typeAccumulator,
@@ -118,6 +126,11 @@ export class XLRSDK {
118
126
  ) {
119
127
  this.computedNodeCache.clear();
120
128
 
129
+ const transformsToRun = [
130
+ ...this.externalTransformFunctions.values(),
131
+ ...(transforms ?? []),
132
+ ];
133
+
121
134
  Object.keys(manifest.capabilities)?.forEach((capabilityName) => {
122
135
  if (
123
136
  filters?.capabilityFilter &&
@@ -131,7 +144,7 @@ export class XLRSDK {
131
144
  !extension.name.match(filters?.typeFilter)
132
145
  ) {
133
146
  const effectiveType =
134
- transforms?.reduce(
147
+ transformsToRun?.reduce(
135
148
  (typeAccumulator: NamedType<NodeType>, transformFn) =>
136
149
  transformFn(
137
150
  typeAccumulator,
@@ -146,6 +159,20 @@ export class XLRSDK {
146
159
  });
147
160
  }
148
161
 
162
+ /**
163
+ * Statically load transform function that should be applied to every XLR bundle that is imported
164
+ */
165
+ public addTransformFunction(name: string, fn: TransformFunction): void {
166
+ this.externalTransformFunctions.set(name, fn);
167
+ }
168
+
169
+ /**
170
+ * Remove any transform function loaded via the `addTransformFunction` method by name
171
+ */
172
+ public removeTransformFunction(name: string): void {
173
+ this.externalTransformFunctions.delete(name);
174
+ }
175
+
149
176
  /**
150
177
  * Returns a Type that has been previously loaded
151
178
  *
@@ -163,7 +190,9 @@ export class XLRSDK {
163
190
  }
164
191
 
165
192
  if (this.computedNodeCache.has(id)) {
166
- return this.computedNodeCache.get(id) as NamedType<NodeType> | undefined;
193
+ return JSON.parse(JSON.stringify(this.computedNodeCache.get(id))) as
194
+ | NamedType<NodeType>
195
+ | undefined;
167
196
  }
168
197
 
169
198
  type = fillInGenerics(this.resolveType(type)) as NamedType;
@@ -285,15 +314,30 @@ export class XLRSDK {
285
314
  objectNode.extends,
286
315
  extendedType as NamedType<ObjectType>
287
316
  ) as NamedType;
317
+ if (extendedType.type === 'object') {
318
+ return {
319
+ ...computeEffectiveObject(
320
+ extendedType as ObjectType,
321
+ objectNode as ObjectType,
322
+ false
323
+ ),
324
+ name: objectNode.name,
325
+ description: objectNode.description,
326
+ };
327
+ }
328
+
329
+ // if the merge isn't straightforward, defer until validation time for now
288
330
  return {
289
- ...computeEffectiveObject(
290
- extendedType as ObjectType,
291
- objectNode as ObjectType,
292
- false
293
- ),
294
331
  name: objectNode.name,
295
- description: objectNode.description,
296
- };
332
+ type: 'and',
333
+ and: [
334
+ {
335
+ ...objectNode,
336
+ extends: undefined,
337
+ },
338
+ extendedType,
339
+ ],
340
+ } as unknown as ObjectNode;
297
341
  }
298
342
 
299
343
  return objectNode;
package/src/utils.ts CHANGED
@@ -9,6 +9,18 @@ import type {
9
9
  ObjectProperty,
10
10
  RefNode,
11
11
  } from '@player-tools/xlr';
12
+ import { isGenericNamedType } from '@player-tools/xlr-utils';
13
+
14
+ const isMatchingCapability = (
15
+ capability: string,
16
+ capabilitiesToMatch: string | Array<string>
17
+ ): boolean => {
18
+ if (Array.isArray(capabilitiesToMatch)) {
19
+ return capabilitiesToMatch.includes(capability);
20
+ }
21
+
22
+ return capability === capabilitiesToMatch;
23
+ };
12
24
 
13
25
  /**
14
26
  * Helper function for simple transforms
@@ -18,7 +30,7 @@ export function simpleTransformGenerator<
18
30
  T extends NodeTypeStrings = NodeTypeStrings
19
31
  >(
20
32
  typeToTransform: T,
21
- capabilityToTransform: string,
33
+ capabilityToTransform: string | Array<string>,
22
34
  functionToRun: (input: NodeTypeMap[T]) => NodeTypeMap[T]
23
35
  ): TransformFunction {
24
36
  /** walker for an XLR tree to touch every node */
@@ -27,7 +39,7 @@ export function simpleTransformGenerator<
27
39
  capability: string
28
40
  ) => {
29
41
  // Run transform on base node before running on children
30
- if (capability === capabilityToTransform) {
42
+ if (isMatchingCapability(capability, capabilityToTransform)) {
31
43
  let node = { ...n };
32
44
  if (node.type === typeToTransform) {
33
45
  node = functionToRun(node as unknown as NodeTypeMap[T]);
@@ -44,9 +56,25 @@ export function simpleTransformGenerator<
44
56
  };
45
57
  }
46
58
 
59
+ // need to walk generic tokens
47
60
  return {
48
61
  ...node,
49
62
  properties: { ...newObjectProperties },
63
+ ...(isGenericNamedType(node)
64
+ ? {
65
+ genericTokens: node.genericTokens.map((token) => {
66
+ return {
67
+ ...token,
68
+ constraints: token.constraints
69
+ ? walker(token.constraints, capability)
70
+ : undefined,
71
+ default: token.default
72
+ ? walker(token.default, capability)
73
+ : undefined,
74
+ };
75
+ }),
76
+ }
77
+ : {}),
50
78
  extends: node.extends
51
79
  ? (walker(node.extends, capability) as RefNode)
52
80
  : undefined,
@@ -80,9 +108,13 @@ export function simpleTransformGenerator<
80
108
  if (node.type === 'ref') {
81
109
  return {
82
110
  ...node,
83
- genericArguments: node.genericArguments?.map((arg) =>
84
- walker(arg, capability)
85
- ),
111
+ ...(node.genericArguments
112
+ ? {
113
+ genericArguments: node.genericArguments?.map((arg) =>
114
+ walker(arg, capability)
115
+ ),
116
+ }
117
+ : {}),
86
118
  };
87
119
  }
88
120
 
package/src/validator.ts CHANGED
@@ -70,10 +70,22 @@ export class XLRValidator {
70
70
  }
71
71
  }
72
72
 
73
+ let message: string;
74
+
75
+ if (xlrNode.name) {
76
+ message = `Does not match any of the expected types for type: '${xlrNode.name}'`;
77
+ } else if (xlrNode.title) {
78
+ message = `Does not match any of the expected types for property: '${xlrNode.title}'`;
79
+ } else {
80
+ message = `Does not match any of the types ${xlrNode.or
81
+ .map((node) => node.name ?? node.title ?? '<unnamed type>')
82
+ .join(' | ')}`;
83
+ }
84
+
73
85
  validationIssues.push({
74
86
  type: 'value',
75
87
  node: rootNode,
76
- message: `Does not match any of the expected types for type: '${xlrNode.name}'`,
88
+ message,
77
89
  });
78
90
  } else if (xlrNode.type === 'and') {
79
91
  const effectiveType = {