Skip to content

Commit

Permalink
Improve CURIE handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlongley committed Aug 12, 2024
1 parent 0f89c5b commit 8160d23
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 49 deletions.
34 changes: 1 addition & 33 deletions lib/ActiveContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,38 +87,6 @@ export class ActiveContext {
return {term, termId: id, plural, def};
}

getTermType({def}) {
// FIXME: consider making `def` hold keyword value for any keyword and
// handle that here
const {'@type': type} = def;
if(!type) {
// no term type
return;
}

// check for potential CURIE value
const [prefix, ...suffix] = type.split(':');
const prefixDef = this._activeCtx.termMap.get(prefix);
if(prefixDef === undefined) {
// no CURIE
return type;
}

// handle CURIE
if(typeof prefixDef === 'string') {
return prefixDef + suffix.join(':');
}

// prefix definition must be an object
if(!(typeof prefixDef === 'object' &&
typeof prefixDef['@id'] === 'string')) {
throw new CborldError(
'ERR_INVALID_TERM_DEFINITION',
'JSON-LD term definitions must be strings or objects with "@id".');
}
return prefixDef['@id'] + suffix.join(':');
}

async _updateActiveContext({
activeCtx, contexts, allowProtectedOverride = false
}) {
Expand All @@ -135,7 +103,7 @@ export class ActiveContext {
// push any local contexts onto the context stack
const {contextLoader} = this;
for(const context of contexts) {
const entry = await contextLoader.load({context});
const entry = await contextLoader.load({activeCtx, context});

// clone entry to create new active context entry for context stack
const newActive = {
Expand Down
64 changes: 51 additions & 13 deletions lib/ContextLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class ContextLoader {
if(term === undefined) {
throw new CborldError(
'ERR_UNKNOWN_CBORLD_TERM_ID',
`Unknown term ID '${id}' was detected in the CBOR-LD input.`);
`Unknown term ID "${id}" was detected in the CBOR-LD input.`);
}
return {term, plural};
}
Expand All @@ -55,7 +55,7 @@ export class ContextLoader {
return this.idToTerm.has({id});
}

async load({context}) {
async load({activeCtx, context}) {
const entry = this.contextMap.get(context);
if(entry) {
// already loaded, return it
Expand All @@ -70,10 +70,10 @@ export class ContextLoader {
}
// FIXME: validate `ctx` to ensure its a valid JSON-LD context value
// add context
return this._addContext({context: ctx, contextUrl});
return this._addContext({activeCtx, context: ctx, contextUrl});
}

async _addContext({context, contextUrl}) {
async _addContext({activeCtx, context, contextUrl}) {
const {contextMap, termToId, idToTerm} = this;

// handle `@import`
Expand Down Expand Up @@ -102,24 +102,33 @@ export class ContextLoader {
// process context keys in sorted order to ensure term IDs are assigned
// consistently
const keys = Object.keys(context).sort();
const isProtected = !!context['@protected'];
for(const key of keys) {
const def = context[key];
if(KEYWORDS_TABLE.has(key)) {
// skip `KEYWORDS_TABLE` to avoid adding unnecessary term defns
continue;
}

let def = context[key];
if(!def) {
continue;
}

// add new `@type` alias
const _id = typeof def === 'string' ? def : def?.['@id'];
if(_id === '@type') {
entry.typeAliases.add(key);
// normalize definition to an object
if(typeof def === 'string') {
def = {'@id': def};
} else if(!(typeof def === 'object' && typeof def['@id'] === 'string')) {
throw new CborldError(
'ERR_INVALID_TERM_DEFINITION',
'JSON-LD term definitions must be strings or objects with "@id".');
}

if(KEYWORDS_TABLE.has(key)) {
// skip `KEYWORDS_TABLE` to avoid adding unnecessary term defns
continue;
// add new `@type` alias
if(def?.['@id'] === '@type') {
entry.typeAliases.add(key);
}

termMap.set(key, def);
termMap.set(key, {...def, protected: isProtected});
const scopedContext = def['@context'];
if(scopedContext) {
scopedContextMap.set(key, scopedContext);
Expand All @@ -136,6 +145,18 @@ export class ContextLoader {
}
}

// handle any CURIE values in definitions
for(const def of termMap.values()) {
const id = def['@id'];
if(id !== undefined) {
def['@id'] = _resolveCurie({activeCtx, context, possibleCurie: id});
}
const type = def['@type'];
if(type !== undefined) {
def['@type'] = _resolveCurie({activeCtx, context, possibleCurie: type});
}
}

// add entry for context URL or context object
contextMap.set(contextUrl || context, entry);

Expand All @@ -151,6 +172,23 @@ export class ContextLoader {
}
}

function _resolveCurie({activeCtx, context, possibleCurie}) {
if(possibleCurie === undefined || !possibleCurie.includes(':')) {
return possibleCurie;
}
// check for potential CURIE values
const [prefix, ...suffix] = possibleCurie.split(':');
const prefixDef = activeCtx.termMap.get(prefix) ?? context[prefix];
if(prefixDef === undefined) {
// no CURIE
return possibleCurie;
}
// handle CURIE
const id = typeof prefixDef === 'string' ? prefixDef : prefixDef['@id'];
possibleCurie = id + suffix.join(':');
return _resolveCurie({activeCtx, context, possibleCurie});
}

/**
* Fetches a resource given a URL and returns it as a string.
*
Expand Down
2 changes: 1 addition & 1 deletion lib/Transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class Transformer {
// FIXME: improve obscure "transform entry" language
// iterate through all values for the current transform entry
const {plural, def} = termInfo;
const termType = typeActiveCtx.getTermType({def});
const termType = def['@type'];
const values = plural ? value : [value];
const entries = [];
for(const value of values) {
Expand Down
4 changes: 2 additions & 2 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ export function getTableType({termInfo, termType}) {
const {term, def} = termInfo;

// handle `@id`, `@type`, their aliases, and `@vocab`
if(term === '@id' || def === '@id' || def?.['.@id'] === '@id' ||
term === '@type' || def === '@type' || def?.['@id'] === '@type' ||
if(term === '@id' || def['@id'] === '@id' ||
term === '@type' || def['@id'] === '@type' ||
termType === '@id' || termType === '@vocab') {
return 'url';
}
Expand Down

0 comments on commit 8160d23

Please sign in to comment.