Skip to content

Commit

Permalink
Handle type containers
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensworks committed Mar 16, 2020
1 parent d4850b5 commit d478310
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 2 deletions.
6 changes: 4 additions & 2 deletions lib/ParsingContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,10 @@ export class ParsingContext {
// Shorten key stack
if (this.pendingContainerFlushBuffers.length) {
for (const buffer of this.pendingContainerFlushBuffers) {
buffer.depth--;
buffer.keys.splice(depth, depthOffset);
if (buffer.depth >= depth + depthOffset) {
buffer.depth -= depthOffset;
buffer.keys.splice(depth, depthOffset);
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions lib/containerhandler/ContainerHandlerType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {EntryHandlerPredicate} from "../entryhandler/EntryHandlerPredicate";
import {ParsingContext} from "../ParsingContext";
import {Util} from "../Util";
import {IContainerHandler} from "./IContainerHandler";

/**
* Container handler for @type.
*
* This will add this entry to the parent node, and use the current key as an rdf:type value.
*/
export class ContainerHandlerType implements IContainerHandler {

public async handle(parsingContext: ParsingContext, util: Util, keys: string[], value: any, depth: number)
: Promise<void> {
if (!Array.isArray(value)) {
// Handle the value of this node, which will also cause the type predicate from above to be emitted.
await parsingContext.newOnValueJob(keys, value, depth - 1, true);

// Identify the type to emit.
const keyOriginal = keys[depth];
const context = await parsingContext.getContext(keys);
const type = util.createVocabOrBaseTerm(context, keyOriginal);
if (type) {
// Push the type to the stack using the rdf:type predicate
await EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth + 1, null,
util.rdfType, type, false);
}

// Flush any pending flush buffers
await parsingContext.handlePendingContainerFlushBuffers();
}

parsingContext.emittedStack[depth] = false; // Don't emit the predicate owning this container.
}

}
2 changes: 2 additions & 0 deletions lib/entryhandler/EntryHandlerContainer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {ContainerHandlerIdentifier} from "../containerhandler/ContainerHandlerIdentifier";
import {ContainerHandlerIndex} from "../containerhandler/ContainerHandlerIndex";
import {ContainerHandlerLanguage} from "../containerhandler/ContainerHandlerLanguage";
import {ContainerHandlerType} from "../containerhandler/ContainerHandlerType";
import {IContainerHandler} from "../containerhandler/IContainerHandler";
import {ParsingContext} from "../ParsingContext";
import {Util} from "../Util";
Expand All @@ -16,6 +17,7 @@ export class EntryHandlerContainer implements IEntryHandler<IContainerHandler> {
'@id': new ContainerHandlerIdentifier(),
'@index': new ContainerHandlerIndex(),
'@language': new ContainerHandlerLanguage(),
'@type': new ContainerHandlerType(),
};

/**
Expand Down
192 changes: 192 additions & 0 deletions test/JsonLdParser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,198 @@ describe('JsonLdParser', () => {
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([]);
});

it('with @id and type map', async () => {
const stream = streamifyString(`
{
"@context": {
"@base": "http://example.com/entries/",
"ex": "http://ex.org/",
"p": { "@id": "http://ex.org/pred1", "@container": "@type" },
"value": "ex:value"
},
"@id": "http://ex.org/myid",
"p": {
"ex:Type1": {
"@id": "value1",
"value": "1539"
},
"ex:Type2": {
"@id": "value2",
"value": "1204"
}
}
}`);
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value2')),
triple(namedNode('http://example.com/entries/value1'), namedNode('http://ex.org/value'),
literal('1539')),
triple(namedNode('http://example.com/entries/value1'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type1')),
triple(namedNode('http://example.com/entries/value2'), namedNode('http://ex.org/value'),
literal('1204')),
triple(namedNode('http://example.com/entries/value2'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type2')),
]);
});

it('with @id and type map with an array value', async () => {
const stream = streamifyString(`
{
"@context": {
"@base": "http://example.com/entries/",
"ex": "http://ex.org/",
"p": { "@id": "http://ex.org/pred1", "@container": "@type" },
"value": "ex:value"
},
"@id": "http://ex.org/myid",
"p": {
"ex:Type1": [
{
"@id": "value1",
"value": "1539"
},
{
"@id": "value1.1",
"value": "1539.1"
}
],
"ex:Type2": {
"@id": "value2",
"value": "1204"
}
}
}`);
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value1.1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value2')),
triple(namedNode('http://example.com/entries/value1'), namedNode('http://ex.org/value'),
literal('1539')),
triple(namedNode('http://example.com/entries/value1'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type1')),
triple(namedNode('http://example.com/entries/value1.1'), namedNode('http://ex.org/value'),
literal('1539.1')),
triple(namedNode('http://example.com/entries/value1.1'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type1')),
triple(namedNode('http://example.com/entries/value2'), namedNode('http://ex.org/value'),
literal('1204')),
triple(namedNode('http://example.com/entries/value2'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type2')),
]);
});

it('with @id and type map with an array value', async () => {
const stream = streamifyString(`
{
"@context": {
"@base": "http://example.com/entries/",
"ex": "http://ex.org/",
"p": { "@id": "http://ex.org/pred1", "@container": "@type" },
"value": "ex:value"
},
"@id": "http://ex.org/myid",
"p": {
"ex:Type1": []
}
}`);
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([]);
});

it('with @id and type map with a nested array value', async () => {
const stream = streamifyString(`
{
"@context": {
"@base": "http://example.com/entries/",
"ex": "http://ex.org/",
"p": { "@id": "http://ex.org/pred1", "@container": "@type" },
"value": "ex:value"
},
"@id": "http://ex.org/myid",
"p": {
"ex:Type1": [
[{
"@id": "value1",
"value": "1539"
}],
[{
"@id": "value1.1",
"value": "1539.1"
}]
],
"ex:Type2": {
"@id": "value2",
"value": "1204"
}
}
}`);
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value1.1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://example.com/entries/value2')),
triple(namedNode('http://example.com/entries/value1'), namedNode('http://ex.org/value'),
literal('1539')),
triple(namedNode('http://example.com/entries/value1'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type1')),
triple(namedNode('http://example.com/entries/value1.1'), namedNode('http://ex.org/value'),
literal('1539.1')),
triple(namedNode('http://example.com/entries/value1.1'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type1')),
triple(namedNode('http://example.com/entries/value2'), namedNode('http://ex.org/value'),
literal('1204')),
triple(namedNode('http://example.com/entries/value2'),
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
namedNode('http://ex.org/Type2')),
]);
});

it('with @id and invalid type map', async () => {
const stream = streamifyString(`
{
"@context": {
"ex": "http://ex.org/",
"p": { "@id": "http://ex.org/pred1", "@container": "@type" },
"value": "ex:value"
},
"@id": "http://ex.org/myid",
"p": {
"Type1": {
"@id": "ex:entries/value1",
"value": "1539"
},
"Type2": {
"@id": "ex:entries/value2",
"value": "1204"
}
}
}`);
return expect(await arrayifyStream(stream.pipe(parser))).toBeRdfIsomorphic([
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://ex.org/entries/value1')),
triple(namedNode('http://ex.org/myid'), namedNode('http://ex.org/pred1'),
namedNode('http://ex.org/entries/value2')),
triple(namedNode('http://ex.org/entries/value1'), namedNode('http://ex.org/value'),
literal('1539')),
triple(namedNode('http://ex.org/entries/value2'), namedNode('http://ex.org/value'),
literal('1204')),
]);
});

it('with @index in a string value should be ignored', async () => {
const stream = streamifyString(`
{
Expand Down
7 changes: 7 additions & 0 deletions test/entryhandler/EntryHandlerContainer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ describe('EntryHandlerContainer', () => {
.toBe(true);
});

it('should return true when targeting a depth in an @type container', async () => {
parsingContext.contextTree.setContext(["a", "container"],
Promise.resolve({ container: { "@container": "@type" } }));
expect(await EntryHandlerContainer.isContainerHandler(parsingContext, ["a", "container", "key", "subKey"], 3))
.toBe(true);
});

it('should return true when targeting a depth in an unknown container', async () => {
parsingContext.contextTree.setContext(["a", "container"],
Promise.resolve({ container: { "@container": "@bla" } }));
Expand Down

0 comments on commit d478310

Please sign in to comment.