@player-tools/xlr-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -231,29 +231,34 @@ class XLRValidator {
231
231
  validateObject(xlrNode, node) {
232
232
  const issues = [];
233
233
  const objectProps = xlrUtils.makePropertyMap(node);
234
- for (const prop in xlrNode.properties) {
235
- const expectedType = xlrNode.properties[prop];
234
+ let effectiveXLRNode = xlrNode;
235
+ if (xlrNode.extends) {
236
+ const extendedNode = this.getRefType(xlrNode.extends);
237
+ effectiveXLRNode = this.computeEffectiveObject(extendedNode, xlrNode);
238
+ }
239
+ for (const prop in effectiveXLRNode.properties) {
240
+ const expectedType = effectiveXLRNode.properties[prop];
236
241
  const valueNode = objectProps.get(prop);
237
242
  if (expectedType.required && valueNode === void 0) {
238
243
  issues.push({
239
244
  type: "missing",
240
245
  node,
241
- message: `Property '${prop}' missing from type '${xlrNode.name}'`
246
+ message: `Property '${prop}' missing from type '${effectiveXLRNode.name}'`
242
247
  });
243
248
  }
244
249
  if (valueNode) {
245
250
  issues.push(...this.validateType(valueNode, expectedType.node));
246
251
  }
247
252
  }
248
- const extraKeys = Array.from(objectProps.keys()).filter((key) => xlrNode.properties[key] === void 0);
249
- if (xlrNode.additionalProperties === false && extraKeys.length > 0) {
253
+ const extraKeys = Array.from(objectProps.keys()).filter((key) => effectiveXLRNode.properties[key] === void 0);
254
+ if (effectiveXLRNode.additionalProperties === false && extraKeys.length > 0) {
250
255
  issues.push({
251
256
  type: "value",
252
257
  node,
253
- message: `Unexpected properties on '${xlrNode.name}': ${extraKeys.join(", ")}`
258
+ message: `Unexpected properties on '${effectiveXLRNode.name}': ${extraKeys.join(", ")}`
254
259
  });
255
260
  } else {
256
- issues.push(...extraKeys.flatMap((key) => this.validateType(objectProps.get(key), xlrNode.additionalProperties)));
261
+ issues.push(...extraKeys.flatMap((key) => this.validateType(objectProps.get(key), effectiveXLRNode.additionalProperties)));
257
262
  }
258
263
  return issues;
259
264
  }
@@ -357,13 +362,15 @@ class XLRValidator {
357
362
  }
358
363
  computeEffectiveObject(base, operand, errorOnOverlap = true) {
359
364
  var _a, _b;
365
+ const baseObjectName = (_a = base.name) != null ? _a : "object literal";
366
+ const operandObjectName = (_b = operand.name) != null ? _b : "object literal";
360
367
  const newObject = __spreadProps(__spreadValues({}, base), {
361
- name: `${base.name} & ${operand.name}`,
362
- description: `Effective type combining ${base.name} and ${operand.name}`
368
+ name: `${baseObjectName} & ${operandObjectName}`,
369
+ description: `Effective type combining ${baseObjectName} and ${operandObjectName}`
363
370
  });
364
371
  for (const property in operand.properties) {
365
372
  if (newObject.properties[property] !== void 0 && newObject.properties[property].node.type !== operand.properties[property].node.type && errorOnOverlap) {
366
- 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}`);
373
+ throw new Error(`Can't compute effective type for ${baseObjectName} and ${operandObjectName} because of conflicting properties ${property}`);
367
374
  }
368
375
  newObject.properties[property] = operand.properties[property];
369
376
  }
@@ -504,6 +511,62 @@ ${nodeText}`;
504
511
  }
505
512
  }
506
513
 
514
+ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functionToRun) {
515
+ const walker = (node, capability) => {
516
+ var _a;
517
+ if (capability === capabilityToTransform) {
518
+ if (node.type === typeToTransform) {
519
+ functionToRun(node);
520
+ }
521
+ if (node.type === "object") {
522
+ if (node.extends) {
523
+ walker(node, capability);
524
+ }
525
+ for (const key in node.properties) {
526
+ const value = node.properties[key];
527
+ walker(value.node, capability);
528
+ }
529
+ if (node.additionalProperties) {
530
+ walker(node.additionalProperties, capability);
531
+ }
532
+ } else if (node.type === "array") {
533
+ walker(node.elementType, capability);
534
+ } else if (node.type === "and") {
535
+ node.and.forEach((element) => walker(element, capability));
536
+ } else if (node.type === "or") {
537
+ node.or.forEach((element) => walker(element, capability));
538
+ } else if (node.type === "ref") {
539
+ (_a = node.genericArguments) == null ? void 0 : _a.forEach((element) => walker(element, capability));
540
+ } else if (node.type === "tuple") {
541
+ if (node.additionalItems) {
542
+ walker(node.additionalItems, capability);
543
+ }
544
+ node.elementTypes.forEach((element) => walker(element, capability));
545
+ } else if (node.type === "function") {
546
+ node.parameters.forEach((param) => {
547
+ walker(param.type, capability);
548
+ if (param.default) {
549
+ walker(param.default, capability);
550
+ }
551
+ });
552
+ if (node.returnType) {
553
+ walker(node.returnType, capability);
554
+ }
555
+ } else if (node.type === "record") {
556
+ walker(node.keyType, capability);
557
+ walker(node.valueType, capability);
558
+ } else if (node.type === "conditional") {
559
+ walker(node.check.left, capability);
560
+ walker(node.check.right, capability);
561
+ walker(node.value.true, capability);
562
+ walker(node.value.false, capability);
563
+ }
564
+ }
565
+ };
566
+ return walker;
567
+ }
568
+
507
569
  exports.BasicXLRRegistry = BasicXLRRegistry;
508
570
  exports.XLRSDK = XLRSDK;
571
+ exports.simpleTransformGenerator = simpleTransformGenerator;
509
572
  //# sourceMappingURL=index.cjs.js.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Node } from 'jsonc-parser';
2
- import { NamedType, NodeType, TransformFunction } from '@player-tools/xlr';
2
+ import { NamedType, NodeType, TransformFunction, NodeTypeStrings, NodeTypeMap } from '@player-tools/xlr';
3
3
 
4
4
  interface ValidationError {
5
5
  /** Error message text */
@@ -77,4 +77,10 @@ declare class XLRSDK {
77
77
  private exportToTypeScript;
78
78
  }
79
79
 
80
- export { BasicXLRRegistry, ExportTypes, Filters, TypeMetadata, ValidationError, XLRRegistry, XLRSDK };
80
+ /**
81
+ * Helper function for simple transforms
82
+ * Walks an XLR tree looking for the specified node type calls the supplied function when called
83
+ */
84
+ declare function simpleTransformGenerator<T extends NodeTypeStrings = NodeTypeStrings>(typeToTransform: T, capabilityToTransform: string, functionToRun: (input: NodeTypeMap[T]) => void): TransformFunction;
85
+
86
+ export { BasicXLRRegistry, ExportTypes, Filters, TypeMetadata, ValidationError, XLRRegistry, XLRSDK, simpleTransformGenerator };
package/dist/index.esm.js CHANGED
@@ -203,29 +203,34 @@ class XLRValidator {
203
203
  validateObject(xlrNode, node) {
204
204
  const issues = [];
205
205
  const objectProps = makePropertyMap(node);
206
- for (const prop in xlrNode.properties) {
207
- const expectedType = xlrNode.properties[prop];
206
+ let effectiveXLRNode = xlrNode;
207
+ if (xlrNode.extends) {
208
+ const extendedNode = this.getRefType(xlrNode.extends);
209
+ effectiveXLRNode = this.computeEffectiveObject(extendedNode, xlrNode);
210
+ }
211
+ for (const prop in effectiveXLRNode.properties) {
212
+ const expectedType = effectiveXLRNode.properties[prop];
208
213
  const valueNode = objectProps.get(prop);
209
214
  if (expectedType.required && valueNode === void 0) {
210
215
  issues.push({
211
216
  type: "missing",
212
217
  node,
213
- message: `Property '${prop}' missing from type '${xlrNode.name}'`
218
+ message: `Property '${prop}' missing from type '${effectiveXLRNode.name}'`
214
219
  });
215
220
  }
216
221
  if (valueNode) {
217
222
  issues.push(...this.validateType(valueNode, expectedType.node));
218
223
  }
219
224
  }
220
- const extraKeys = Array.from(objectProps.keys()).filter((key) => xlrNode.properties[key] === void 0);
221
- if (xlrNode.additionalProperties === false && extraKeys.length > 0) {
225
+ const extraKeys = Array.from(objectProps.keys()).filter((key) => effectiveXLRNode.properties[key] === void 0);
226
+ if (effectiveXLRNode.additionalProperties === false && extraKeys.length > 0) {
222
227
  issues.push({
223
228
  type: "value",
224
229
  node,
225
- message: `Unexpected properties on '${xlrNode.name}': ${extraKeys.join(", ")}`
230
+ message: `Unexpected properties on '${effectiveXLRNode.name}': ${extraKeys.join(", ")}`
226
231
  });
227
232
  } else {
228
- issues.push(...extraKeys.flatMap((key) => this.validateType(objectProps.get(key), xlrNode.additionalProperties)));
233
+ issues.push(...extraKeys.flatMap((key) => this.validateType(objectProps.get(key), effectiveXLRNode.additionalProperties)));
229
234
  }
230
235
  return issues;
231
236
  }
@@ -329,13 +334,15 @@ class XLRValidator {
329
334
  }
330
335
  computeEffectiveObject(base, operand, errorOnOverlap = true) {
331
336
  var _a, _b;
337
+ const baseObjectName = (_a = base.name) != null ? _a : "object literal";
338
+ const operandObjectName = (_b = operand.name) != null ? _b : "object literal";
332
339
  const newObject = __spreadProps(__spreadValues({}, base), {
333
- name: `${base.name} & ${operand.name}`,
334
- description: `Effective type combining ${base.name} and ${operand.name}`
340
+ name: `${baseObjectName} & ${operandObjectName}`,
341
+ description: `Effective type combining ${baseObjectName} and ${operandObjectName}`
335
342
  });
336
343
  for (const property in operand.properties) {
337
344
  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}`);
345
+ throw new Error(`Can't compute effective type for ${baseObjectName} and ${operandObjectName} because of conflicting properties ${property}`);
339
346
  }
340
347
  newObject.properties[property] = operand.properties[property];
341
348
  }
