@blackcatinformatics/purrdf 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/index.d.ts +7 -2
- package/index.mjs +17 -3
- package/package.json +1 -1
- package/pkg/purrdf_wasm.d.ts +39 -0
- package/pkg/purrdf_wasm.js +70 -0
- package/pkg/purrdf_wasm_bg.wasm +0 -0
- package/pkg/purrdf_wasm_bg.wasm.d.ts +2 -0
package/README.md
CHANGED
|
@@ -14,6 +14,10 @@ It is the same engine, byte-for-byte behavior, that ships as the `purrdf`
|
|
|
14
14
|
Rust crates, the `purrdf` PyPI package, and `libpurrdf` — PurRDF's rule is
|
|
15
15
|
**one engine, one behavior, every language**.
|
|
16
16
|
|
|
17
|
+
> **Try it live** — the [RDF-1.2 playground](https://blackcat-informatics.github.io/purrdf/playground/)
|
|
18
|
+
> runs this package in your browser: parse, SPARQL, SHACL, serialize, and
|
|
19
|
+
> canonicalize/compare RDF-1.2 graphs client-side, with no install.
|
|
20
|
+
|
|
17
21
|
## Why this instead of an incumbent RDF/JS library?
|
|
18
22
|
|
|
19
23
|
No incumbent RDF/JS library carries the RDF 1.2 features:
|
|
@@ -73,7 +77,11 @@ const reparsed = Dataset.parse(nq, "nquads");
|
|
|
73
77
|
`fromTerm`, `fromQuad`.
|
|
74
78
|
- `Dataset` — `Dataset.parse(input, format, base?)`, `serialize(format)`,
|
|
75
79
|
`add` / `delete` / `has` / `match` / `quads` / `size`, iteration.
|
|
76
|
-
Formats: `turtle`, `ntriples`, `nquads`, `trig`, `rdfxml
|
|
80
|
+
Formats: `turtle`, `ntriples`, `nquads`, `trig`, `rdfxml` (`serialize` also `jsonld`).
|
|
81
|
+
- `Dataset.canonicalize()` / `Dataset.isomorphic(other)` — RDFC-1.0 canonical N-Quads
|
|
82
|
+
and RDF graph-identity (isomorphism under blank-node relabeling).
|
|
83
|
+
- `shaclValidateToSarif(shapesTtl, dataNt)` / `shaclEntail(shapesTtl, dataNt)` — SHACL
|
|
84
|
+
validation to a SARIF 2.1.0 report and SHACL-AF `sh:rule` entailment to N-Triples.
|
|
77
85
|
- `Sink`, `datasetToStream`, `streamToDataset` — the async RDF/JS
|
|
78
86
|
Stream/Sink primitives over the synchronous engine surface.
|
|
79
87
|
- SPARQL evaluation over the in-memory dataset (no server required).
|
|
@@ -83,8 +91,8 @@ Full typings ship in `index.d.ts`.
|
|
|
83
91
|
## Scope
|
|
84
92
|
|
|
85
93
|
In-memory only, by design: no persistent store and no network I/O inside the
|
|
86
|
-
wasm module. For the container transport (GTS),
|
|
87
|
-
|
|
94
|
+
wasm module. For the container transport (GTS), SPARQL result serializers, and the
|
|
95
|
+
rest of the toolkit, see the
|
|
88
96
|
[main repository](https://github.com/Blackcat-Informatics/purrdf).
|
|
89
97
|
|
|
90
98
|
## Supply chain
|
package/index.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Blackcat Informatics® Inc. <paudley@blackcatinformatics.ca>
|
|
2
2
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
3
3
|
|
|
4
|
-
// The wasm-bindgen-generated class declarations (DataFactory/Dataset/Quad/Sink/Term
|
|
5
|
-
// and the free `version()`
|
|
4
|
+
// The wasm-bindgen-generated class declarations (DataFactory/Dataset/Quad/Sink/Term)
|
|
5
|
+
// and the free functions (`version()`, `shaclValidateToSarif`, `shaclEntail`) are the
|
|
6
|
+
// source of truth for the engine surface — the whole `#[wasm_bindgen]` surface is
|
|
7
|
+
// re-exported from the package root (Dataset.canonicalize()/isomorphic() ship on the
|
|
8
|
+
// Dataset class itself).
|
|
6
9
|
export {
|
|
7
10
|
DataFactory,
|
|
8
11
|
Dataset,
|
|
9
12
|
Quad,
|
|
13
|
+
shaclEntail,
|
|
14
|
+
shaclValidateToSarif,
|
|
10
15
|
Sink,
|
|
11
16
|
Term,
|
|
12
17
|
version,
|
package/index.mjs
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
// purrdf — the idiomatic RDF/JS surface over the wasm engine.
|
|
5
5
|
//
|
|
6
|
-
// The wasm-bindgen-generated classes (DataFactory/Dataset/Quad/Sink/Term)
|
|
7
|
-
// re-exported as-is
|
|
6
|
+
// The wasm-bindgen-generated classes (DataFactory/Dataset/Quad/Sink/Term) and the
|
|
7
|
+
// free functions (version, shaclValidateToSarif, shaclEntail) are re-exported as-is —
|
|
8
|
+
// the whole `#[wasm_bindgen]` surface is reachable from the package root, so
|
|
9
|
+
// SHACL validation/entailment and Dataset.canonicalize()/isomorphic() need no deep
|
|
10
|
+
// `./pkg/` import. This wrapper adds the isomorphic glue that the synchronous
|
|
8
11
|
// wasm boundary cannot express in Rust:
|
|
9
12
|
// * `ready()` — one-time async wasm instantiation (required for the `web` target).
|
|
10
13
|
// * the polymorphic RDF/JS `DataFactory.literal(value, languageOrDatatype)` —
|
|
@@ -18,6 +21,8 @@ import init, {
|
|
|
18
21
|
DataFactory,
|
|
19
22
|
Dataset,
|
|
20
23
|
Quad,
|
|
24
|
+
shaclEntail,
|
|
25
|
+
shaclValidateToSarif,
|
|
21
26
|
Sink,
|
|
22
27
|
Term,
|
|
23
28
|
version,
|
|
@@ -125,4 +130,13 @@ export async function streamToDataset(quadStream) {
|
|
|
125
130
|
return sink.finish();
|
|
126
131
|
}
|
|
127
132
|
|
|
128
|
-
export {
|
|
133
|
+
export {
|
|
134
|
+
DataFactory,
|
|
135
|
+
Dataset,
|
|
136
|
+
Quad,
|
|
137
|
+
shaclEntail,
|
|
138
|
+
shaclValidateToSarif,
|
|
139
|
+
Sink,
|
|
140
|
+
Term,
|
|
141
|
+
version,
|
|
142
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackcatinformatics/purrdf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A wasm32, in-memory RDF 1.2 engine with an idiomatic RDF/JS (DataFactory/Dataset/Stream) API. Quoted-triple terms and directional literals included.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
package/pkg/purrdf_wasm.d.ts
CHANGED
|
@@ -45,6 +45,9 @@ export class DataFactory {
|
|
|
45
45
|
* `namedNode(value)` → a `NamedNode` term.
|
|
46
46
|
*/
|
|
47
47
|
namedNode(value: string): Term;
|
|
48
|
+
/**
|
|
49
|
+
* `new DataFactory()` — a fresh factory with its blank-node counter at zero.
|
|
50
|
+
*/
|
|
48
51
|
constructor();
|
|
49
52
|
/**
|
|
50
53
|
* `quad(subject, predicate, object, graph?)` → a `Quad`. The graph defaults to the
|
|
@@ -80,6 +83,15 @@ export class Dataset {
|
|
|
80
83
|
* `add(quad)` → insert a quad. Returns `true` if the effective set changed.
|
|
81
84
|
*/
|
|
82
85
|
add(quad: Quad): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* `canonicalize()` → the dataset as canonical, flat N-Quads under RDFC-1.0
|
|
88
|
+
* (SHA-256).
|
|
89
|
+
*
|
|
90
|
+
* The deterministic identity string for the graph: two datasets denote the same
|
|
91
|
+
* RDF graph (under blank-node relabeling) iff their canonical forms are
|
|
92
|
+
* byte-identical. This is the same RDFC-1.0 output the conformance gate pins.
|
|
93
|
+
*/
|
|
94
|
+
canonicalize(): string;
|
|
83
95
|
/**
|
|
84
96
|
* `delete(quad)` → remove a quad. Returns `true` if the effective set changed.
|
|
85
97
|
*/
|
|
@@ -88,6 +100,16 @@ export class Dataset {
|
|
|
88
100
|
* `has(quad)` → whether the quad is in the dataset.
|
|
89
101
|
*/
|
|
90
102
|
has(quad: Quad): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* `isomorphic(other)` → whether this dataset and `other` are the same RDF graph
|
|
105
|
+
* under blank-node relabeling.
|
|
106
|
+
*
|
|
107
|
+
* The formal RDF graph-identity check, backed by full RDFC-1.0 canonicalization:
|
|
108
|
+
* an exact oracle with no false positives or false negatives. Equivalent to
|
|
109
|
+
* comparing the two [`canonicalize`](Self::canonicalize) strings, but avoids
|
|
110
|
+
* materializing them for obviously-different inputs.
|
|
111
|
+
*/
|
|
112
|
+
isomorphic(other: Dataset): boolean;
|
|
91
113
|
/**
|
|
92
114
|
* `match(subject?, predicate?, object?, graph?)` → a new dataset of the matching
|
|
93
115
|
* quads. An omitted (`undefined`) position is a wildcard; `defaultGraph()` matches
|
|
@@ -150,9 +172,21 @@ export class Quad {
|
|
|
150
172
|
* Structural RDF/JS quad equality.
|
|
151
173
|
*/
|
|
152
174
|
equals(other: Quad): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* The graph [`Term`] of the quad (`DefaultGraph` when unnamed).
|
|
177
|
+
*/
|
|
153
178
|
readonly graph: Term;
|
|
179
|
+
/**
|
|
180
|
+
* The object [`Term`] of the quad.
|
|
181
|
+
*/
|
|
154
182
|
readonly object: Term;
|
|
183
|
+
/**
|
|
184
|
+
* The predicate [`Term`] of the quad.
|
|
185
|
+
*/
|
|
155
186
|
readonly predicate: Term;
|
|
187
|
+
/**
|
|
188
|
+
* The subject [`Term`] of the quad.
|
|
189
|
+
*/
|
|
156
190
|
readonly subject: Term;
|
|
157
191
|
/**
|
|
158
192
|
* Always `"Quad"` (a Quad is itself an RDF/JS term).
|
|
@@ -176,6 +210,9 @@ export class Sink {
|
|
|
176
210
|
* resulting dataset. The sink is consumed; further `push`/`finish` is an error.
|
|
177
211
|
*/
|
|
178
212
|
finish(): Dataset;
|
|
213
|
+
/**
|
|
214
|
+
* `new Sink()` — an empty sink ready to accept quads via `push`.
|
|
215
|
+
*/
|
|
179
216
|
constructor();
|
|
180
217
|
/**
|
|
181
218
|
* `push(quad)` — stream one quad into the sink (interned via the event protocol).
|
|
@@ -284,8 +321,10 @@ export interface InitOutput {
|
|
|
284
321
|
readonly datafactory_typedLiteral: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
285
322
|
readonly datafactory_variable: (a: number, b: number, c: number) => number;
|
|
286
323
|
readonly dataset_add: (a: number, b: number, c: number) => void;
|
|
324
|
+
readonly dataset_canonicalize: (a: number, b: number) => void;
|
|
287
325
|
readonly dataset_delete: (a: number, b: number, c: number) => void;
|
|
288
326
|
readonly dataset_has: (a: number, b: number, c: number) => void;
|
|
327
|
+
readonly dataset_isomorphic: (a: number, b: number, c: number) => void;
|
|
289
328
|
readonly dataset_match: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
290
329
|
readonly dataset_new: (a: number) => void;
|
|
291
330
|
readonly dataset_parse: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
package/pkg/purrdf_wasm.js
CHANGED
|
@@ -116,6 +116,9 @@ export class DataFactory {
|
|
|
116
116
|
const ret = wasm.datafactory_namedNode(this.__wbg_ptr, ptr0, len0);
|
|
117
117
|
return Term.__wrap(ret);
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* `new DataFactory()` — a fresh factory with its blank-node counter at zero.
|
|
121
|
+
*/
|
|
119
122
|
constructor() {
|
|
120
123
|
const ret = wasm.datafactory_new();
|
|
121
124
|
this.__wbg_ptr = ret;
|
|
@@ -252,6 +255,39 @@ export class Dataset {
|
|
|
252
255
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
253
256
|
}
|
|
254
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* `canonicalize()` → the dataset as canonical, flat N-Quads under RDFC-1.0
|
|
260
|
+
* (SHA-256).
|
|
261
|
+
*
|
|
262
|
+
* The deterministic identity string for the graph: two datasets denote the same
|
|
263
|
+
* RDF graph (under blank-node relabeling) iff their canonical forms are
|
|
264
|
+
* byte-identical. This is the same RDFC-1.0 output the conformance gate pins.
|
|
265
|
+
* @returns {string}
|
|
266
|
+
*/
|
|
267
|
+
canonicalize() {
|
|
268
|
+
let deferred2_0;
|
|
269
|
+
let deferred2_1;
|
|
270
|
+
try {
|
|
271
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
272
|
+
wasm.dataset_canonicalize(retptr, this.__wbg_ptr);
|
|
273
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
274
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
275
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
276
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
277
|
+
var ptr1 = r0;
|
|
278
|
+
var len1 = r1;
|
|
279
|
+
if (r3) {
|
|
280
|
+
ptr1 = 0; len1 = 0;
|
|
281
|
+
throw takeObject(r2);
|
|
282
|
+
}
|
|
283
|
+
deferred2_0 = ptr1;
|
|
284
|
+
deferred2_1 = len1;
|
|
285
|
+
return getStringFromWasm0(ptr1, len1);
|
|
286
|
+
} finally {
|
|
287
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
288
|
+
wasm.__wbindgen_export3(deferred2_0, deferred2_1, 1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
255
291
|
/**
|
|
256
292
|
* `delete(quad)` → remove a quad. Returns `true` if the effective set changed.
|
|
257
293
|
* @param {Quad} quad
|
|
@@ -294,6 +330,33 @@ export class Dataset {
|
|
|
294
330
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
295
331
|
}
|
|
296
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* `isomorphic(other)` → whether this dataset and `other` are the same RDF graph
|
|
335
|
+
* under blank-node relabeling.
|
|
336
|
+
*
|
|
337
|
+
* The formal RDF graph-identity check, backed by full RDFC-1.0 canonicalization:
|
|
338
|
+
* an exact oracle with no false positives or false negatives. Equivalent to
|
|
339
|
+
* comparing the two [`canonicalize`](Self::canonicalize) strings, but avoids
|
|
340
|
+
* materializing them for obviously-different inputs.
|
|
341
|
+
* @param {Dataset} other
|
|
342
|
+
* @returns {boolean}
|
|
343
|
+
*/
|
|
344
|
+
isomorphic(other) {
|
|
345
|
+
try {
|
|
346
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
347
|
+
_assertClass(other, Dataset);
|
|
348
|
+
wasm.dataset_isomorphic(retptr, this.__wbg_ptr, other.__wbg_ptr);
|
|
349
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
350
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
351
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
352
|
+
if (r2) {
|
|
353
|
+
throw takeObject(r1);
|
|
354
|
+
}
|
|
355
|
+
return r0 !== 0;
|
|
356
|
+
} finally {
|
|
357
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
297
360
|
/**
|
|
298
361
|
* `match(subject?, predicate?, object?, graph?)` → a new dataset of the matching
|
|
299
362
|
* quads. An omitted (`undefined`) position is a wildcard; `defaultGraph()` matches
|
|
@@ -550,6 +613,7 @@ export class Quad {
|
|
|
550
613
|
return ret !== 0;
|
|
551
614
|
}
|
|
552
615
|
/**
|
|
616
|
+
* The graph [`Term`] of the quad (`DefaultGraph` when unnamed).
|
|
553
617
|
* @returns {Term}
|
|
554
618
|
*/
|
|
555
619
|
get graph() {
|
|
@@ -557,6 +621,7 @@ export class Quad {
|
|
|
557
621
|
return Term.__wrap(ret);
|
|
558
622
|
}
|
|
559
623
|
/**
|
|
624
|
+
* The object [`Term`] of the quad.
|
|
560
625
|
* @returns {Term}
|
|
561
626
|
*/
|
|
562
627
|
get object() {
|
|
@@ -564,6 +629,7 @@ export class Quad {
|
|
|
564
629
|
return Term.__wrap(ret);
|
|
565
630
|
}
|
|
566
631
|
/**
|
|
632
|
+
* The predicate [`Term`] of the quad.
|
|
567
633
|
* @returns {Term}
|
|
568
634
|
*/
|
|
569
635
|
get predicate() {
|
|
@@ -571,6 +637,7 @@ export class Quad {
|
|
|
571
637
|
return Term.__wrap(ret);
|
|
572
638
|
}
|
|
573
639
|
/**
|
|
640
|
+
* The subject [`Term`] of the quad.
|
|
574
641
|
* @returns {Term}
|
|
575
642
|
*/
|
|
576
643
|
get subject() {
|
|
@@ -655,6 +722,9 @@ export class Sink {
|
|
|
655
722
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
656
723
|
}
|
|
657
724
|
}
|
|
725
|
+
/**
|
|
726
|
+
* `new Sink()` — an empty sink ready to accept quads via `push`.
|
|
727
|
+
*/
|
|
658
728
|
constructor() {
|
|
659
729
|
const ret = wasm.sink_new();
|
|
660
730
|
this.__wbg_ptr = ret;
|
package/pkg/purrdf_wasm_bg.wasm
CHANGED
|
Binary file
|
|
@@ -19,8 +19,10 @@ export const datafactory_quotedTriple: (a: number, b: number, c: number, d: numb
|
|
|
19
19
|
export const datafactory_typedLiteral: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
20
20
|
export const datafactory_variable: (a: number, b: number, c: number) => number;
|
|
21
21
|
export const dataset_add: (a: number, b: number, c: number) => void;
|
|
22
|
+
export const dataset_canonicalize: (a: number, b: number) => void;
|
|
22
23
|
export const dataset_delete: (a: number, b: number, c: number) => void;
|
|
23
24
|
export const dataset_has: (a: number, b: number, c: number) => void;
|
|
25
|
+
export const dataset_isomorphic: (a: number, b: number, c: number) => void;
|
|
24
26
|
export const dataset_match: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
25
27
|
export const dataset_new: (a: number) => void;
|
|
26
28
|
export const dataset_parse: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|