Skip to content

Commit 0f55ba0

Browse files
committed
Handle keyof parameter ranges
1 parent 4359e2a commit 0f55ba0

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

components/context.jsonld

+9
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
"parameters": {
3030
"@id": "oo:parameter"
3131
},
32+
"memberKeys": {
33+
"@id": "oo:memberKey"
34+
},
3235
"genericTypeParameters": {
3336
"@id": "oo:genericTypeParameter"
3437
},
@@ -77,6 +80,12 @@
7780
"ParameterRangeArray": {
7881
"@id": "oo:ParameterRangeArray"
7982
},
83+
"ParameterRangeRest": {
84+
"@id": "oo:ParameterRangeRest"
85+
},
86+
"ParameterRangeKeyof": {
87+
"@id": "oo:ParameterRangeKeyof"
88+
},
8089
"ParameterRangeLiteral": {
8190
"@id": "oo:ParameterRangeLiteral"
8291
},

lib/preprocess/parameterproperty/ParameterPropertyHandlerRange.ts

+17
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,20 @@ export class ParameterPropertyHandlerRange implements IParameterPropertyHandler
190190
return Boolean(value && value.term.equals(paramRange.property.parameterRangeValue.term));
191191
}
192192

193+
// Check if the range refers to `keyof ...`
194+
if (paramRange.isA('ParameterRangeKeyof')) {
195+
const component = paramRange.property.parameterRangeValue;
196+
// Simulate a union of the member keys as literal parameter ranges
197+
const simulatedUnionRange = this.objectLoader.createCompactedResource({
198+
'@type': 'ParameterRangeUnion',
199+
parameterRangeElements: component.properties.memberKeys.map(memberKey => ({
200+
'@type': 'ParameterRangeLiteral',
201+
parameterRangeValue: memberKey,
202+
})),
203+
});
204+
return this.hasParamValueValidType(value, param, simulatedUnionRange, genericsContext);
205+
}
206+
193207
// Check if the range refers to a generic type
194208
if (paramRange.isA('ParameterRangeGenericTypeReference')) {
195209
return genericsContext.bindGenericTypeToValue(
@@ -263,6 +277,9 @@ export class ParameterPropertyHandlerRange implements IParameterPropertyHandler
263277
if (paramRange.isA('ParameterRangeRest')) {
264278
return `...${this.rangeToDisplayString(paramRange.property.parameterRangeValue, genericsContext)}`;
265279
}
280+
if (paramRange.isA('ParameterRangeKeyof')) {
281+
return `keyof ${this.rangeToDisplayString(paramRange.property.parameterRangeValue, genericsContext)}`;
282+
}
266283
if (paramRange.isA('ParameterRangeUnion')) {
267284
return paramRange.properties.parameterRangeElements
268285
.map(child => this.rangeToDisplayString(child, genericsContext))

test/unit/preprocess/parameterproperty/ParameterPropertyHandlerRange-test.ts

+33
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,39 @@ describe('ParameterPropertyHandlerRange', () => {
13061306
// eslint-disable-next-line max-len
13071307
)).toThrow(/^Simultaneous manual generic type passing and generic type inference are not supported yet\./u);
13081308
});
1309+
1310+
it('should handle keyof type with valid value', () => {
1311+
expect(handler.captureType(
1312+
objectLoader.createCompactedResource('"fieldB"'),
1313+
objectLoader.createCompactedResource({
1314+
range: {
1315+
'@type': 'ParameterRangeKeyof',
1316+
parameterRangeValue: {
1317+
'@id': 'ex:SomeType1',
1318+
memberKeys: [ '"fieldA"', '"fieldB"' ],
1319+
},
1320+
},
1321+
}),
1322+
genericsContext,
1323+
)).toBeTruthy();
1324+
});
1325+
1326+
it('should throw on keyof type without valid value', () => {
1327+
expect(() => handler.captureType(
1328+
objectLoader.createCompactedResource('"fieldC"'),
1329+
objectLoader.createCompactedResource({
1330+
range: {
1331+
'@type': 'ParameterRangeKeyof',
1332+
parameterRangeValue: {
1333+
'@id': 'ex:SomeType1',
1334+
memberKeys: [ '"fieldA"', '"fieldB"' ],
1335+
},
1336+
},
1337+
}),
1338+
genericsContext,
1339+
// eslint-disable-next-line max-len
1340+
)).toThrow(/^The value "fieldC" for parameter ".*" is not of required range type "keyof ex:SomeType1"/u);
1341+
});
13091342
});
13101343
});
13111344

0 commit comments

Comments
 (0)