mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Allow vocabularies to be extended
This commit is contained in:
parent
2e1bae90c7
commit
97f7ca027e
@ -47,8 +47,7 @@ export type VocabularyValue<T> = T extends Vocabulary<any, infer TKey> ? T[TKey]
|
|||||||
export type VocabularyTerm<T> = T extends Vocabulary<any, infer TKey> ? T['terms'][TKey] : never;
|
export type VocabularyTerm<T> = T extends Vocabulary<any, infer TKey> ? T['terms'][TKey] : never;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a function that expands local names from the given base URI,
|
* Creates a {@link ValueVocabulary} with the given `baseUri` as namespace and all `localNames` as entries.
|
||||||
* and exports the given local names as properties on the returned object.
|
|
||||||
*/
|
*/
|
||||||
function createValueVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase, localNames: TLocal[]):
|
function createValueVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase, localNames: TLocal[]):
|
||||||
ValueVocabulary<TBase, TLocal> {
|
ValueVocabulary<TBase, TLocal> {
|
||||||
@ -64,31 +63,44 @@ ValueVocabulary<TBase, TLocal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a function that expands local names from the given base URI into named nodes,
|
* Creates a {@link TermVocabulary} based on the provided {@link ValueVocabulary}.
|
||||||
* and exports the given local names as properties on the returned object.
|
|
||||||
*/
|
*/
|
||||||
function createTermVocabulary<TBase extends string, TLocal extends string>(namespace: ValueVocabulary<TBase, TLocal>):
|
function createTermVocabulary<TBase extends string, TLocal extends string>(values: ValueVocabulary<TBase, TLocal>):
|
||||||
TermVocabulary<ValueVocabulary<TBase, TLocal>> {
|
TermVocabulary<ValueVocabulary<TBase, TLocal>> {
|
||||||
// Need to cast since `fromEntries` typings aren't strict enough
|
// Need to cast since `fromEntries` typings aren't strict enough
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(namespace).map(([ key, value ]): [string, NamedNode] => [ key, DataFactory.namedNode(value) ]),
|
Object.entries(values).map(([ key, value ]): [string, NamedNode] => [ key, DataFactory.namedNode(value) ]),
|
||||||
) as TermVocabulary<ValueVocabulary<TBase, TLocal>>;
|
) as TermVocabulary<ValueVocabulary<TBase, TLocal>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a function that expands local names from the given base URI into string,
|
* Creates a {@link Vocabulary} with the given `baseUri` as namespace and all `localNames` as entries.
|
||||||
* and exports the given local names as properties on the returned object.
|
* The values are the local names expanded from the given base URI as strings.
|
||||||
* Under the `terms` property, it exposes the expanded local names as named nodes.
|
* The `terms` field contains all the same values but as {@link NamedNode} instead.
|
||||||
*/
|
*/
|
||||||
export function createVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase,
|
export function createVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase,
|
||||||
...localNames: TLocal[]): string extends TLocal ? PartialVocabulary<TBase> : Vocabulary<TBase, TLocal> {
|
...localNames: TLocal[]): string extends TLocal ? PartialVocabulary<TBase> : Vocabulary<TBase, TLocal> {
|
||||||
const namespace = createValueVocabulary(baseUri, localNames);
|
const values = createValueVocabulary(baseUri, localNames);
|
||||||
return {
|
return {
|
||||||
...namespace,
|
...values,
|
||||||
terms: createTermVocabulary(namespace),
|
terms: createTermVocabulary(values),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Vocabulary} that extends an existing one by adding new local names.
|
||||||
|
* @param vocabulary - The {@link Vocabulary} to extend.
|
||||||
|
* @param newNames - The new local names that need to be added.
|
||||||
|
*/
|
||||||
|
export function extendVocabulary<TBase extends string, TLocal extends string, TNew extends string>(
|
||||||
|
vocabulary: Vocabulary<TBase, TLocal>, ...newNames: TNew[]):
|
||||||
|
ReturnType<typeof createVocabulary<TBase, TLocal | TNew>> {
|
||||||
|
const localNames = Object.keys(vocabulary)
|
||||||
|
.filter((key): boolean => key !== 'terms' && key !== 'namespace') as TLocal[];
|
||||||
|
const allNames = [ ...localNames, ...newNames ];
|
||||||
|
return createVocabulary(vocabulary.namespace, ...allNames);
|
||||||
|
}
|
||||||
|
|
||||||
export const ACL = createVocabulary('http://www.w3.org/ns/auth/acl#',
|
export const ACL = createVocabulary('http://www.w3.org/ns/auth/acl#',
|
||||||
'accessTo',
|
'accessTo',
|
||||||
'agent',
|
'agent',
|
||||||
|
@ -1,22 +1,50 @@
|
|||||||
import { DataFactory } from 'n3';
|
import { DataFactory } from 'n3';
|
||||||
import { LDP } from '../../../src/util/Vocabularies';
|
import { createVocabulary, extendVocabulary } from '../../../src/util/Vocabularies';
|
||||||
|
|
||||||
describe('Vocabularies', (): void => {
|
describe('Vocabularies', (): void => {
|
||||||
describe('LDP', (): void => {
|
const vocabulary = createVocabulary('http://www.w3.org/ns/ldp#', 'contains', 'Container');
|
||||||
|
|
||||||
|
describe('createVocabulary', (): void => {
|
||||||
it('contains its own URI.', (): void => {
|
it('contains its own URI.', (): void => {
|
||||||
expect(LDP.namespace).toBe('http://www.w3.org/ns/ldp#');
|
expect(vocabulary.namespace).toBe('http://www.w3.org/ns/ldp#');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('contains its own URI as a term.', (): void => {
|
it('contains its own URI as a term.', (): void => {
|
||||||
expect(LDP.terms.namespace).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#'));
|
expect(vocabulary.terms.namespace).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exposes ldp:contains.', (): void => {
|
it('exposes the defined URIs.', (): void => {
|
||||||
expect(LDP.contains).toBe('http://www.w3.org/ns/ldp#contains');
|
expect(vocabulary.contains).toBe('http://www.w3.org/ns/ldp#contains');
|
||||||
|
expect(vocabulary.Container).toBe('http://www.w3.org/ns/ldp#Container');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exposes ldp:contains as a term.', (): void => {
|
it('exposes the defined URIs as terms.', (): void => {
|
||||||
expect(LDP.terms.contains).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#contains'));
|
expect(vocabulary.terms.contains).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#contains'));
|
||||||
|
expect(vocabulary.terms.Container).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#Container'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('extendVocabulary', (): void => {
|
||||||
|
const extended = extendVocabulary(vocabulary, 'extended', 'extra');
|
||||||
|
|
||||||
|
it('still contains all the original values.', async(): Promise<void> => {
|
||||||
|
expect(extended.namespace).toBe('http://www.w3.org/ns/ldp#');
|
||||||
|
expect(extended.terms.namespace).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#'));
|
||||||
|
expect(extended.contains).toBe('http://www.w3.org/ns/ldp#contains');
|
||||||
|
expect(extended.Container).toBe('http://www.w3.org/ns/ldp#Container');
|
||||||
|
expect(extended.terms.contains).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#contains'));
|
||||||
|
expect(extended.terms.Container).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#Container'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('contains the new values.', async(): Promise<void> => {
|
||||||
|
expect(extended.extended).toBe('http://www.w3.org/ns/ldp#extended');
|
||||||
|
expect(extended.extra).toBe('http://www.w3.org/ns/ldp#extra');
|
||||||
|
expect(extended.terms.extended).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#extended'));
|
||||||
|
expect(extended.terms.extra).toEqual(DataFactory.namedNode('http://www.w3.org/ns/ldp#extra'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify the original vocabulary.', async(): Promise<void> => {
|
||||||
|
expect((vocabulary as any).extended).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user