Skip to content

Commit 9be1fd0

Browse files
committed
Add causes for param check failures in error messages
1 parent 83bd1bc commit 9be1fd0

File tree

6 files changed

+387
-128
lines changed

6 files changed

+387
-128
lines changed

lib/preprocess/GenericsContext.ts

+44-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type * as RDF from '@rdfjs/types';
22
import type { Resource, RdfObjectLoader } from 'rdf-object';
33
import { ErrorResourcesContext } from '../util/ErrorResourcesContext';
4+
import type { IParamValueConflict } from './parameterproperty/ParameterPropertyHandlerRange';
5+
import { ParameterPropertyHandlerRange } from './parameterproperty/ParameterPropertyHandlerRange';
46

57
/**
68
* Context for binding generic types to a concrete range value.
@@ -74,23 +76,33 @@ export class GenericsContext {
7476
public bindGenericTypeToValue(
7577
genericTypeId: string,
7678
value: Resource | undefined,
77-
typeValidator: (subValue: Resource | undefined, subType: Resource) => boolean,
78-
): boolean {
79+
typeValidator: (subValue: Resource | undefined, subType: Resource) => IParamValueConflict | undefined,
80+
): IParamValueConflict | undefined {
7981
// Fail if an unknown generic type is referenced
8082
if (!(genericTypeId in this.genericTypeIds)) {
81-
return false;
83+
return {
84+
description: `unknown generic <${genericTypeId}> is being referenced`,
85+
context: { value },
86+
};
8287
}
8388

8489
// If the generic was already bound to a range, validate it
8590
const existingRange = this.bindings[genericTypeId];
86-
if (existingRange && !typeValidator(value, existingRange)) {
87-
return false;
91+
if (existingRange) {
92+
const subConflict = typeValidator(value, existingRange);
93+
if (subConflict) {
94+
return {
95+
description: `generic <${genericTypeId}> with existing range "${ParameterPropertyHandlerRange.rangeToDisplayString(existingRange, this)}" can not contain the given value`,
96+
context: { existingRange, value },
97+
causes: [ subConflict ],
98+
};
99+
}
88100
}
89101

90102
// Infer type of value
91103
const valueRange = this.inferValueRange(value);
92104
if (!valueRange) {
93-
return true;
105+
return;
94106
}
95107

96108
// Save inferred type
@@ -106,24 +118,31 @@ export class GenericsContext {
106118
public bindGenericTypeToRange(
107119
genericTypeId: string,
108120
range: Resource,
109-
): boolean {
121+
): IParamValueConflict | undefined {
110122
// Fail if an unknown generic type is referenced
111123
if (!(genericTypeId in this.genericTypeIds)) {
112-
return false;
124+
return {
125+
description: `unknown generic <${genericTypeId}> is being referenced`,
126+
};
113127
}
114128

115129
// If we already had a range, check if they match
116130
if (this.bindings[genericTypeId]) {
117131
const mergedRange = this.mergeRanges(this.bindings[genericTypeId], range);
118132
if (!mergedRange) {
119-
return false;
133+
return {
134+
description: `generic <${genericTypeId}> with existing range "${ParameterPropertyHandlerRange.rangeToDisplayString(this.bindings[genericTypeId], this)}" can not be bound to range "${ParameterPropertyHandlerRange.rangeToDisplayString(range, this)}"`,
135+
context: {
136+
existingRange: this.bindings[genericTypeId],
137+
newRange: range,
138+
},
139+
};
120140
}
121141

122142
range = mergedRange;
123143
}
124144

125145
this.bindings[genericTypeId] = range;
126-
return true;
127146
}
128147

129148
/**
@@ -249,12 +268,14 @@ export class GenericsContext {
249268
component: Resource,
250269
genericTypeInstances: Resource[],
251270
errorContext: Record<string, Resource | Resource[] | string>,
252-
): boolean {
271+
): IParamValueConflict | undefined {
253272
const genericTypeParameters = component.properties.genericTypeParameters;
254273

255274
// Don't do anything if no generic type instances are passed.
256275
if (genericTypeInstances.length === 0) {
257-
return false;
276+
return {
277+
description: `no generic type instances are passed`,
278+
};
258279
}
259280

260281
// Throw if an unexpected number of generic type instances are passed.
@@ -271,15 +292,19 @@ export class GenericsContext {
271292
for (const [ i, genericTypeInstance ] of genericTypeInstances.entries()) {
272293
// Remap generic type IRI to inner generic type IRI
273294
const genericTypeIdInner = genericTypeParameters[i].value;
274-
if (genericTypeInstance.property.parameterRangeGenericBindings && !this.bindGenericTypeToRange(
275-
genericTypeIdInner,
276-
genericTypeInstance.property.parameterRangeGenericBindings,
277-
)) {
278-
return false;
295+
if (genericTypeInstance.property.parameterRangeGenericBindings) {
296+
const subConflict = this.bindGenericTypeToRange(
297+
genericTypeIdInner,
298+
genericTypeInstance.property.parameterRangeGenericBindings,
299+
);
300+
if (subConflict) {
301+
return {
302+
description: `invalid binding for generic <${genericTypeIdInner}>`,
303+
causes: [ subConflict ],
304+
};
305+
}
279306
}
280307
this.genericTypeIds[genericTypeIdInner] = true;
281308
}
282-
283-
return true;
284309
}
285310
}

0 commit comments

Comments
 (0)