componentsjs 5.0.0-beta.0 → 5.0.0-beta.4

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +272 -0
  2. package/README.md +16 -0
  3. package/components/context.jsonld +62 -1
  4. package/lib/ComponentsManager.js +3 -5
  5. package/lib/construction/strategy/ConstructionStrategyCommonJs.d.ts +3 -1
  6. package/lib/construction/strategy/ConstructionStrategyCommonJs.js +8 -10
  7. package/lib/construction/strategy/ConstructionStrategyCommonJsString.js +6 -8
  8. package/lib/loading/ComponentRegistryFinalizer.js +7 -1
  9. package/lib/preprocess/ConfigPreprocessorComponent.d.ts +2 -0
  10. package/lib/preprocess/ConfigPreprocessorComponent.js +18 -1
  11. package/lib/preprocess/ConfigPreprocessorComponentMapped.d.ts +3 -2
  12. package/lib/preprocess/ConfigPreprocessorComponentMapped.js +9 -7
  13. package/lib/preprocess/GenericsContext.d.ts +74 -0
  14. package/lib/preprocess/GenericsContext.js +326 -0
  15. package/lib/preprocess/ParameterHandler.d.ts +6 -2
  16. package/lib/preprocess/ParameterHandler.js +7 -6
  17. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerCollectEntries.d.ts +3 -2
  18. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerCollectEntries.js +8 -6
  19. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerElements.d.ts +2 -1
  20. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerElements.js +2 -2
  21. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerFields.d.ts +2 -1
  22. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerFields.js +3 -2
  23. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerKeyValue.d.ts +4 -3
  24. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerKeyValue.js +7 -7
  25. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerList.d.ts +2 -1
  26. package/lib/preprocess/constructorargumentsmapping/ConstructorArgumentsElementMappingHandlerList.js +5 -3
  27. package/lib/preprocess/constructorargumentsmapping/IConstructorArgumentsElementMappingHandler.d.ts +5 -2
  28. package/lib/preprocess/constructorargumentsmapping/IConstructorArgumentsMapper.d.ts +5 -2
  29. package/lib/preprocess/parameterproperty/IParameterPropertyHandler.d.ts +5 -2
  30. package/lib/preprocess/parameterproperty/ParameterPropertyHandlerRange.d.ts +34 -11
  31. package/lib/preprocess/parameterproperty/ParameterPropertyHandlerRange.js +393 -88
  32. package/lib/util/ErrorResourcesContext.d.ts +11 -14
  33. package/lib/util/ErrorResourcesContext.js +44 -22
  34. package/package.json +2 -2
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ParameterPropertyHandlerRange = void 0;
4
4
  const Iris_1 = require("../../rdf/Iris");
5
5
  const ErrorResourcesContext_1 = require("../../util/ErrorResourcesContext");
6
+ const GenericsContext_1 = require("../GenericsContext");
6
7
  /**
7
8
  * If a param range is defined, apply the type and validate the range.
8
9
  */
