mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Improve vocabulary typings
This commit is contained in:
parent
4b39b50b0c
commit
2e1bae90c7
@ -22,6 +22,7 @@ The following changes are relevant for v5 custom configs that replaced certain f
|
||||
### Interface changes
|
||||
These changes are relevant if you wrote custom modules for the server that depend on existing interfaces.
|
||||
- `AgentGroupAccessChecker` no longer accepts any input parameters.
|
||||
- The functions in `Vocabularies.ts` were renamed, the typings have been made more precise and several utility types were added.
|
||||
|
||||
## v5.0.0
|
||||
### New features
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createUriAndTermNamespace } from '../../../util/Vocabularies';
|
||||
import { createVocabulary } from '../../../util/Vocabularies';
|
||||
|
||||
export const TEMPLATE = createUriAndTermNamespace('urn:solid-server:template:',
|
||||
export const TEMPLATE = createVocabulary('urn:solid-server:template:',
|
||||
'ResourceStore');
|
||||
|
||||
// Variables used for configuration templates
|
||||
// This is not an exclusive list
|
||||
export const TEMPLATE_VARIABLE = createUriAndTermNamespace(`${TEMPLATE.namespace}variable:`,
|
||||
export const TEMPLATE_VARIABLE = createVocabulary(`${TEMPLATE.namespace}variable:`,
|
||||
'baseUrl',
|
||||
'rootFilePath',
|
||||
'sparqlEndpoint',
|
||||
|
@ -2,46 +2,77 @@
|
||||
import { DataFactory } from 'n3';
|
||||
import type { NamedNode } from 'rdf-js';
|
||||
|
||||
type RecordOf<TKey extends any[], TValue> = Record<TKey[number], TValue>;
|
||||
/**
|
||||
* A `Record` in which each value is a concatenation of the baseUrl and its key.
|
||||
*/
|
||||
type ExpandedRecord<TBase extends string, TLocal extends string> = {[K in TLocal]: `${TBase}${K}` };
|
||||
|
||||
export type Namespace<TKey extends any[], TValue> =
|
||||
{ namespace: TValue } & RecordOf<TKey, TValue>;
|
||||
/**
|
||||
* Has a base URL as `namespace` value and each key has as value the concatenation with that base URL.
|
||||
*/
|
||||
type ValueVocabulary<TBase extends string, TLocal extends string> =
|
||||
{ namespace: TBase } & ExpandedRecord<TBase, TLocal>;
|
||||
/**
|
||||
* A {@link ValueVocabulary} where the URI values are {@link NamedNode}s.
|
||||
*/
|
||||
type TermVocabulary<T> = T extends ValueVocabulary<any, any> ? {[K in keyof T]: NamedNode<T[K]> } : never;
|
||||
|
||||
/**
|
||||
* Contains a namespace and keys linking to the entries in this namespace.
|
||||
* The `terms` field contains the same values but as {@link NamedNode} instead of string.
|
||||
*/
|
||||
export type Vocabulary<TBase extends string, TKey extends string> =
|
||||
ValueVocabulary<TBase, TKey> & { terms: TermVocabulary<ValueVocabulary<TBase, TKey>> };
|
||||
|
||||
/**
|
||||
* A {@link Vocabulary} where all the non-namespace fields are of unknown value.
|
||||
* This is a fallback in case {@link createVocabulary} gets called with a non-strict string array.
|
||||
*/
|
||||
export type PartialVocabulary<TBase extends string> =
|
||||
{ namespace: TBase } &
|
||||
Partial<Record<string, string>> &
|
||||
{ terms: { namespace: NamedNode<TBase> } & Partial<Record<string, NamedNode>> };
|
||||
|
||||
/**
|
||||
* A local name of a {@link Vocabulary}.
|
||||
*/
|
||||
export type VocabularyLocal<T> = T extends Vocabulary<any, infer TKey> ? TKey : never;
|
||||
/**
|
||||
* A URI string entry of a {@link Vocabulary}.
|
||||
*/
|
||||
export type VocabularyValue<T> = T extends Vocabulary<any, infer TKey> ? T[TKey] : never;
|
||||
/**
|
||||
* A {@link NamedNode} entry of a {@link Vocabulary}.
|
||||
*/
|
||||
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,
|
||||
* and exports the given local names as properties on the returned object.
|
||||
*/
|
||||
export function createNamespace<TKey extends string, TValue>(
|
||||
baseUri: string,
|
||||
toValue: (expanded: string) => TValue,
|
||||
...localNames: TKey[]):
|
||||
Namespace<typeof localNames, TValue> {
|
||||
const expanded: Namespace<typeof localNames, TValue> = {} as any;
|
||||
// Expose the main namespace
|
||||
expanded.namespace = toValue(baseUri);
|
||||
function createValueVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase, localNames: TLocal[]):
|
||||
ValueVocabulary<TBase, TLocal> {
|
||||
const expanded: Partial<ExpandedRecord<TBase, TLocal>> = { };
|
||||
// Expose the listed local names as properties
|
||||
for (const localName of localNames) {
|
||||
(expanded as RecordOf<TKey[], TValue>)[localName] = toValue(`${baseUri}${localName}`);
|
||||
expanded[localName] = `${baseUri}${localName}`;
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that expands local names from the given base URI into strings,
|
||||
* and exports the given local names as properties on the returned object.
|
||||
*/
|
||||
export function createUriNamespace<T extends string>(baseUri: string, ...localNames: T[]):
|
||||
Namespace<typeof localNames, string> {
|
||||
return createNamespace(baseUri, (expanded): string => expanded, ...localNames);
|
||||
return {
|
||||
namespace: baseUri,
|
||||
...expanded as ExpandedRecord<TBase, TLocal>,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that expands local names from the given base URI into named nodes,
|
||||
* and exports the given local names as properties on the returned object.
|
||||
*/
|
||||
export function createTermNamespace<T extends string>(baseUri: string, ...localNames: T[]):
|
||||
Namespace<typeof localNames, NamedNode> {
|
||||
return createNamespace(baseUri, DataFactory.namedNode, ...localNames);
|
||||
function createTermVocabulary<TBase extends string, TLocal extends string>(namespace: ValueVocabulary<TBase, TLocal>):
|
||||
TermVocabulary<ValueVocabulary<TBase, TLocal>> {
|
||||
// Need to cast since `fromEntries` typings aren't strict enough
|
||||
return Object.fromEntries(
|
||||
Object.entries(namespace).map(([ key, value ]): [string, NamedNode] => [ key, DataFactory.namedNode(value) ]),
|
||||
) as TermVocabulary<ValueVocabulary<TBase, TLocal>>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,13 +80,16 @@ Namespace<typeof localNames, NamedNode> {
|
||||
* and exports the given local names as properties on the returned object.
|
||||
* Under the `terms` property, it exposes the expanded local names as named nodes.
|
||||
*/
|
||||
export function createUriAndTermNamespace<T extends string>(baseUri: string, ...localNames: T[]):
|
||||
Namespace<typeof localNames, string> & { terms: Namespace<typeof localNames, NamedNode> } {
|
||||
return Object.assign(createUriNamespace(baseUri, ...localNames),
|
||||
{ terms: createTermNamespace(baseUri, ...localNames) });
|
||||
export function createVocabulary<TBase extends string, TLocal extends string>(baseUri: TBase,
|
||||
...localNames: TLocal[]): string extends TLocal ? PartialVocabulary<TBase> : Vocabulary<TBase, TLocal> {
|
||||
const namespace = createValueVocabulary(baseUri, localNames);
|
||||
return {
|
||||
...namespace,
|
||||
terms: createTermVocabulary(namespace),
|
||||
};
|
||||
}
|
||||
|
||||
export const ACL = createUriAndTermNamespace('http://www.w3.org/ns/auth/acl#',
|
||||
export const ACL = createVocabulary('http://www.w3.org/ns/auth/acl#',
|
||||
'accessTo',
|
||||
'agent',
|
||||
'agentClass',
|
||||
@ -71,42 +105,42 @@ export const ACL = createUriAndTermNamespace('http://www.w3.org/ns/auth/acl#',
|
||||
'Control',
|
||||
);
|
||||
|
||||
export const AS = createUriAndTermNamespace('https://www.w3.org/ns/activitystreams#',
|
||||
export const AS = createVocabulary('https://www.w3.org/ns/activitystreams#',
|
||||
'Create',
|
||||
'Delete',
|
||||
'Update',
|
||||
);
|
||||
|
||||
export const AUTH = createUriAndTermNamespace('urn:solid:auth:',
|
||||
export const AUTH = createVocabulary('urn:solid:auth:',
|
||||
'userMode',
|
||||
'publicMode',
|
||||
);
|
||||
|
||||
export const DC = createUriAndTermNamespace('http://purl.org/dc/terms/',
|
||||
export const DC = createVocabulary('http://purl.org/dc/terms/',
|
||||
'description',
|
||||
'modified',
|
||||
'title',
|
||||
);
|
||||
|
||||
export const FOAF = createUriAndTermNamespace('http://xmlns.com/foaf/0.1/',
|
||||
export const FOAF = createVocabulary('http://xmlns.com/foaf/0.1/',
|
||||
'Agent',
|
||||
);
|
||||
|
||||
export const HH = createUriAndTermNamespace('http://www.w3.org/2011/http-headers#',
|
||||
export const HH = createVocabulary('http://www.w3.org/2011/http-headers#',
|
||||
'content-length',
|
||||
);
|
||||
|
||||
export const HTTP = createUriAndTermNamespace('http://www.w3.org/2011/http#',
|
||||
export const HTTP = createVocabulary('http://www.w3.org/2011/http#',
|
||||
'statusCodeNumber',
|
||||
);
|
||||
|
||||
export const IANA = createUriAndTermNamespace('http://www.w3.org/ns/iana/media-types/');
|
||||
export const IANA = createVocabulary('http://www.w3.org/ns/iana/media-types/');
|
||||
|
||||
export const JSON_LD = createUriAndTermNamespace('http://www.w3.org/ns/json-ld#',
|
||||
export const JSON_LD = createVocabulary('http://www.w3.org/ns/json-ld#',
|
||||
'context',
|
||||
);
|
||||
|
||||
export const LDP = createUriAndTermNamespace('http://www.w3.org/ns/ldp#',
|
||||
export const LDP = createVocabulary('http://www.w3.org/ns/ldp#',
|
||||
'contains',
|
||||
|
||||
'BasicContainer',
|
||||
@ -114,32 +148,32 @@ export const LDP = createUriAndTermNamespace('http://www.w3.org/ns/ldp#',
|
||||
'Resource',
|
||||
);
|
||||
|
||||
export const MA = createUriAndTermNamespace('http://www.w3.org/ns/ma-ont#',
|
||||
export const MA = createVocabulary('http://www.w3.org/ns/ma-ont#',
|
||||
'format',
|
||||
);
|
||||
|
||||
export const OIDC = createUriAndTermNamespace('http://www.w3.org/ns/solid/oidc#',
|
||||
export const OIDC = createVocabulary('http://www.w3.org/ns/solid/oidc#',
|
||||
'redirect_uris',
|
||||
);
|
||||
|
||||
export const PIM = createUriAndTermNamespace('http://www.w3.org/ns/pim/space#',
|
||||
export const PIM = createVocabulary('http://www.w3.org/ns/pim/space#',
|
||||
'Storage',
|
||||
);
|
||||
|
||||
export const POSIX = createUriAndTermNamespace('http://www.w3.org/ns/posix/stat#',
|
||||
export const POSIX = createVocabulary('http://www.w3.org/ns/posix/stat#',
|
||||
'mtime',
|
||||
'size',
|
||||
);
|
||||
|
||||
export const RDF = createUriAndTermNamespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
export const RDF = createVocabulary('http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'type',
|
||||
);
|
||||
|
||||
export const RDFS = createUriAndTermNamespace('http://www.w3.org/2000/01/rdf-schema#',
|
||||
export const RDFS = createVocabulary('http://www.w3.org/2000/01/rdf-schema#',
|
||||
'label',
|
||||
);
|
||||
|
||||
export const SOLID = createUriAndTermNamespace('http://www.w3.org/ns/solid/terms#',
|
||||
export const SOLID = createVocabulary('http://www.w3.org/ns/solid/terms#',
|
||||
'deletes',
|
||||
'inserts',
|
||||
'oidcIssuer',
|
||||
@ -150,22 +184,22 @@ export const SOLID = createUriAndTermNamespace('http://www.w3.org/ns/solid/terms
|
||||
'InsertDeletePatch',
|
||||
);
|
||||
|
||||
export const SOLID_AS = createUriAndTermNamespace('http://www.w3.org/ns/solid/activitystreams#',
|
||||
export const SOLID_AS = createVocabulary('http://www.w3.org/ns/solid/activitystreams#',
|
||||
'Activity',
|
||||
);
|
||||
|
||||
export const SOLID_ERROR = createUriAndTermNamespace('urn:npm:solid:community-server:error:',
|
||||
export const SOLID_ERROR = createVocabulary('urn:npm:solid:community-server:error:',
|
||||
'disallowedMethod',
|
||||
'errorResponse',
|
||||
'stack',
|
||||
);
|
||||
|
||||
export const SOLID_HTTP = createUriAndTermNamespace('urn:npm:solid:community-server:http:',
|
||||
export const SOLID_HTTP = createVocabulary('urn:npm:solid:community-server:http:',
|
||||
'location',
|
||||
'slug',
|
||||
);
|
||||
|
||||
export const SOLID_META = createUriAndTermNamespace('urn:npm:solid:community-server:meta:',
|
||||
export const SOLID_META = createVocabulary('urn:npm:solid:community-server:meta:',
|
||||
// This identifier is used as graph for all metadata that is generated on the fly and should not be stored
|
||||
'ResponseMetadata',
|
||||
// This is used to identify templates that can be used for the representation of a resource
|
||||
@ -177,15 +211,15 @@ export const SOLID_META = createUriAndTermNamespace('urn:npm:solid:community-ser
|
||||
'preserve',
|
||||
);
|
||||
|
||||
export const VANN = createUriAndTermNamespace('http://purl.org/vocab/vann/',
|
||||
export const VANN = createVocabulary('http://purl.org/vocab/vann/',
|
||||
'preferredNamespacePrefix',
|
||||
);
|
||||
|
||||
export const VCARD = createUriAndTermNamespace('http://www.w3.org/2006/vcard/ns#',
|
||||
export const VCARD = createVocabulary('http://www.w3.org/2006/vcard/ns#',
|
||||
'hasMember',
|
||||
);
|
||||
|
||||
export const XSD = createUriAndTermNamespace('http://www.w3.org/2001/XMLSchema#',
|
||||
export const XSD = createVocabulary('http://www.w3.org/2001/XMLSchema#',
|
||||
'dateTime',
|
||||
'integer',
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user