@@ -476,5 +483,60 @@ ${nodeText}`;
476
483
  }
477
484
  }
478
485
 
479
- export { BasicXLRRegistry, XLRSDK };
486
+ function simpleTransformGenerator(typeToTransform, capabilityToTransform, functionToRun) {
487
+ const walker = (node, capability) => {
488
+ var _a;
489
+ if (capability === capabilityToTransform) {
490
+ if (node.type === typeToTransform) {
491
+ functionToRun(node);
492
+ }
493
+ if (node.type === "object") {
494
+ if (node.extends) {
495
+ walker(node, capability);
496
+ }
497
+ for (const key in node.properties) {
498
+ const value = node.properties[key];
499
+ walker(value.node, capability);
500
+ }
501
+ if (node.additionalProperties) {
502
+ walker(node.additionalProperties, capability);
503
+ }
504
+ } else if (node.type === "array") {
505
+ walker(node.elementType, capability);
506
+ } else if (node.type === "and") {
507
+ node.and.forEach((element) => walker(element, capability));
508
+ } else if (node.type === "or") {
509
+ node.or.forEach((element) => walker(element, capability));
510
+ } else if (node.type === "ref") {
511
+ (_a = node.genericArguments) == null ? void 0 : _a.forEach((element) => walker(element, capability));
512
+ } else if (node.type === "tuple") {
513
+ if (node.additionalItems) {
514
+ walker(node.additionalItems, capability);
515
+ }
516
+ node.elementTypes.forEach((element) => walker(element, capability));
517
+ } else if (node.type === "function") {
518
+ node.parameters.forEach((param) => {
519
+ walker(param.type, capability);
520
+ if (param.default) {
521
+ walker(param.default, capability);
522
+ }
523
+ });
524
+ if (node.returnType) {
525
+ walker(node.returnType, capability);
526
+ }
527
+ } else if (node.type === "record") {
528
+ walker(node.keyType, capability);
529
+ walker(node.valueType, capability);
530
+ } else if (node.type === "conditional") {
531
+ walker(node.check.left, capability);
532
+ walker(node.check.right, capability);
533
+ walker(node.value.true, capability);
534
+ walker(node.value.false, capability);
535
+ }
536
+ }
537
+ };
538
+ return walker;
539
+ }
540
+
541
+ export { BasicXLRRegistry, XLRSDK, simpleTransformGenerator };
480
542
  //# sourceMappingURL=index.esm.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@player-tools/xlr-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org"
@@ -9,9 +9,9 @@
9
9
  "typescript": "4.4.4"
10
10
  },
11
11
  "dependencies": {
12
- "@player-tools/xlr": "0.1.0",
13
- "@player-tools/xlr-utils": "0.1.0",
14
- "@player-tools/xlr-converters": "0.1.0",
12
+ "@player-tools/xlr": "0.2.0",
13
+ "@player-tools/xlr-utils": "0.2.0",
14
+ "@player-tools/xlr-converters": "0.2.0",
15
15
  "jsonc-parser": "^2.3.1",
16
16
  "@types/node": "^16.11.12",
17
17
  "@types/fs-extra": "^9.0.13",
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './sdk';
2
2
  export * from './types';
3
3
  export * from './registry';
4
+ export * from './utils';
package/src/utils.ts ADDED
@@ -0,0 +1,85 @@
1
+ /* eslint-disable guard-for-in */
2
+ /* eslint-disable no-restricted-syntax */
3
+ import type {
4
+ NamedType,
5
+ NodeTypeStrings,
6
+ NodeTypeMap,
7
+ TransformFunction,
8
+ NodeType,
9
+ } from '@player-tools/xlr';
10
+
11
+ /**
12
+ * Helper function for simple transforms
13
+ * Walks an XLR tree looking for the specified node type calls the supplied function when called
14
+ */
15
+ export function simpleTransformGenerator<
16
+ T extends NodeTypeStrings = NodeTypeStrings
17
+ >(
18
+ typeToTransform: T,
19
+ capabilityToTransform: string,
20
+ functionToRun: (input: NodeTypeMap[T]) => void
21
+ ): TransformFunction {
22
+ /** walker for an XLR tree to touch every node */
23
+ const walker: TransformFunction = (
24
+ node: NamedType | NodeType,
25
+ capability: string
26
+ ) => {
27
+ // Run transform on base node before running on children
28
+ if (capability === capabilityToTransform) {
29
+ if (node.type === typeToTransform) {
30
+ functionToRun(node as unknown as NodeTypeMap[T]);
31
+ }
32
+
33
+ if (node.type === 'object') {
34
+ if (node.extends) {
35
+ walker(node, capability);
36
+ }
37
+
38
+ for (const key in node.properties) {
39
+ const value = node.properties[key];
40
+ walker(value.node, capability);
41
+ }
42
+
43
+ if (node.additionalProperties) {
44
+ walker(node.additionalProperties, capability);
45
+ }
46
+ } else if (node.type === 'array') {
47
+ walker(node.elementType, capability);
48
+ } else if (node.type === 'and') {
49
+ node.and.forEach((element) => walker(element, capability));
50
+ } else if (node.type === 'or') {
51
+ node.or.forEach((element) => walker(element, capability));
52
+ } else if (node.type === 'ref') {
53
+ node.genericArguments?.forEach((element) =>
54
+ walker(element, capability)
55
+ );
56
+ } else if (node.type === 'tuple') {
57
+ if (node.additionalItems) {
58
+ walker(node.additionalItems, capability);
59
+ }
60
+
61
+ node.elementTypes.forEach((element) => walker(element, capability));
62
+ } else if (node.type === 'function') {
63
+ node.parameters.forEach((param) => {
64
+ walker(param.type, capability);
65
+ if (param.default) {
66
+ walker(param.default, capability);
67
+ }
68
+ });
69
+ if (node.returnType) {
70
+ walker(node.returnType, capability);
71
+ }
72
+ } else if (node.type === 'record') {
73
+ walker(node.keyType, capability);
74
+ walker(node.valueType, capability);
75
+ } else if (node.type === 'conditional') {
76
+ walker(node.check.left, capability);
77
+ walker(node.check.right, capability);
78
+ walker(node.value.true, capability);
79
+ walker(node.value.false, capability);
80
+ }
81
+ }
82
+ };
83
+
84
+ return walker;
85
+ }
package/src/validator.ts CHANGED
@@ -169,15 +169,23 @@ export class XLRValidator {
169
169
  private validateObject(xlrNode: ObjectType, node: Node) {
170
170
  const issues: Array<ValidationError> = [];
171
171
  const objectProps = makePropertyMap(node);
172
+
173
+ let effectiveXLRNode = xlrNode;
174
+
175
+ if (xlrNode.extends) {
176
+ const extendedNode = this.getRefType(xlrNode.extends) as ObjectType;
177
+ effectiveXLRNode = this.computeEffectiveObject(extendedNode, xlrNode);
178
+ }
179
+
172
180
  // eslint-disable-next-line guard-for-in, no-restricted-syntax
173
- for (const prop in xlrNode.properties) {
174
- const expectedType = xlrNode.properties[prop];
181
+ for (const prop in effectiveXLRNode.properties) {
182
+ const expectedType = effectiveXLRNode.properties[prop];
175
183
  const valueNode = objectProps.get(prop);
176
184
  if (expectedType.required && valueNode === undefined) {
177
185
  issues.push({
178
186
  type: 'missing',
179
187
  node,
180
- message: `Property '${prop}' missing from type '${xlrNode.name}'`,
188
+ message: `Property '${prop}' missing from type '${effectiveXLRNode.name}'`,
181
189
  });
182
190
  }
183
191
 
@@ -190,22 +198,25 @@ export class XLRValidator {
190
198
 
191
199
  // Check if unknown keys are allowed and if they are - do the violate the constraint
192
200
  const extraKeys = Array.from(objectProps.keys()).filter(
193
- (key) => xlrNode.properties[key] === undefined
201
+ (key) => effectiveXLRNode.properties[key] === undefined
194
202
  );
195
- if (xlrNode.additionalProperties === false && extraKeys.length > 0) {
203
+ if (
204
+ effectiveXLRNode.additionalProperties === false &&
205
+ extraKeys.length > 0
206
+ ) {
196
207
  issues.push({
197
208
  type: 'value',
198
209
  node,
199
- message: `Unexpected properties on '${xlrNode.name}': ${extraKeys.join(
200
- ', '
201
- )}`,
210
+ message: `Unexpected properties on '${
211
+ effectiveXLRNode.name
212
+ }': ${extraKeys.join(', ')}`,
202
213
  });