@@ -13,8 +14,8 @@ class ParameterPropertyHandlerRange {
13
14
  canHandle(value, configRoot, parameter) {
14
15
  return Boolean(parameter.property.range);
15
16
  }
16
- handle(value, configRoot, parameter, configElement) {
17
- this.captureType(value, parameter);
17
+ handle(value, configRoot, parameter, configElement, genericsContext) {
18
+ this.captureType(value, parameter, genericsContext);
18
19
  return value;
19
20
  }
20
21
  /**
@@ -24,34 +25,48 @@ class ParameterPropertyHandlerRange {
24
25
  * Will be ignored if the value is not a literal or the type is not recognized.
25
26
  * @param value The value.
26
27
  * @param param The parameter.
28
+ * @param genericsContext Context for generic types.
27
29
  */
28
- captureType(value, param) {
29
- if (this.hasParamValueValidType(value, param, param.property.range)) {
30
+ captureType(value, param, genericsContext) {
31
+ const errorContext = { param };
32
+ const conflict = this.hasValueType(value, param.property.range, errorContext, genericsContext);
33
+ if (!conflict) {
30
34
  return value;
31
35
  }
32
- this.throwIncorrectTypeError(value, param);
36
+ ParameterPropertyHandlerRange.throwIncorrectTypeError(value, param, genericsContext, conflict);
33
37
  }
34
38
  /**
35
- * Apply the given datatype to the given literal.
36
- * Checks if the datatype is correct and casts to the correct js type.
37
- * Will throw an error if the type has an invalid value.
38
- * Will be ignored if the value is not a literal or the type is not recognized.
39
+ * Check if the given value is of the given type.
40
+ *
41
+ * For valid literals, the `valueRaw` field will be set.
42
+ *
39
43
  * @param value The value.
40
- * @param param The parameter.
41
- * @param paramRange The parameter's range.
44
+ * @param type The parameter's range.
45
+ * @param genericsContext Context for generic types.
46
+ * @param errorContext The context for error reporting.
47
+ * @return IParamValueConflict A conflict value if there was an error, or undefined if there was no error
42
48
  */
43
- hasParamValueValidType(value, param, paramRange) {
44
- if (!paramRange) {
45
- return true;
49
+ hasValueType(value, type, errorContext, genericsContext) {
50
+ errorContext = Object.assign(Object.assign({}, errorContext), { value, type });
51
+ if (!type) {
52
+ return;
53
+ }
54
+ if (type.isA('ParameterRangeWildcard')) {
55
+ return;
56
+ }
57
+ if (!value && type.isA('ParameterRangeUndefined')) {
58
+ return;
46
59
  }
47
- if (!value && paramRange.isA('ParameterRangeUndefined')) {
48
- return true;
60
+ // Always match variable values
61
+ if (value && value.isA('Variable')) {
62
+ return;
49
63
  }
64
+ // Handle literal values
50
65
  if (value && value.type === 'Literal') {
51
66
  let parsed;
52
- switch (paramRange.value) {
67
+ switch (type.value) {
53
68
  case Iris_1.IRIS_XSD.string:
54
- return true;
69
+ return;
55
70
  case Iris_1.IRIS_XSD.boolean:
56
71
  if (value.value === 'true') {
57
72
  value.term.valueRaw = true;
@@ -60,9 +75,12 @@ class ParameterPropertyHandlerRange {
60
75
  value.term.valueRaw = false;
61
76
  }
62
77
  else {
63
- return false;
78
+ return {
79
+ description: 'value must either be "true" or "false"',
80
+ context: errorContext,
81
+ };
64
82
  }
65
- return true;
83
+ return;
66
84
  case Iris_1.IRIS_XSD.integer:
67
85
  case Iris_1.IRIS_XSD.number:
68
86
  case Iris_1.IRIS_XSD.int:
@@ -70,138 +88,425 @@ class ParameterPropertyHandlerRange {
70
88
  case Iris_1.IRIS_XSD.long:
71
89
  parsed = Number.parseInt(value.value, 10);
72
90
  if (Number.isNaN(parsed)) {
73
- return false;
91
+ return {
92
+ description: `value is not a number`,
93
+ context: errorContext,
94
+ };
74
95
  }
75
96
  // ParseInt also parses floats to ints!
76
97
  if (String(parsed) !== value.value) {
77
- return false;
98
+ return {
99
+ description: `value can not be a float`,
100
+ context: errorContext,
101
+ };
78
102
  }
79
103
  value.term.valueRaw = parsed;
80
- return true;
104
+ return;
81
105
  case Iris_1.IRIS_XSD.float:
82
106
  case Iris_1.IRIS_XSD.decimal:
83
107
  case Iris_1.IRIS_XSD.double:
84
108
  parsed = Number.parseFloat(value.value);
85
109
  if (Number.isNaN(parsed)) {
86
- return false;
110
+ return {
111
+ description: `value is not a number`,
112
+ context: errorContext,
113
+ };
87
114
  }
88
115
  value.term.valueRaw = parsed;
89
- return true;
116
+ return;
90
117
  case Iris_1.IRIS_RDF.JSON:
91
118
  try {
92
119
  parsed = JSON.parse(value.value);
93
120
  value.term.valueRaw = parsed;
94
121
  }
95
- catch (_a) {
96
- return false;
122
+ catch (error) {
123
+ return {
124
+ description: `JSON parse exception: ${error.message}`,
125
+ context: errorContext,
126
+ };
97
127
  }
98
- return true;
128
+ return;
99
129
  }
100
130
  }
101
131
  // Allow IRIs to be casted to strings
102
- if (value && paramRange && paramRange.value === Iris_1.IRIS_XSD.string && value.type === 'NamedNode') {
103
- return true;
132
+ if (value && type.value === Iris_1.IRIS_XSD.string && value.type === 'NamedNode') {
133
+ return;
104
134
  }
105
- if (paramRange && (!value || (!value.isA('Variable') && !value.isA(paramRange.term)))) {
106
- if (value && paramRange.isA('ParameterRangeArray')) {
107
- if (!value.list) {
108
- return false;
135
+ // Try to match the value with the parameter's range (which will always be defined at this stage)
136
+ // Check if the value has a super-type that equals the parameter's range
137
+ let hasTypeConflict;
138
+ if (value) {
139
+ const hasTypeConflictInner = this.hasType(value, type, genericsContext, value.property.genericTypeInstancesComponentScope, value.properties.genericTypeInstances, errorContext);
140
+ if (!hasTypeConflictInner) {
141
+ return;
142
+ }
143
+ hasTypeConflict = hasTypeConflictInner;
144
+ }
145
+ else {
146
+ hasTypeConflict = undefined;
147
+ }
148
+ // Check if the param type is an array
149
+ if (value && type.isA('ParameterRangeArray')) {
150
+ if (!value.list) {
151
+ return {
152
+ description: `value is not an RDF list`,
153
+ context: errorContext,
154
+ };
155
+ }
156
+ const subConflicts = value.list.map(listElement => this
157
+ .hasValueType(listElement, type.property.parameterRangeValue, errorContext, genericsContext))
158
+ .filter(subConflict => subConflict !== undefined);
159
+ return subConflicts.length === 0 ?
160
+ undefined :
161
+ {
162
+ description: `one or more array values are invalid`,
163
+ context: errorContext,
164
+ causes: subConflicts,
165
+ };
166
+ }
167
+ // Check if the param type is a composed type
168
+ if (type.isA('ParameterRangeUnion')) {
169
+ const subConflicts = [];
170
+ for (const parameterRangeElement of type.properties.parameterRangeElements) {
171
+ const subConflict = this.hasValueType(value, parameterRangeElement, errorContext, genericsContext);
172
+ if (!subConflict) {
173
+ return;
109
174
  }
110
- return value.list.every(listElement => this
111
- .hasParamValueValidType(listElement, param, paramRange.property.parameterRangeValue));
175
+ subConflicts.push(subConflict);
112
176
  }
113
- // Check if the param type is a composed type
114
- if (paramRange.isA('ParameterRangeUnion')) {
115
- return paramRange.properties.parameterRangeElements
116
- .some(child => this.hasParamValueValidType(value, param, child));
177
+ return {
178
+ description: `no union values are valid`,
179
+ context: errorContext,
180
+ causes: subConflicts,
181
+ };
182
+ }
183
+ if (type.isA('ParameterRangeIntersection')) {
184
+ const subConflicts = type.properties.parameterRangeElements
185
+ .map(child => this.hasValueType(value, child, errorContext, genericsContext));
186
+ if (subConflicts.every(subConflict => subConflict === undefined)) {
187
+ return;
117
188
  }
118
- if (paramRange.isA('ParameterRangeIntersection')) {
119
- return paramRange.properties.parameterRangeElements
120
- .every(child => this.hasParamValueValidType(value, param, child));
189
+ return {
190
+ description: `not all intersection values are valid`,
191
+ context: errorContext,
192
+ causes: subConflicts.filter(subConflict => subConflict !== undefined),
193
+ };
194
+ }
195
+ if (type.isA('ParameterRangeTuple')) {
196
+ if (!value) {
197
+ return {
198
+ description: `undefined value is not an RDF list`,
199
+ context: errorContext,
200
+ };
121
201
  }
122
- if (paramRange.isA('ParameterRangeTuple')) {
123
- if (!value || !value.list) {
124
- return false;
125
- }
126
- // Iterate over list elements and try to match with tuple types
127
- const listElements = value.list;
128
- const tupleTypes = paramRange.properties.parameterRangeElements;
129
- let listIndex = 0;
130
- let tupleIndex = 0;
131
- while (listIndex < listElements.length && tupleIndex < tupleTypes.length) {
132
- if (tupleTypes[tupleIndex].isA('ParameterRangeRest')) {
133
- // Rest types can match multiple list elements, so only increment index if no match is found.
134
- if (!this.hasParamValueValidType(listElements[listIndex], param, tupleTypes[tupleIndex].property.parameterRangeValue)) {
135
- tupleIndex++;
136
- }
137
- else {
138
- listIndex++;
139
- }
202
+ if (!value.list) {
203
+ return {
204
+ description: `value is not an RDF list`,
205
+ context: errorContext,
206
+ };
207
+ }
208
+ // Iterate over list elements and try to match with tuple types
209
+ const listElements = value.list;
210
+ const tupleTypes = type.properties.parameterRangeElements;
211
+ let listIndex = 0;
212
+ let tupleIndex = 0;
213
+ while (listIndex < listElements.length && tupleIndex < tupleTypes.length) {
214
+ if (tupleTypes[tupleIndex].isA('ParameterRangeRest')) {
215
+ // Rest types can match multiple list elements, so only increment index if no match is found.
216
+ const subConflict = this.hasValueType(listElements[listIndex], tupleTypes[tupleIndex].property.parameterRangeValue, errorContext, genericsContext);
217
+ if (subConflict) {
218
+ tupleIndex++;
140
219
  }
141
220
  else {
142
- if (!this.hasParamValueValidType(listElements[listIndex], param, tupleTypes[tupleIndex])) {
143
- return false;
144
- }
145
- tupleIndex++;
146
221
  listIndex++;
147
222
  }
148
223
  }
149
- return listIndex === listElements.length &&
150
- (tupleIndex === tupleTypes.length ||
151
- (tupleIndex === tupleTypes.length - 1 && tupleTypes[tupleIndex].isA('ParameterRangeRest')));
224
+ else {
225
+ const subConflict = this.hasValueType(listElements[listIndex], tupleTypes[tupleIndex], errorContext, genericsContext);
226
+ if (subConflict) {
227
+ return {
228
+ description: `tuple element is invalid`,
229
+ context: errorContext,
230
+ causes: [subConflict],
231
+ };
232
+ }
233
+ tupleIndex++;
234
+ listIndex++;
235
+ }
236
+ }
237
+ if (!(listIndex === listElements.length &&
238
+ (tupleIndex === tupleTypes.length ||
239
+ (tupleIndex === tupleTypes.length - 1 && tupleTypes[tupleIndex].isA('ParameterRangeRest'))))) {
240
+ return {
241
+ description: `tuple does not contain the expected number of elements`,
242
+ context: errorContext,
243
+ };
244
+ }
245
+ return;
246
+ }
247
+ if (type.isA('ParameterRangeLiteral')) {
248
+ if (value && value.term.equals(type.property.parameterRangeValue.term)) {
249
+ return;
250
+ }
251
+ return {
252
+ description: `literal value is unequal`,
253
+ context: errorContext,
254
+ };
255
+ }
256
+ // Check if the range refers to `keyof ...`
257
+ if (type.isA('ParameterRangeKeyof')) {
258
+ const component = type.property.parameterRangeValue;
259
+ // Simulate a union of the member keys as literal parameter ranges
260
+ const simulatedUnionRange = this.objectLoader.createCompactedResource({
261
+ '@type': 'ParameterRangeUnion',
262
+ parameterRangeElements: component.properties.memberFields.map(memberField => ({
263
+ '@type': 'ParameterRangeLiteral',
264
+ parameterRangeValue: memberField.property.memberFieldName,
265
+ })),
266
+ });
267
+ const subConflict = this.hasValueType(value, simulatedUnionRange, errorContext, genericsContext);
268
+ if (!subConflict) {
269
+ return;
270
+ }
271
+ return {
272
+ description: `keyof value is invalid`,
273
+ context: errorContext,
274
+ causes: [subConflict],
275
+ };
276
+ }
277
+ // Check if the range refers to an indexed type such as `MyClass[myField]`
278
+ if (type.isA('ParameterRangeIndexed')) {
279
+ const object = type.property.parameterRangeIndexedObject;
280
+ const index = type.property.parameterRangeIndexedIndex;
281
+ // Collect field ranges
282
+ const fieldRanges = Object.fromEntries(object.properties.memberFields
283
+ .map(memberField => [memberField.property.memberFieldName.value, memberField.property.range ||
284
+ this.objectLoader.createCompactedResource({ '@type': 'ParameterRangeWildcard' })]));
285
+ // Handle literal indexes
286
+ if (index.isA('ParameterRangeLiteral')) {
287
+ const field = index.property.parameterRangeValue.value;
288
+ const range = fieldRanges[field];
289
+ if (!range) {
290
+ return {
291
+ description: `indexed index does not refer to a known field`,
292
+ context: errorContext,
293
+ };
294
+ }
295
+ const subConflict = this.hasValueType(value, range, errorContext, genericsContext);
296
+ if (!subConflict) {
297
+ return;
298
+ }
299
+ return {
300
+ description: `indexed value is invalid`,
301
+ context: errorContext,
302
+ causes: [subConflict],
303
+ };
152
304
  }
153
- if (paramRange.isA('ParameterRangeLiteral')) {
154
- return Boolean(value && value.term.equals(paramRange.property.parameterRangeValue.term));
305
+ return {
306
+ description: `indexed index type can not be understood`,
307
+ context: errorContext,
308
+ };
309
+ }
310
+ // Check if the range refers to a generic type
311
+ if (type.isA('ParameterRangeGenericTypeReference')) {
312
+ return genericsContext.bindGenericTypeToValue(type.property.parameterRangeGenericType.value, value, (subValue, subType) => this.hasValueType(subValue, subType, errorContext, genericsContext), (subType, superType) => this.hasType(subType, superType, genericsContext, undefined, [], errorContext));
313
+ }
314
+ // Check if the range refers to a component with a generic type
315
+ if (type.isA('ParameterRangeGenericComponent')) {
316
+ if (value) {
317
+ if (!value.property.genericTypeInstances) {
318
+ // For the defined generic type instances, apply them into the instance so they can be checked later during a
319
+ // call to GenericsContext#bindComponentGenericTypes.
320
+ value.property.genericTypeInstancesComponentScope = type.property.component;
321
+ value.properties.genericTypeInstances = type.properties.genericTypeInstances
322
+ .map(genericTypeInstance => {
323
+ // If we have a generic param type reference, instantiate them based on the current generics context
324
+ if (genericTypeInstance.isA('ParameterRangeGenericTypeReference')) {
325
+ if (!genericTypeInstance.property.parameterRangeGenericType) {
326
+ throw new ErrorResourcesContext_1.ErrorResourcesContext(`Invalid generic type instance in a ParameterRangeGenericComponent was detected: missing parameterRangeGenericType property.`, Object.assign(Object.assign({}, errorContext), { genericTypeInstance }));
327
+ }
328
+ return this.objectLoader.createCompactedResource({
329
+ '@type': 'ParameterRangeGenericTypeReference',
330
+ parameterRangeGenericType: genericTypeInstance.property.parameterRangeGenericType.value,
331
+ parameterRangeGenericBindings: genericsContext
332
+ .bindings[genericTypeInstance.property.parameterRangeGenericType.value],
333
+ });
334
+ }
335
+ // For all other param types, return the as-is
336
+ return genericTypeInstance;
337
+ });
338
+ }
339
+ else {
340
+ // TODO: Once we support manual generics setting, we'll need to check here if we can merge with it.
341
+ // (sometimes, it can also be identical)
342
+ }
155
343
  }
156
- // Check if this param defines a field with sub-params
157
- if (paramRange.isA('ParameterRangeCollectEntries')) {
158
- // TODO: Add support for type-checking nested fields with collectEntries
159
- return true;
344
+ const subConflict = this.hasValueType(value, type.property.component, errorContext, genericsContext);
345
+ if (!subConflict) {
346
+ return;
160
347
  }
161
- return false;
348
+ return {
349
+ description: `generic component is invalid`,
350
+ context: errorContext,
351
+ causes: [subConflict],
352
+ };
353
+ }
354
+ // Check if this param defines a field with sub-params
355
+ if (type.isA('ParameterRangeCollectEntries')) {
356
+ // TODO: Add support for type-checking nested fields with collectEntries
357
+ return;
162
358
  }
163
- return true;
359
+ return hasTypeConflict || { description: 'unknown parameter type', context: errorContext };
164
360
  }
165
- throwIncorrectTypeError(value, parameter) {
361
+ static throwIncorrectTypeError(value, parameter, genericsContext, conflict) {
166
362
  const withTypes = value && value.properties.types.length > 0 ? ` with types "${value.properties.types.map(resource => resource.value)}"` : '';
167
363
  // eslint-disable-next-line @typescript-eslint/no-extra-parens
168
364
  const valueString = value ? (value.list ? `[${value.list.map(subValue => subValue.value).join(', ')}]` : value.value) : 'undefined';
169
- throw new ErrorResourcesContext_1.ErrorResourcesContext(`The value "${valueString}"${withTypes} for parameter "${parameter.value}" is not of required range type "${this.rangeToDisplayString(parameter.property.range)}"`, {
170
- value: value || 'undefined',
171
- parameter,
172
- });
365
+ throw new ErrorResourcesContext_1.ErrorResourcesContext(`The value "${valueString}"${withTypes} for parameter "${parameter.value}" is not of required range type "${ParameterPropertyHandlerRange.rangeToDisplayString(parameter.property.range, genericsContext)}"`, Object.assign(Object.assign({ cause: conflict, value: value || 'undefined' }, Object.keys(genericsContext.bindings).length > 0 ?
366
+ { generics: `[\n ${Object.entries(genericsContext.bindings)
367
+ .map(([id, subValue]) => `<${id}> => ${ParameterPropertyHandlerRange.rangeToDisplayString(subValue, genericsContext)}`)
368
+ .join(',\n ')}\n]` } :
369
+ {}), { parameter }));
173
370
  }
174
- rangeToDisplayString(paramRange) {
175
- if (!paramRange) {
371
+ /**
372
+ * Check if the given value is of the given type.
373
+ * @param value A value.
374
+ * @param type A type.
375
+ * @param genericsContext The current generics context.
376
+ * @param genericTypeInstancesComponentScope
377
+ * @param genericTypeInstances
378
+ * @param errorContext
379
+ */
380
+ hasType(value, type, genericsContext, genericTypeInstancesComponentScope, genericTypeInstances, errorContext) {
381
+ var _a;
382
+ // Immediately return if the terms are equal
383
+ if (value.term.equals(type.term)) {
384
+ return;
385
+ }
386
+ // Otherwise, iterate over the value's super types are recursively call this method again.
387
+ const subConflictTypes = [];
388
+ for (const valueSuperType of [...value.properties.extends, ...value.properties.type]) {
389
+ // Special case: if the super component is wrapped in a generic component instantiation, unwrap it.
390
+ if (((_a = valueSuperType.property.type) === null || _a === void 0 ? void 0 : _a.value) === this.objectLoader.contextResolved
391
+ .expandTerm('oo:GenericComponentExtension')) {
392
+ // First recursively continue calling hasType for the unwrapped component
393
+ const hasTypeConflict = this.hasType(valueSuperType.property.component, type, genericsContext, genericTypeInstancesComponentScope, genericTypeInstances, errorContext);
394
+ if (!hasTypeConflict) {
395
+ // If hasType has passed, validate the generic instantiations
396
+ // AND (possibly) the parameter's generic type instances against the component's generic params.
397
+ const superComponent = valueSuperType.property.component;
398
+ const genericsContextInner = new GenericsContext_1.GenericsContext(this.objectLoader, superComponent.properties.genericTypeParameters);
399
+ const typeTypeValidator = (subType, superType) => this
400
+ .hasType(subType, superType, genericsContextInner, undefined, [], errorContext);
401
+ // Try to bind the generic instances from the wrapped generic component instantiation
402
+ const subConflictWrapped = genericsContextInner.bindComponentGenericTypes(superComponent, valueSuperType.properties.genericTypeInstances
403
+ .map(instance => this.objectLoader.createCompactedResource({
404
+ parameterRangeGenericBindings: instance,
405
+ })), { value }, typeTypeValidator);
406
+ if (subConflictWrapped) {
407
+ return {
408
+ description: `invalid wrapped bindings for generic type instances for generic component extension of "${superComponent.value}"`,
409
+ context: { value, type },
410
+ causes: [subConflictWrapped],
411
+ };
412
+ }
413
+ // If the given generic type component scope applies to this component,
414
+ // Try to bind the generic instances from the parameter type-checking.
415
+ if (genericTypeInstancesComponentScope && genericTypeInstancesComponentScope.value === superComponent.value) {
416
+ const subConflictParam = genericsContextInner.bindComponentGenericTypes(superComponent, genericTypeInstances, { value }, typeTypeValidator);
417
+ if (subConflictParam) {
418
+ return {
419
+ description: `invalid parameter bindings for generic type instances for generic component extension of "${superComponent.value}"`,
420
+ context: { value, type },
421
+ causes: [subConflictParam],
422
+ };
423
+ }
424
+ // Extract the bound generic instances from the inner context into the actual context.
425
+ // This is needed for cases where param generics are bound via a wrapped generic component instantiation.
426
+ for (const [i, genericTypeInstance] of genericTypeInstances.entries()) {
427
+ const innerGenericType = genericTypeInstancesComponentScope.properties.genericTypeParameters[i].value;
428
+ if (genericTypeInstance.isA('ParameterRangeGenericTypeReference')) {
429
+ // If the generic type instance refers to another generic,
430
+ // bind it to the corresponding value of the inner context
431
+ const outerGenericType = genericTypeInstance.property.parameterRangeGenericType.value;
432
+ genericsContext.bindings[outerGenericType] = genericsContextInner.bindings[innerGenericType];
433
+ }
434
+ else if (!genericsContextInner.mergeRanges(genericsContextInner.bindings[innerGenericType], genericTypeInstance, typeTypeValidator)) {
435
+ // If the generic type instance is just a type, check it against the value in the inner context.
436
+ // If it does not match, return an error.
437
+ return {
438
+ description: `invalid binding for generic type <${innerGenericType}> in generic component extension of "${superComponent.value}": existing range "${ParameterPropertyHandlerRange.rangeToDisplayString(genericsContextInner.bindings[innerGenericType], genericsContextInner)}" can not be bound to range "${ParameterPropertyHandlerRange.rangeToDisplayString(genericTypeInstance, genericsContextInner)}"`,
439
+ context: { value, type },
440
+ };
441
+ }
442
+ }
443
+ }
444
+ return;
445
+ }
446
+ return {
447
+ description: `value is not a subtype of the referenced component in the generic component extension of "${valueSuperType.property.component.value}"`,
448
+ context: { value, type },
449
+ causes: [hasTypeConflict],
450
+ };
451
+ }
452
+ // The default case just checks the super type recursively.
453
+ const subConflictType = this.hasType(valueSuperType, type, genericsContext, genericTypeInstancesComponentScope, genericTypeInstances, errorContext);
454
+ if (!subConflictType) {
455
+ return;
456
+ }
457
+ subConflictTypes.push(subConflictType);
458
+ }
459
+ return Object.assign({ description: `value is not a subtype of "${type.value}"`, context: { value, type } }, subConflictTypes.length > 0 ? { causes: subConflictTypes } : {});
460
+ }
461
+ static rangeToDisplayString(paramRange, genericsContext) {
462
+ if (!paramRange || paramRange.isA('ParameterRangeWildcard')) {
176
463
  return `any`;
177
464
  }
178
465
  if (paramRange.isA('ParameterRangeUndefined')) {
179
466
  return `undefined`;
180
467
  }
181
468
  if (paramRange.isA('ParameterRangeArray')) {
182
- return `${this.rangeToDisplayString(paramRange.property.parameterRangeValue)}[]`;
469
+ return `${ParameterPropertyHandlerRange.rangeToDisplayString(paramRange.property.parameterRangeValue, genericsContext)}[]`;
183
470
  }
184
471
  if (paramRange.isA('ParameterRangeRest')) {
185
- return `...${this.rangeToDisplayString(paramRange.property.parameterRangeValue)}`;
472
+ return `...${ParameterPropertyHandlerRange.rangeToDisplayString(paramRange.property.parameterRangeValue, genericsContext)}`;
473
+ }
474
+ if (paramRange.isA('ParameterRangeKeyof')) {
475
+ return `keyof ${ParameterPropertyHandlerRange.rangeToDisplayString(paramRange.property.parameterRangeValue, genericsContext)}`;
186
476
  }
187
477
  if (paramRange.isA('ParameterRangeUnion')) {
188
478
  return paramRange.properties.parameterRangeElements
189
- .map(child => this.rangeToDisplayString(child))
479
+ .map(child => ParameterPropertyHandlerRange.rangeToDisplayString(child, genericsContext))
190
480
  .join(' | ');
191
481
  }
192
482
  if (paramRange.isA('ParameterRangeIntersection')) {
193
483
  return paramRange.properties.parameterRangeElements
194
- .map(child => this.rangeToDisplayString(child))
484
+ .map(child => ParameterPropertyHandlerRange.rangeToDisplayString(child, genericsContext))
195
485
  .join(' & ');
196
486
  }
197
487
  if (paramRange.isA('ParameterRangeTuple')) {
198
488
  return `[${paramRange.properties.parameterRangeElements
199
- .map(child => this.rangeToDisplayString(child))
489
+ .map(child => ParameterPropertyHandlerRange.rangeToDisplayString(child, genericsContext))
200
490
  .join(', ')}]`;
201
491
  }
202
492
  if (paramRange.isA('ParameterRangeLiteral')) {
203
493
  return paramRange.property.parameterRangeValue.value;
204
494
  }
495
+ if (paramRange.isA('ParameterRangeGenericTypeReference')) {
496
+ const valid = paramRange.property.parameterRangeGenericType.value in genericsContext.genericTypeIds;
497
+ return `${valid ? 'GENERIC: ' : 'UNKNOWN GENERIC: '}${paramRange.property.parameterRangeGenericType.value}`;
498
+ }
499
+ if (paramRange.isA('ParameterRangeGenericComponent')) {
500
+ return `(${ParameterPropertyHandlerRange.rangeToDisplayString(paramRange.property.component, genericsContext)})<${paramRange.properties.genericTypeInstances
501
+ .map(genericTypeInstance => ParameterPropertyHandlerRange.rangeToDisplayString(genericTypeInstance, genericsContext)).join(', ')}>`;
502
+ }
503
+ if (paramRange.isA('ParameterRangeIndexed')) {
504
+ const object = ParameterPropertyHandlerRange
505
+ .rangeToDisplayString(paramRange.property.parameterRangeIndexedObject, genericsContext);
506
+ const index = ParameterPropertyHandlerRange
507
+ .rangeToDisplayString(paramRange.property.parameterRangeIndexedIndex, genericsContext);
508
+ return `${object}[${index}]`;
509
+ }
205
510
  return paramRange.value;
206
511
  }
207
512
  }
@@ -1,19 +1,16 @@
1
- import type { Resource } from 'rdf-object';
1
+ import { Resource } from 'rdf-object';
2
+ import type { IParamValueConflict } from '../preprocess/parameterproperty/ParameterPropertyHandlerRange';
2
3
  /**
3
4
  * An error that can include a context containing resources for display.
4
5
  */
5
6
  export declare class ErrorResourcesContext extends Error {
6
- readonly context: Record<string, Resource | Resource[] | string>;
7
- constructor(message: string, context: Record<string, Resource | Resource[] | string>);
8
- static contextToString(context: Record<string, Resource | Resource[] | string>): string;
9
- /**
10
- * Convert the given resource to a compact string.
11
- * Mainly used for error reporting.
12
- *
13
- * Note that this will remove certain fields from the resource,
14
- * so only use this when throwing an error that will stop the process.
15
- *
16
- * @param resource A resource.
17
- */
18
- static resourceToString(resource: Resource): string;
7
+ readonly context: IErrorContext;
8
+ constructor(message: string, context: IErrorContext);
9
+ exportContext(): any;
10
+ static contextToJson(context: IErrorContext): any;
11
+ static resourceToJson(resource: Resource | undefined): any;
12
+ static conflictToJson(conflict: IParamValueConflict): any;
13
+ }
14
+ export interface IErrorContext {
15
+ [key: string]: Resource | Resource[] | string | undefined | IErrorContext | IParamValueConflict;
19
16
  }