Skip to content

Commit 3501a0f

Browse files
committed
Accept RDF lists as argument values, #47
1 parent aedd53a commit 3501a0f

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './lib/construction/argument/ArgumentConstructorHandlerArray';
22
export * from './lib/construction/argument/ArgumentConstructorHandlerHash';
3+
export * from './lib/construction/argument/ArgumentConstructorHandlerList';
34
export * from './lib/construction/argument/ArgumentConstructorHandlerPrimitive';
45
export * from './lib/construction/argument/ArgumentConstructorHandlerReference';
56
export * from './lib/construction/argument/ArgumentConstructorHandlerUndefined';

lib/construction/ConfigConstructor.ts

+12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { IModuleState } from '../loading/ModuleStateBuilder';
33
import { ErrorResourcesContext } from '../util/ErrorResourcesContext';
44
import { ArgumentConstructorHandlerArray } from './argument/ArgumentConstructorHandlerArray';
55
import { ArgumentConstructorHandlerHash } from './argument/ArgumentConstructorHandlerHash';
6+
import { ArgumentConstructorHandlerList } from './argument/ArgumentConstructorHandlerList';
67
import { ArgumentConstructorHandlerPrimitive } from './argument/ArgumentConstructorHandlerPrimitive';
78
import { ArgumentConstructorHandlerReference } from './argument/ArgumentConstructorHandlerReference';
89
import { ArgumentConstructorHandlerUndefined } from './argument/ArgumentConstructorHandlerUndefined';
@@ -32,6 +33,7 @@ export class ConfigConstructor<Instance> implements IArgumentsConstructor<Instan
3233
new ArgumentConstructorHandlerUndefined(),
3334
new ArgumentConstructorHandlerHash(),
3435
new ArgumentConstructorHandlerArray(),
36+
new ArgumentConstructorHandlerList(),
3537
new ArgumentConstructorHandlerValue(),
3638
new ArgumentConstructorHandlerReference(),
3739
new ArgumentConstructorHandlerPrimitive(),
@@ -58,6 +60,16 @@ export class ConfigConstructor<Instance> implements IArgumentsConstructor<Instan
5860
return this.getArgumentValue(values[0], settings);
5961
}
6062

63+
// Unwrap RDF list-based values out of the array
64+
if (values.length > 0 && values.some(value => value.list)) {
65+
if (values.length > 1) {
66+
throw new ErrorResourcesContext(`Detected multiple values for an argument while only a single RDF list is allowed`, {
67+
arguments: values.flatMap(value => value.list ? value.list : [ value ]),
68+
});
69+
}
70+
return this.getArgumentValue(values[0], settings);
71+
}
72+
6173
// Otherwise, keep the array form
6274
const elements = await Promise.all(values.map(element => this.getArgumentValue(element, settings)));
6375
return this.constructionStrategy.createArray({ settings, elements });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { Resource } from 'rdf-object';
2+
import type { IConstructionSettings } from '../IConstructionSettings';
3+
import type { IArgumentConstructorHandler } from './IArgumentConstructorHandler';
4+
import type { IArgumentsConstructor } from './IArgumentsConstructor';
5+
6+
/**
7+
* Handles arguments with RDF list values.
8+
*/
9+
export class ArgumentConstructorHandlerList implements IArgumentConstructorHandler {
10+
public canHandle<Instance>(
11+
value: Resource,
12+
settings: IConstructionSettings,
13+
argsCreator: IArgumentsConstructor<Instance>,
14+
): boolean {
15+
return Boolean(value.list);
16+
}
17+
18+
public async handle<Instance>(
19+
argument: Resource,
20+
settings: IConstructionSettings,
21+
argsCreator: IArgumentsConstructor<Instance>,
22+
): Promise<Instance> {
23+
// Recursively handle all sub-args in the list
24+
const elements = await Promise.all(argument.list!
25+
.map((entry: Resource) => argsCreator.getArgumentValue(entry, settings)));
26+
27+
return argsCreator.constructionStrategy.createArray({ settings, elements });
28+
}
29+
}

test/unit/construction/ConfigConstructor-test.ts

+75
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,39 @@ describe('ConfigConstructor', () => {
101101
expect(constructionStrategy.createPrimitive).toHaveBeenCalledWith({ settings, value: 'DEF' });
102102
expect(constructionStrategy.createPrimitive).toHaveBeenCalledWith({ settings, value: 'GHI' });
103103
});
104+
105+
it('should handle an RDF list', async() => {
106+
const values = [
107+
objectLoader.createCompactedResource({
108+
list: [
109+
'"ABC"',
110+
'"DEF"',
111+
'"GHI"',
112+
],
113+
}),
114+
];
115+
expect(await constructor.getArgumentValues(values, settings)).toEqual([
116+
'ABC',
117+
'DEF',
118+
'GHI',
119+
]);
120+
expect(constructionStrategy.createArray).toHaveBeenCalledWith({ settings, elements: [ 'ABC', 'DEF', 'GHI' ]});
121+
});
122+
123+
it('should throw on an RDF list and anything else', async() => {
124+
const values = [
125+
objectLoader.createCompactedResource({
126+
list: [
127+
'"ABC"',
128+
'"DEF"',
129+
'"GHI"',
130+
],
131+
}),
132+
objectLoader.createCompactedResource('"ABC"'),
133+
];
134+
await expect(constructor.getArgumentValues(values, settings)).rejects
135+
.toThrowError(`Detected multiple values for an argument while only a single RDF list is allowed`);
136+
});
104137
});
105138

106139
describe('getArgumentValue', () => {
@@ -308,6 +341,48 @@ describe('ConfigConstructor', () => {
308341
});
309342
});
310343

344+
describe('for RDF lists', () => {
345+
it('should handle one element', async() => {
346+
const resource = objectLoader.createCompactedResource({
347+
list: [
348+
'"ABC"',
349+
],
350+
});
351+
expect(await constructor.getArgumentValue(resource, settings)).toEqual([
352+
'ABC',
353+
]);
354+
expect(constructionStrategy.createArray).toHaveBeenCalledWith({
355+
settings,
356+
elements: [
357+
'ABC',
358+
],
359+
});
360+
});
361+
362+
it('should handle multiple elements', async() => {
363+
const resource = objectLoader.createCompactedResource({
364+
list: [
365+
'"ABC"',
366+
'"DEF"',
367+
'"GHI"',
368+
],
369+
});
370+
expect(await constructor.getArgumentValue(resource, settings)).toEqual([
371+
'ABC',
372+
'DEF',
373+
'GHI',
374+
]);
375+
expect(constructionStrategy.createArray).toHaveBeenCalledWith({
376+
settings,
377+
elements: [
378+
'ABC',
379+
'DEF',
380+
'GHI',
381+
],
382+
});
383+
});
384+
});
385+
311386
describe('for references', () => {
312387
it('should handle an IRI with value', async() => {
313388
const resource = objectLoader.createCompactedResource({

0 commit comments

Comments
 (0)