203
214
  } else {
204
215
  issues.push(
205
216
  ...extraKeys.flatMap((key) =>
206
217
  this.validateType(
207
218
  objectProps.get(key) as Node,
208
- xlrNode.additionalProperties as NodeType
219
+ effectiveXLRNode.additionalProperties as NodeType
209
220
  )
210
221
  )
211
222
  );
@@ -358,10 +369,12 @@ export class XLRValidator {
358
369
  operand: ObjectType,
359
370
  errorOnOverlap = true
360
371
  ): ObjectType {
372
+ const baseObjectName = base.name ?? 'object literal';
373
+ const operandObjectName = operand.name ?? 'object literal';
361
374
  const newObject = {
362
375
  ...base,
363
- name: `${base.name} & ${operand.name}`,
364
- description: `Effective type combining ${base.name} and ${operand.name}`,
376
+ name: `${baseObjectName} & ${operandObjectName}`,
377
+ description: `Effective type combining ${baseObjectName} and ${operandObjectName}`,
365
378
  };
366
379
 
367
380
  // eslint-disable-next-line no-restricted-syntax, guard-for-in
@@ -373,11 +386,7 @@ export class XLRValidator {
373
386
  errorOnOverlap
374
387
  ) {
375
388
  throw new Error(
376
- `Can't compute effective type for ${
377
- base.name ?? 'object literal'
378
- } and ${
379
- operand.name ?? 'object literal'
380
- } because of conflicting properties ${property}`
389
+ `Can't compute effective type for ${baseObjectName} and ${operandObjectName} because of conflicting properties ${property}`
381
390
  );
382
391
  }
383
392