Skip to content

Commit e4e552c

Browse files
feat: add rdf package (#222)
* feat: add first draft of rdf package * fix: take jsonld as input * refactor: serializartion is base64 encoded update also statement format
1 parent 719d7d6 commit e4e552c

File tree

8 files changed

+350
-0
lines changed

8 files changed

+350
-0
lines changed

pkg/rdf/package.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "@slangroom/rdf",
3+
"version": "1.44.1",
4+
"dependencies": {
5+
"@slangroom/core": "workspace:*",
6+
"jsonld": "^8.3.3",
7+
"n3": "^1.24.2",
8+
"rdfjs-c14n": "^3.1.3"
9+
},
10+
"repository": "https://github.com/dyne/slangroom",
11+
"license": "AGPL-3.0-only",
12+
"type": "module",
13+
"main": "./build/esm/src/index.js",
14+
"types": "./build/esm/src/index.d.ts",
15+
"exports": {
16+
".": {
17+
"import": {
18+
"types": "./build/esm/src/index.d.ts",
19+
"default": "./build/esm/src/index.js"
20+
}
21+
},
22+
"./*": {
23+
"import": {
24+
"types": "./build/esm/src/*.d.ts",
25+
"default": "./build/esm/src/*.js"
26+
}
27+
},
28+
"./package.json": "./package.json"
29+
},
30+
"publishConfig": {
31+
"access": "public"
32+
},
33+
"engines": {
34+
"node": "^18.20.0 || ^20.10.0 || ^22 || ^23"
35+
},
36+
"devDependencies": {
37+
"@types/jsonld": "^1.5.15",
38+
"@types/n3": "^1.24.2"
39+
}
40+
}

pkg/rdf/package.json.license

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2025 Dyne.org foundation
2+
3+
SPDX-License-Identifier: AGPL-3.0-or-later

pkg/rdf/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// SPDX-FileCopyrightText: 2025 Dyne.org foundation
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-or-later
4+
5+
export * from '@slangroom/rdf/plugin';

pkg/rdf/src/plugin.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-FileCopyrightText: 2025 Dyne.org foundation
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-or-later
4+
5+
import { Plugin } from '@slangroom/core';
6+
import n3 from "n3";
7+
import jsonld from "jsonld";
8+
import { RDFC10, type InputQuads } from 'rdfjs-c14n';
9+
10+
// read the version from the package.json
11+
import packageJson from '@slangroom/rdf/package.json' with { type: 'json' };
12+
13+
export const version = packageJson.version;
14+
15+
export class RdfError extends Error {
16+
constructor(e: string) {
17+
super(e)
18+
this.name = 'Slangroom @slangroom/rdf@' + packageJson.version + ' Error'
19+
}
20+
}
21+
22+
const p = new Plugin();
23+
24+
const rdfc10 = new RDFC10(n3.DataFactory);
25+
26+
/**
27+
* @internal
28+
*/
29+
export const canonicalization = p.new(
30+
['dictionary'],
31+
'generate serialized canonical rdf',
32+
async (ctx) => {
33+
const input = ctx.fetch('dictionary');
34+
if(!input || typeof input !== "object") {
35+
return ctx.fail(new RdfError('Invalid input, it must be an object'))
36+
}
37+
try {
38+
const quads = await jsonld.toRDF(input as object, {format: "application/n-quads"}) as unknown as InputQuads;
39+
const normalized: string = (await rdfc10.c14n(quads)).canonical_form
40+
return ctx.pass(btoa(normalized));
41+
} catch(e) {
42+
return ctx.fail(new RdfError((e as Error).message))
43+
}
44+
}
45+
);
46+
47+
export const rdf = p;

pkg/rdf/test/e2e.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// SPDX-FileCopyrightText: 2025 Dyne.org foundation
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-or-later
4+
5+
import test from 'ava';
6+
import { Slangroom } from '@slangroom/core';
7+
import { rdf } from '@slangroom/rdf';
8+
// read the version from the package.json
9+
// import packageJson from '@slangroom/rdf/package.json' with { type: 'json' };
10+
11+
// const stripAnsiCodes = (str: string) => str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
12+
13+
test('canonicalization', async (t) => {
14+
const slangroom = new Slangroom(rdf);
15+
const script: string = `Rule unknown ignore
16+
Given I send dictionary 'dataset' and generate serialized canonical rdf and output into 'res'
17+
Prepare 'res_2': generate serialized canonical rdf with dictionary 'dataset'
18+
Given I have a 'string' named 'res'
19+
Given I have a 'string' named 'res_2'
20+
Then print the data
21+
`;
22+
const expected_res: string = `<did:example:ebfeb1f712ebc6f1c276e12ec21> <https://www.w3.org/ns/credentials/examples#degree> _:c14n0 .
23+
<http://university.example/credentials/3732> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
24+
<http://university.example/credentials/3732> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/ns/credentials/examples#ExampleDegreeCredential> .
25+
<http://university.example/credentials/3732> <https://www.w3.org/2018/credentials#credentialSubject> <did:example:ebfeb1f712ebc6f1c276e12ec21> .
26+
<http://university.example/credentials/3732> <https://www.w3.org/2018/credentials#issuer> <https://university.example/issuers/565049> .
27+
<http://university.example/credentials/3732> <https://www.w3.org/2018/credentials#validFrom> "2010-01-01T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
28+
_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/ns/credentials/examples#ExampleBachelorDegree> .
29+
_:c14n0 <https://schema.org/name> "Bachelor of Science and Arts" .
30+
`
31+
const fn = slangroom.execute(script, {
32+
data: {
33+
dataset: {
34+
"@context": [
35+
"https://www.w3.org/ns/credentials/v2",
36+
"https://www.w3.org/ns/credentials/examples/v2"
37+
],
38+
id: "http://university.example/credentials/3732",
39+
type: ["VerifiableCredential", "ExampleDegreeCredential"],
40+
issuer: "https://university.example/issuers/565049",
41+
validFrom: "2010-01-01T00:00:00Z",
42+
credentialSubject: {
43+
id: "did:example:ebfeb1f712ebc6f1c276e12ec21",
44+
degree: {
45+
type: "ExampleBachelorDegree",
46+
name: "Bachelor of Science and Arts"
47+
}
48+
}
49+
}
50+
}
51+
});
52+
const result = await fn;
53+
t.is(result.result['res'], btoa(expected_res), JSON.stringify(result.result));
54+
t.is(result.result['res_2'], btoa(expected_res), JSON.stringify(result.result));
55+
});

pkg/rdf/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../tsconfig.json

pkg/rdf/tsconfig.json.license

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2025 Dyne.org foundation
2+
3+
SPDX-License-Identifier: AGPL-3.0-or-later

0 commit comments

Comments
 (0)