componentsjs 5.0.0-beta.1 → 5.0.0-beta.5

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