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