componentsjs 5.0.0-beta.2 → 5.0.0-beta.6

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.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GenericsContext = void 0;
4
+ const ParameterPropertyHandlerRange_1 = require("./parameterproperty/ParameterPropertyHandlerRange");
4
5
  /**
5
6
  * Context for binding generic types to a concrete range value.
6
7
  */
@@ -12,7 +13,7 @@ class GenericsContext {
12
13
  this.bindings = {};
13
14
  for (const genericTypeParameter of genericTypeParameters) {
14
15
  if (genericTypeParameter.property.range) {
15
- this.bindings[genericTypeParameter.value] = genericTypeParameter.properties.range;
16
+ this.bindings[genericTypeParameter.value] = genericTypeParameter.property.range;
16
17
  }
17
18
  }
18
19
  }
@@ -20,27 +21,68 @@ class GenericsContext {
20
21
  * Try to to bind the given value to the given generic.
21
22
  * @param genericTypeId IRI of the generic to bind.
22
23
  * @param value The value to bind to.
23
- * @param typeValidator Callback for validating values against types.
24
+ * @param valueTypeValidator Callback for validating values against types.
25
+ * @param typeTypeValidator Callback for validating sub-types against super-types.
26
+ * @return boolean True if the binding was valid and took place.
24
27
  */
25
- bindGenericTypeToValue(genericTypeId, value, typeValidator) {
28
+ bindGenericTypeToValue(genericTypeId, value, valueTypeValidator, typeTypeValidator) {
26
29
  // Fail if an unknown generic type is referenced
27
30
  if (!(genericTypeId in this.genericTypeIds)) {
28
- return false;
31
+ return {
32
+ description: `unknown generic <${genericTypeId}> is being referenced`,
33
+ context: { value },
34
+ };
29
35
  }
30
36
  // If the generic was already bound to a range, validate it
31
37
  const existingRange = this.bindings[genericTypeId];
32
- if (existingRange && existingRange.some(existingRangeElement => !typeValidator(value, existingRangeElement))) {
33
- return false;
38
+ if (existingRange) {
39
+ const subConflict = valueTypeValidator(value, existingRange);
40
+ if (subConflict) {
41
+ return {
42
+ description: `generic <${genericTypeId}> with existing range "${ParameterPropertyHandlerRange_1.ParameterPropertyHandlerRange.rangeToDisplayString(existingRange, this)}" can not contain the given value`,
43
+ context: { existingRange, value },
44
+ causes: [subConflict],
45
+ };
46
+ }
34
47
  }
35
48
  // Infer type of value
36
49
  const valueRange = this.inferValueRange(value);
37
- if (valueRange.length > 0) {
38
- // If we already had a range, try to align them
39
- // TODO: this will be needed for resources with common inheritance hierarchies
40
- // Save inferred type
41
- this.bindings[genericTypeId] = valueRange;
50
+ if (!valueRange) {
51
+ return;
42
52
  }
43
- return true;
53
+ // Save inferred type
54
+ return this.bindGenericTypeToRange(genericTypeId, valueRange, typeTypeValidator);
55
+ }
56
+ /**
57
+ * Try to bind the given range to the given generic.
58
+ * @param genericTypeId IRI of the generic to bind.
59
+ * @param range The range to bind to.
60
+ * @param typeTypeValidator Callback for validating sub-types against super-types.
61
+ * @return boolean True if the binding was valid and took place.
62
+ */
63
+ bindGenericTypeToRange(genericTypeId, range, typeTypeValidator) {
64
+ // Fail if an unknown generic type is referenced
65
+ if (!(genericTypeId in this.genericTypeIds)) {
66
+ return {
67
+ description: `unknown generic <${genericTypeId}> is being referenced`,
68
+ context: {},
69
+ };
70
+ }
71
+ // If we already had a range, check if they match
72
+ if (this.bindings[genericTypeId]) {
73
+ const mergedRange = this.mergeRanges(this.bindings[genericTypeId], range, typeTypeValidator);
74
+ if (!mergedRange) {
75
+ return {
76
+ description: `generic <${genericTypeId}> with existing range "${ParameterPropertyHandlerRange_1.ParameterPropertyHandlerRange.rangeToDisplayString(this.bindings[genericTypeId], this)}" can not be bound to range "${ParameterPropertyHandlerRange_1.ParameterPropertyHandlerRange.rangeToDisplayString(range, this)}"`,
77
+ context: {
78
+ existingRange: this.bindings[genericTypeId],
79
+ newRange: range,
80
+ },
81
+ };
82
+ }
83
+ range = mergedRange;
84
+ }
85
+ this.bindings[genericTypeId] = range;
44
86
  }
45
87
  /**
46
88
  * Infer the parameter range of the given value.
@@ -49,15 +91,238 @@ class GenericsContext {
49
91
  inferValueRange(value) {
50
92
  // Value is undefined
51
93
  if (!value) {
52
- return [this.objectLoader.createCompactedResource({ type: 'ParameterRangeUndefined' })];
94
+ return this.objectLoader.createCompactedResource({ '@type': 'ParameterRangeUndefined' });
53
95
  }
54
96
  // Value is a literal
55
97
  if (value.term.termType === 'Literal') {
56
- return [this.objectLoader.createCompactedResource(value.term.datatype)];
98
+ return this.objectLoader.createCompactedResource(value.term.datatype);
57
99
  }
58
100
  // Value is a named node
59
- return value.properties.type;
101
+ const types = value.properties.type;
102
+ if (types.length > 1) {
103
+ return this.objectLoader.createCompactedResource({
104
+ '@type': 'ParameterRangeUnion',
105
+ parameterRangeElements: types,
106
+ });
107
+ }
108
+ return types[0];
109
+ }
110
+ /**
111
+ * Merge the given ranges into a new range.
112
+ * This will return undefined in the ranges are incompatible.
113
+ *
114
+ * If one type is more specific than the other, it will return the narrowest type.
115
+ *
116
+ * @param rangeA A first range.
117
+ * @param rangeB A second range.
118
+ * @param typeTypeValidator Callback for validating sub-types against super-types.
119
+ */
120
+ mergeRanges(rangeA, rangeB, typeTypeValidator) {
121
+ var _a, _b;
122
+ // Check if one is a subtype of the other (and return the most specific type)
123
+ if (!typeTypeValidator(rangeA, rangeB)) {
124
+ return rangeA;
125
+ }
126
+ if (!typeTypeValidator(rangeB, rangeA)) {
127
+ return rangeB;
128
+ }
129
+ // Check XSD inheritance relationship
130
+ if (this.isXsdSubType(rangeA.term, rangeB.term)) {
131
+ return rangeA;
132
+ }
133
+ if (this.isXsdSubType(rangeB.term, rangeA.term)) {
134
+ return rangeB;
135
+ }
136
+ // If a range is a wildcard, return the other type
137
+ if (rangeA.isA('ParameterRangeWildcard')) {
138
+ return rangeB;
139
+ }
140
+ if (rangeB.isA('ParameterRangeWildcard')) {
141
+ return rangeA;
142
+ }
143
+ // Ranges always match with generic references
144
+ if (rangeA.isA('ParameterRangeGenericTypeReference')) {
145
+ return rangeB;
146
+ }
147
+ if (rangeB.isA('ParameterRangeGenericTypeReference')) {
148
+ return rangeA;
149
+ }
150
+ // Check parameter range types
151
+ if ((_a = rangeA.property.type) === null || _a === void 0 ? void 0 : _a.term.equals((_b = rangeB.property.type) === null || _b === void 0 ? void 0 : _b.term)) {
152
+ // Check sub-value for specific param range cases
153
+ if (rangeA.isA('ParameterRangeArray') ||
154
+ rangeA.isA('ParameterRangeRest') ||
155
+ rangeA.isA('ParameterRangeKeyof')) {
156
+ const valueA = rangeA.property.parameterRangeValue;
157
+ const valueB = rangeB.property.parameterRangeValue;
158
+ const merged = this.mergeRanges(valueA, valueB, typeTypeValidator);
159
+ if (!merged) {
160
+ return;
161
+ }
162
+ return this.objectLoader.createCompactedResource({
163
+ '@type': rangeA.property.type,
164
+ parameterRangeValue: merged,
165
+ });
166
+ }
167
+ // Check sub-values for specific param range cases
168
+ if (rangeA.isA('ParameterRangeUnion') ||
169
+ rangeA.isA('ParameterRangeIntersection') ||
170
+ rangeA.isA('ParameterRangeTuple')) {
171
+ const valuesA = rangeA.properties.parameterRangeElements;
172
+ const valuesB = rangeB.properties.parameterRangeElements;
173
+ if (valuesA.length !== valuesB.length) {
174
+ return;
175
+ }
176
+ const merged = valuesA.map((valueA, i) => this.mergeRanges(valueA, valuesB[i], typeTypeValidator));
177
+ if (merged.some(subValue => !subValue)) {
178
+ return;
179
+ }
180
+ return this.objectLoader.createCompactedResource({
181
+ '@type': rangeA.property.type,
182
+ parameterRangeElements: merged,
183
+ });
184
+ }
185
+ // Check sub-values for generic components
186
+ if (rangeA.isA('ParameterRangeGenericComponent')) {
187
+ const mergedComponent = this.mergeRanges(rangeA.property.component, rangeB.property.component, typeTypeValidator);
188
+ if (!mergedComponent) {
189
+ return;
190
+ }
191
+ const valuesA = rangeA.properties.genericTypeInstances;
192
+ const valuesB = rangeB.properties.genericTypeInstances;
193
+ if (valuesA.length !== valuesB.length) {
194
+ return;
195
+ }
196
+ const merged = valuesA.map((valueA, i) => this.mergeRanges(valueA, valuesB[i], typeTypeValidator));
197
+ if (merged.some(subValue => !subValue)) {
198
+ return;
199
+ }
200
+ return this.objectLoader.createCompactedResource({
201
+ '@type': 'ParameterRangeGenericComponent',
202
+ component: mergedComponent,
203
+ genericTypeInstances: merged,
204
+ });
205
+ }
206
+ return rangeA;
207
+ }
208
+ // Handle left or right being a union
209
+ if (rangeA.isA('ParameterRangeUnion')) {
210
+ return this.mergeUnion(rangeA, rangeB, typeTypeValidator);
211
+ }
212
+ if (rangeB.isA('ParameterRangeUnion')) {
213
+ return this.mergeUnion(rangeB, rangeA, typeTypeValidator);
214
+ }
215
+ // Check if the range refers to a component with a generic type
216
+ // TODO: somehow pass the range's component and genericTypeInstances (like in ParameterPropertyHandlerRange)?
217
+ if (rangeA.isA('ParameterRangeGenericComponent')) {
218
+ return this.mergeRanges(rangeA.property.component, rangeB, typeTypeValidator);
219
+ }
220
+ if (rangeB.isA('ParameterRangeGenericComponent')) {
221
+ return this.mergeRanges(rangeB.property.component, rangeA, typeTypeValidator);
222
+ }
223
+ }
224
+ mergeUnion(rangeUnion, rangeOther, typeValidator) {
225
+ const elements = rangeUnion.properties.parameterRangeElements;
226
+ const mergedValues = elements
227
+ .map(element => this.mergeRanges(rangeOther, element, typeValidator))
228
+ .filter(Boolean);
229
+ if (mergedValues.length === 0) {
230
+ return;
231
+ }
232
+ if (mergedValues.length === 1) {
233
+ return mergedValues[0];
234
+ }
235
+ return this.objectLoader.createCompactedResource({
236
+ '@type': 'ParameterRangeUnion',
237
+ parameterRangeElements: mergedValues,
238
+ });
239
+ }
240
+ /**
241
+ * Check if the given type is a subtype of the given super type.
242
+ * @param type A type node.
243
+ * @param potentialSuperType A potential super type node.
244
+ */
245
+ isXsdSubType(type, potentialSuperType) {
246
+ const values = GenericsContext.XSD_INHERITANCE_TABLE[potentialSuperType.value];
247
+ return values && values.has(type.value);
248
+ }
249
+ /**
250
+ * Apply the give generic type instances for the given component's generic type parameters.
251
+ *
252
+ * This will throw if the number of passed instances does not match with
253
+ * the number of generic type parameters on the component.
254
+ *
255
+ * @param component The component
256
+ * @param genericTypeInstances The generic type instances to apply.
257
+ * @param errorContext The context for error reporting.
258
+ * @param typeTypeValidator Callback for validating sub-types against super-types.
259
+ * @return boolean False if the application failed due to a binding error. True otherwise
260
+ */
261
+ bindComponentGenericTypes(component, genericTypeInstances, errorContext, typeTypeValidator) {
262
+ const genericTypeParameters = component.properties.genericTypeParameters;
263
+ // Don't do anything if no generic type instances are passed.
264
+ if (genericTypeInstances.length === 0) {
265
+ return {
266
+ description: `no generic type instances are passed`,
267
+ context: errorContext,
268
+ };
269
+ }
270
+ // Throw if an unexpected number of generic type instances are passed.
271
+ if (genericTypeParameters.length !== genericTypeInstances.length) {
272
+ return {
273
+ description: `Invalid generic type instantiation: a different amount of generic types are passed (${genericTypeInstances.length}) than are defined on the component (${genericTypeParameters.length}).`,
274
+ context: Object.assign({ passedGenerics: genericTypeInstances, definedGenerics: genericTypeParameters, component }, errorContext),
275
+ };
276
+ }
277
+ // Populate with manually defined generic type bindings
278
+ for (const [i, genericTypeInstance] of genericTypeInstances.entries()) {
279
+ // Remap generic type IRI to inner generic type IRI
280
+ const genericTypeIdInner = genericTypeParameters[i].value;
281
+ if (genericTypeInstance.property.parameterRangeGenericBindings) {
282
+ const subConflict = this.bindGenericTypeToRange(genericTypeIdInner, genericTypeInstance.property.parameterRangeGenericBindings, typeTypeValidator);
283
+ if (subConflict) {
284
+ return {
285
+ description: `invalid binding for generic <${genericTypeIdInner}>`,
286
+ context: errorContext,
287
+ causes: [subConflict],
288
+ };
289
+ }
290
+ }
291
+ this.genericTypeIds[genericTypeIdInner] = true;
292
+ }
60
293
  }
61
294
  }
62
295
  exports.GenericsContext = GenericsContext;
296
+ GenericsContext.XSD_INHERITANCE_TABLE = {
297
+ 'http://www.w3.org/2001/XMLSchema#number': new Set([
298
+ 'http://www.w3.org/2001/XMLSchema#integer',
299
+ 'http://www.w3.org/2001/XMLSchema#long',
300
+ 'http://www.w3.org/2001/XMLSchema#int',
301
+ 'http://www.w3.org/2001/XMLSchema#byte',
302
+ 'http://www.w3.org/2001/XMLSchema#short',
303
+ 'http://www.w3.org/2001/XMLSchema#negativeInteger',
304
+ 'http://www.w3.org/2001/XMLSchema#nonNegativeInteger',
305
+ 'http://www.w3.org/2001/XMLSchema#nonPositiveInteger',
306
+ 'http://www.w3.org/2001/XMLSchema#positiveInteger',
307
+ 'http://www.w3.org/2001/XMLSchema#unsignedByte',
308
+ 'http://www.w3.org/2001/XMLSchema#unsignedInt',
309
+ 'http://www.w3.org/2001/XMLSchema#unsignedLong',
310
+ 'http://www.w3.org/2001/XMLSchema#unsignedShort',
311
+ 'http://www.w3.org/2001/XMLSchema#double',
312
+ 'http://www.w3.org/2001/XMLSchema#decimal',
313
+ 'http://www.w3.org/2001/XMLSchema#float',
314
+ ]),
315
+ 'http://www.w3.org/2001/XMLSchema#string': new Set([
316
+ 'http://www.w3.org/2001/XMLSchema#normalizedString',
317
+ 'http://www.w3.org/2001/XMLSchema#anyURI',
318
+ 'http://www.w3.org/2001/XMLSchema#base64Binary',
319
+ 'http://www.w3.org/2001/XMLSchema#language',
320
+ 'http://www.w3.org/2001/XMLSchema#Name',
321
+ 'http://www.w3.org/2001/XMLSchema#NCName',
322
+ 'http://www.w3.org/2001/XMLSchema#NMTOKEN',
323
+ 'http://www.w3.org/2001/XMLSchema#token',
324
+ 'http://www.w3.org/2001/XMLSchema#hexBinary',
325
+ 'http://www.w3.org/2001/XMLSchema#langString',
326
+ ]),
327
+ };
63
328
  //# sourceMappingURL=GenericsContext.js.map
@@ -1,11 +1,13 @@
1
1
  import type { RdfObjectLoader, Resource } from 'rdf-object';
2
2
  import type { GenericsContext } from './GenericsContext';
3
+ import { ParameterPropertyHandlerRange } from './parameterproperty/ParameterPropertyHandlerRange';
3
4
  /**
4
5
  * Handles component parameters in the context of a config.
5
6
  */
6
7
  export declare class ParameterHandler {
7
8
  private readonly objectLoader;
8
9
  private readonly parameterPropertyHandlers;
10
+ readonly parameterPropertyHandlerRange: ParameterPropertyHandlerRange;
9
11
  constructor(options: IParameterHandlerOptions);
10
12
  /**
11
13
  * Obtain the values of the given parameter in the context of the given config.
@@ -19,4 +21,5 @@ export declare class ParameterHandler {
19
21
  }
20
22
  export interface IParameterHandlerOptions {
21
23
  objectLoader: RdfObjectLoader;
24
+ typeChecking: boolean;
22
25
  }
@@ -17,7 +17,7 @@ class ParameterHandler {
17
17
  new ParameterPropertyHandlerDefaultScoped_1.ParameterPropertyHandlerDefaultScoped(this.objectLoader),
18
18
  new ParameterPropertyHandlerDefault_1.ParameterPropertyHandlerDefault(this.objectLoader),
19
19
  new ParameterPropertyHandlerFixed_1.ParameterPropertyHandlerFixed(this.objectLoader),
20
- new ParameterPropertyHandlerRange_1.ParameterPropertyHandlerRange(this.objectLoader),
20
+ this.parameterPropertyHandlerRange = new ParameterPropertyHandlerRange_1.ParameterPropertyHandlerRange(this.objectLoader, options.typeChecking),
21
21
  new ParameterPropertyHandlerLazy_1.ParameterPropertyHandlerLazy(),
22
22
  ];
23
23
  }
@@ -38,7 +38,7 @@ class ParameterHandler {
38
38
  }
39
39
  else if (values.length > 0) {
40
40
  if (values.some(subValue => !subValue.list)) {
41
- throw new ErrorResourcesContext_1.ErrorResourcesContext(`Detected multiple values for parameter ${parameter.value}. RDF lists should be used for defining multiple values.`, {
41
+ throw new ErrorResourcesContext_1.ErrorResourcesContext(`Detected multiple values for parameter ${parameter.value} in ${configElement.value}. RDF lists should be used for defining multiple values.`, {
42
42
  arguments: values,
43
43
  });
44
44
  }
@@ -1,12 +1,14 @@
1
1
  import type { RdfObjectLoader, Resource } from 'rdf-object';
2
- import type { GenericsContext } from '../GenericsContext';
2
+ import type { IErrorContext } from '../../util/ErrorResourcesContext';
3
+ import { GenericsContext } from '../GenericsContext';
3
4
  import type { IParameterPropertyHandler } from './IParameterPropertyHandler';
4
5
  /**
5
6
  * If a param range is defined, apply the type and validate the range.
6
7
  */
7
8
  export declare class ParameterPropertyHandlerRange implements IParameterPropertyHandler {
8
9
  private readonly objectLoader;
9
- constructor(objectLoader: RdfObjectLoader);
10
+ private readonly typeChecking;
11
+ constructor(objectLoader: RdfObjectLoader, typeChecking: boolean);
10
12
  canHandle(value: Resource | undefined, configRoot: Resource, parameter: Resource): boolean;
11
13
  handle(value: Resource | undefined, configRoot: Resource, parameter: Resource, configElement: Resource, genericsContext: GenericsContext): Resource | undefined;
12
14
  /**
@@ -20,16 +22,35 @@ export declare class ParameterPropertyHandlerRange implements IParameterProperty
20
22
  */
21
23
  captureType(value: Resource | undefined, param: Resource, genericsContext: GenericsContext): Resource | undefined;
22
24
  /**
23
- * Apply the given datatype to the given literal.
24
- * Checks if the datatype is correct and casts to the correct js type.
25
- * Will throw an error if the type has an invalid value.
26
- * Will be ignored if the value is not a literal or the type is not recognized.
25
+ * Check if the given value is of the given type.
26
+ *
27
+ * For valid literals, the `valueRaw` field will be set.
28
+ *
27
29
  * @param value The value.
28
- * @param param The parameter.
29
- * @param paramRange The parameter's range.
30
+ * @param type The parameter's range.
30
31
  * @param genericsContext Context for generic types.
32
+ * @param errorContext The context for error reporting.
33
+ * @return IParamValueConflict A conflict value if there was an error, or undefined if there was no error
31
34
  */
32
- hasParamValueValidType(value: Resource | undefined, param: Resource, paramRange: Resource, genericsContext: GenericsContext): boolean;
33
- protected throwIncorrectTypeError(value: Resource | undefined, parameter: Resource, genericsContext: GenericsContext): never;
34
- rangeToDisplayString(paramRange: Resource | undefined, genericsContext: GenericsContext): string;
35
+ hasValueType(value: Resource | undefined, type: Resource | undefined, errorContext: IErrorContext, genericsContext: GenericsContext): IParamValueConflict | undefined;
36
+ static throwIncorrectTypeError(value: Resource | undefined, parameter: Resource, genericsContext: GenericsContext, conflict: IParamValueConflict): never;
37
+ /**
38
+ * Check if the given value is of the given type.
39
+ * @param value A value.
40
+ * @param type A type.
41
+ * @param genericsContext The current generics context.
42
+ * @param genericTypeInstancesComponentScope
43
+ * @param genericTypeInstances
44
+ * @param errorContext
45
+ */
46
+ hasType(value: Resource, type: Resource, genericsContext: GenericsContext, genericTypeInstancesComponentScope: Resource | undefined, genericTypeInstances: Resource[], errorContext: IErrorContext): IParamValueConflict | undefined;
47
+ static rangeToDisplayString(paramRange: Resource | undefined, genericsContext: GenericsContext): string;
48
+ }
49
+ /**
50
+ * Represents a conflict between a value and a type.
51
+ */
52
+ export interface IParamValueConflict {
53
+ description: string;
54
+ context: IErrorContext;
55
+ causes?: IParamValueConflict[];
35
56
  }