@factoidal/core 0.7.1 → 0.11.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.
Files changed (195) hide show
  1. package/CHANGELOG.md +616 -1
  2. package/NOTICE +2 -21
  3. package/README.md +123 -993
  4. package/api.d.ts +53 -0
  5. package/api.js +5 -0
  6. package/api.mjs +56 -0
  7. package/bin/engine.mjs +38 -19
  8. package/bin/ext.mjs +16 -20
  9. package/bin/factoidal.mjs +667 -118
  10. package/bin/pack.mjs +37 -0
  11. package/bin/serve-worker.mjs +32 -0
  12. package/bin/serve.mjs +423 -0
  13. package/bin/store-worker-host.mjs +1 -1
  14. package/bin/store.mjs +1 -1
  15. package/browser.d.ts +114 -507
  16. package/browser.js +155 -2257
  17. package/docs/fuseki-replacement.md +108 -0
  18. package/fn.d.ts +25 -96
  19. package/fn.js +131 -240
  20. package/index.d.ts +620 -260
  21. package/index.js +4 -234
  22. package/index.mjs +180 -84
  23. package/l4-assets/l4factoidal.js +47 -7
  24. package/l4-assets/l4factoidal.mjs +1 -1
  25. package/l4-assets/l4factoidal.wasm +0 -0
  26. package/l4-assets/version.json +11 -7
  27. package/lib/api.mjs +2337 -0
  28. package/lib/browser-engine.mjs +69 -0
  29. package/lib/dataset.mjs +471 -0
  30. package/lib/delta-log-hosts.mjs +191 -0
  31. package/lib/lean-entry.mjs +213 -0
  32. package/lib/pure.mjs +98 -0
  33. package/lib/store.mjs +115 -0
  34. package/lib/version.mjs +5 -0
  35. package/lws/README.md +137 -0
  36. package/lws/persist.mjs +78 -0
  37. package/lws/server.mjs +416 -0
  38. package/package.json +59 -61
  39. package/rdfjs.js +5 -536
  40. package/rdfjs.mjs +517 -0
  41. package/sample-store.d.ts +8 -16
  42. package/sample-store.mjs +39 -29
  43. package/solid/client/README.md +100 -0
  44. package/solid/client/index.mjs +293 -0
  45. package/solid/server/README.md +96 -0
  46. package/solid/server/index.mjs +395 -0
  47. package/store-host/deno.mjs +8 -0
  48. package/store-host/index.mjs +12 -0
  49. package/store-host/node.mjs +8 -0
  50. package/xmpp/README.md +107 -0
  51. package/xmpp/index.mjs +229 -0
  52. package/browser-wasm.js +0 -872
  53. package/factoidal-npm-entry.js +0 -15477
  54. package/factoidal-npm-entry.wasm.assets/code-5a7fc68f2ab1323718b8.wasm +0 -0
  55. package/factoidal-npm-entry.wasm.js +0 -455
  56. package/factoidal.js +0 -13118
  57. package/factoidal.wasm.assets/code-bbe6099bfb5b10c4c3ab.wasm +0 -0
  58. package/factoidal.wasm.js +0 -457
  59. package/hacl-init.js +0 -92
  60. package/hacl-wasm/FStar.wasm +0 -0
  61. package/hacl-wasm/Hacl_Bignum.wasm +0 -0
  62. package/hacl-wasm/Hacl_Bignum25519_51.wasm +0 -0
  63. package/hacl-wasm/Hacl_Bignum_Base.wasm +0 -0
  64. package/hacl-wasm/Hacl_Curve25519_51.wasm +0 -0
  65. package/hacl-wasm/Hacl_Ed25519.wasm +0 -0
  66. package/hacl-wasm/Hacl_Ed25519_PrecompTable.wasm +0 -0
  67. package/hacl-wasm/Hacl_Hash_Base.wasm +0 -0
  68. package/hacl-wasm/Hacl_Hash_SHA2.wasm +0 -0
  69. package/hacl-wasm/Hacl_IntTypes_Intrinsics.wasm +0 -0
  70. package/hacl-wasm/LowStar_Endianness.wasm +0 -0
  71. package/hacl-wasm/WasmSupport.wasm +0 -0
  72. package/hacl-wasm/api.js +0 -775
  73. package/hacl-wasm/api.json +0 -3787
  74. package/hacl-wasm/layouts.json +0 -1
  75. package/hacl-wasm/loader.js +0 -568
  76. package/hacl-wasm/shell.js +0 -12
  77. package/l4-core.d.ts +0 -159
  78. package/l4-core.js +0 -188
  79. package/l4.d.ts +0 -50
  80. package/l4.js +0 -104
  81. package/lib/api.js +0 -2300
  82. package/lib/engine-js.js +0 -165
  83. package/lib/engine-wasm.js +0 -300
  84. package/sample-store/CURRENT +0 -1
  85. package/sample-store/gen-1/manifest.sbm2 +0 -0
  86. package/sample-store/gen-1/manifest.tsv +0 -14
  87. package/sample-store/gen-1/predicate-0.ibk3 +0 -0
  88. package/sample-store/gen-1/predicate-0.ibk3.merkle +0 -1
  89. package/sample-store/gen-1/predicate-0.ibk3.oli2 +0 -0
  90. package/sample-store/gen-1/predicate-0.ibk3.oli2.merkle +0 -1
  91. package/sample-store/gen-1/predicate-0.ibk3.sri2 +0 -0
  92. package/sample-store/gen-1/predicate-0.ibk3.sri2.merkle +0 -1
  93. package/sample-store/gen-1/predicate-0.ibk3.tli1 +0 -0
  94. package/sample-store/gen-1/predicate-0.ibk3.tli1.merkle +0 -0
  95. package/sample-store/gen-1/predicate-1.ibk3 +0 -0
  96. package/sample-store/gen-1/predicate-1.ibk3.merkle +0 -0
  97. package/sample-store/gen-1/predicate-1.ibk3.oli2 +0 -0
  98. package/sample-store/gen-1/predicate-1.ibk3.oli2.merkle +0 -0
  99. package/sample-store/gen-1/predicate-1.ibk3.sri2 +0 -0
  100. package/sample-store/gen-1/predicate-1.ibk3.sri2.merkle +0 -1
  101. package/sample-store/gen-1/predicate-1.ibk3.tli1 +0 -0
  102. package/sample-store/gen-1/predicate-1.ibk3.tli1.merkle +0 -1
  103. package/sample-store/gen-1/predicate-10.ibk3 +0 -0
  104. package/sample-store/gen-1/predicate-10.ibk3.merkle +0 -1
  105. package/sample-store/gen-1/predicate-10.ibk3.oli2 +0 -0
  106. package/sample-store/gen-1/predicate-10.ibk3.oli2.merkle +0 -0
  107. package/sample-store/gen-1/predicate-10.ibk3.sri2 +0 -0
  108. package/sample-store/gen-1/predicate-10.ibk3.sri2.merkle +0 -1
  109. package/sample-store/gen-1/predicate-10.ibk3.tli1 +0 -0
  110. package/sample-store/gen-1/predicate-10.ibk3.tli1.merkle +0 -1
  111. package/sample-store/gen-1/predicate-11.ibk3 +0 -0
  112. package/sample-store/gen-1/predicate-11.ibk3.merkle +0 -0
  113. package/sample-store/gen-1/predicate-11.ibk3.oli2 +0 -0
  114. package/sample-store/gen-1/predicate-11.ibk3.oli2.merkle +0 -1
  115. package/sample-store/gen-1/predicate-11.ibk3.sri2 +0 -0
  116. package/sample-store/gen-1/predicate-11.ibk3.sri2.merkle +0 -1
  117. package/sample-store/gen-1/predicate-11.ibk3.tli1 +0 -0
  118. package/sample-store/gen-1/predicate-11.ibk3.tli1.merkle +0 -1
  119. package/sample-store/gen-1/predicate-12.ibk3 +0 -0
  120. package/sample-store/gen-1/predicate-12.ibk3.merkle +0 -1
  121. package/sample-store/gen-1/predicate-12.ibk3.oli2 +0 -0
  122. package/sample-store/gen-1/predicate-12.ibk3.oli2.merkle +0 -1
  123. package/sample-store/gen-1/predicate-12.ibk3.sri2 +0 -0
  124. package/sample-store/gen-1/predicate-12.ibk3.sri2.merkle +0 -1
  125. package/sample-store/gen-1/predicate-12.ibk3.tli1 +0 -0
  126. package/sample-store/gen-1/predicate-12.ibk3.tli1.merkle +0 -1
  127. package/sample-store/gen-1/predicate-2.ibk3 +0 -0
  128. package/sample-store/gen-1/predicate-2.ibk3.merkle +0 -1
  129. package/sample-store/gen-1/predicate-2.ibk3.oli2 +0 -0
  130. package/sample-store/gen-1/predicate-2.ibk3.oli2.merkle +0 -1
  131. package/sample-store/gen-1/predicate-2.ibk3.sri2 +0 -0
  132. package/sample-store/gen-1/predicate-2.ibk3.sri2.merkle +0 -0
  133. package/sample-store/gen-1/predicate-2.ibk3.tli1 +0 -0
  134. package/sample-store/gen-1/predicate-2.ibk3.tli1.merkle +0 -0
  135. package/sample-store/gen-1/predicate-3.ibk3 +0 -0
  136. package/sample-store/gen-1/predicate-3.ibk3.merkle +0 -1
  137. package/sample-store/gen-1/predicate-3.ibk3.oli2 +0 -0
  138. package/sample-store/gen-1/predicate-3.ibk3.oli2.merkle +0 -1
  139. package/sample-store/gen-1/predicate-3.ibk3.sri2 +0 -0
  140. package/sample-store/gen-1/predicate-3.ibk3.sri2.merkle +0 -1
  141. package/sample-store/gen-1/predicate-3.ibk3.tli1 +0 -0
  142. package/sample-store/gen-1/predicate-3.ibk3.tli1.merkle +0 -1
  143. package/sample-store/gen-1/predicate-4.ibk3 +0 -0
  144. package/sample-store/gen-1/predicate-4.ibk3.merkle +0 -0
  145. package/sample-store/gen-1/predicate-4.ibk3.oli2 +0 -0
  146. package/sample-store/gen-1/predicate-4.ibk3.oli2.merkle +0 -1
  147. package/sample-store/gen-1/predicate-4.ibk3.sri2 +0 -0
  148. package/sample-store/gen-1/predicate-4.ibk3.sri2.merkle +0 -1
  149. package/sample-store/gen-1/predicate-4.ibk3.tli1 +0 -0
  150. package/sample-store/gen-1/predicate-4.ibk3.tli1.merkle +0 -2
  151. package/sample-store/gen-1/predicate-5.ibk3 +0 -0
  152. package/sample-store/gen-1/predicate-5.ibk3.merkle +0 -1
  153. package/sample-store/gen-1/predicate-5.ibk3.oli2 +0 -0
  154. package/sample-store/gen-1/predicate-5.ibk3.oli2.merkle +0 -1
  155. package/sample-store/gen-1/predicate-5.ibk3.sri2 +0 -0
  156. package/sample-store/gen-1/predicate-5.ibk3.sri2.merkle +0 -1
  157. package/sample-store/gen-1/predicate-5.ibk3.tli1 +0 -0
  158. package/sample-store/gen-1/predicate-5.ibk3.tli1.merkle +0 -1
  159. package/sample-store/gen-1/predicate-6.ibk3 +0 -0
  160. package/sample-store/gen-1/predicate-6.ibk3.merkle +0 -1
  161. package/sample-store/gen-1/predicate-6.ibk3.oli2 +0 -0
  162. package/sample-store/gen-1/predicate-6.ibk3.oli2.merkle +0 -1
  163. package/sample-store/gen-1/predicate-6.ibk3.sri2 +0 -0
  164. package/sample-store/gen-1/predicate-6.ibk3.sri2.merkle +0 -1
  165. package/sample-store/gen-1/predicate-6.ibk3.tli1 +0 -0
  166. package/sample-store/gen-1/predicate-6.ibk3.tli1.merkle +0 -0
  167. package/sample-store/gen-1/predicate-7.ibk3 +0 -0
  168. package/sample-store/gen-1/predicate-7.ibk3.merkle +0 -0
  169. package/sample-store/gen-1/predicate-7.ibk3.oli2 +0 -0
  170. package/sample-store/gen-1/predicate-7.ibk3.oli2.merkle +0 -2
  171. package/sample-store/gen-1/predicate-7.ibk3.sri2 +0 -0
  172. package/sample-store/gen-1/predicate-7.ibk3.sri2.merkle +0 -1
  173. package/sample-store/gen-1/predicate-7.ibk3.tli1 +0 -0
  174. package/sample-store/gen-1/predicate-7.ibk3.tli1.merkle +0 -1
  175. package/sample-store/gen-1/predicate-8.ibk3 +0 -0
  176. package/sample-store/gen-1/predicate-8.ibk3.merkle +0 -1
  177. package/sample-store/gen-1/predicate-8.ibk3.oli2 +0 -0
  178. package/sample-store/gen-1/predicate-8.ibk3.oli2.merkle +0 -1
  179. package/sample-store/gen-1/predicate-8.ibk3.sri2 +0 -0
  180. package/sample-store/gen-1/predicate-8.ibk3.sri2.merkle +0 -1
  181. package/sample-store/gen-1/predicate-8.ibk3.tli1 +0 -0
  182. package/sample-store/gen-1/predicate-8.ibk3.tli1.merkle +0 -1
  183. package/sample-store/gen-1/predicate-9.ibk3 +0 -0
  184. package/sample-store/gen-1/predicate-9.ibk3.merkle +0 -1
  185. package/sample-store/gen-1/predicate-9.ibk3.oli2 +0 -0
  186. package/sample-store/gen-1/predicate-9.ibk3.oli2.merkle +0 -1
  187. package/sample-store/gen-1/predicate-9.ibk3.sri2 +0 -0
  188. package/sample-store/gen-1/predicate-9.ibk3.sri2.merkle +0 -3
  189. package/sample-store/gen-1/predicate-9.ibk3.tli1 +0 -0
  190. package/sample-store/gen-1/predicate-9.ibk3.tli1.merkle +0 -2
  191. package/select.d.ts +0 -116
  192. package/select.js +0 -492
  193. package/version.json +0 -102
  194. package/wasm.d.ts +0 -130
  195. package/wasm.js +0 -158
package/rdfjs.mjs ADDED
@@ -0,0 +1,517 @@
1
+ // factoidal — RDF/JS data model + N-Quads token converters.
2
+ //
3
+ // Implements the RDF/JS Data Model specification
4
+ // (https://rdf.js.org/data-model-spec/): DataFactory producing
5
+ // NamedNode / BlankNode / Literal / Variable / DefaultGraph / Quad
6
+ // terms with spec-compliant `termType` / `value` / `language` /
7
+ // `datatype` and `.equals()`. Self-contained — no runtime deps.
8
+ //
9
+ // Also: the field copy between RDF/JS terms and the engine's term objects
10
+ // (Lean L4Factoidal.RDF.TermJson), and N-Quads text in and out through
11
+ // engine ops. This file reads and writes no RDF syntax itself: no escaping,
12
+ // no tokenising (https://github.com/danbri/factoidal/issues/894). The text
13
+ // functions need the engine, which lib/api.mjs installs when it loads.
14
+ //
15
+ // ES module (0.9.0): the same file serves Node (index.mjs, and rdfjs.js for
16
+ // require()) and the browser (browser.js), with no build step.
17
+
18
+ // RDF/JS Data Model defaults of DataFactory.literal.
19
+ const XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string'; // purity-lint: allow RDF/JS DataFactory default
20
+ const RDF_LANGSTRING =
21
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; // purity-lint: allow RDF/JS DataFactory default
22
+ const RDF_DIRLANGSTRING =
23
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString'; // purity-lint: allow RDF/JS DataFactory default
24
+
25
+ // ---------------------------------------------------------------------
26
+ // Terms
27
+ // ---------------------------------------------------------------------
28
+
29
+ class NamedNode {
30
+ constructor(iri) {
31
+ this.termType = 'NamedNode';
32
+ this.value = iri;
33
+ Object.freeze(this);
34
+ }
35
+ equals(other) {
36
+ return !!other && other.termType === 'NamedNode' &&
37
+ other.value === this.value;
38
+ }
39
+ }
40
+
41
+ class BlankNode {
42
+ constructor(label) {
43
+ this.termType = 'BlankNode';
44
+ this.value = label;
45
+ Object.freeze(this);
46
+ }
47
+ equals(other) {
48
+ return !!other && other.termType === 'BlankNode' &&
49
+ other.value === this.value;
50
+ }
51
+ }
52
+
53
+ class Literal {
54
+ constructor(value, language, datatype, direction) {
55
+ this.termType = 'Literal';
56
+ this.value = value;
57
+ this.language = language || '';
58
+ // RDF/JS Data Model DataFactory.literal: no datatype argument means
59
+ // xsd:string, a language means rdf:langString, a language and a
60
+ // direction mean rdf:dirLangString.
61
+ this.datatype = datatype ||
62
+ new NamedNode(language ? (direction ? RDF_DIRLANGSTRING : RDF_LANGSTRING) : XSD_STRING); // purity-lint: allow RDF/JS DataFactory default
63
+ this.direction = direction || '';
64
+ Object.freeze(this);
65
+ }
66
+ equals(other) {
67
+ return !!other && other.termType === 'Literal' &&
68
+ other.value === this.value &&
69
+ other.language === this.language &&
70
+ (other.direction || '') === this.direction &&
71
+ !!other.datatype && other.datatype.value === this.datatype.value;
72
+ }
73
+ }
74
+
75
+ class Variable {
76
+ constructor(name) {
77
+ this.termType = 'Variable';
78
+ this.value = name;
79
+ Object.freeze(this);
80
+ }
81
+ equals(other) {
82
+ return !!other && other.termType === 'Variable' &&
83
+ other.value === this.value;
84
+ }
85
+ }
86
+
87
+ class DefaultGraph {
88
+ constructor() {
89
+ this.termType = 'DefaultGraph';
90
+ this.value = '';
91
+ Object.freeze(this);
92
+ }
93
+ equals(other) {
94
+ return !!other && other.termType === 'DefaultGraph';
95
+ }
96
+ }
97
+
98
+ const DEFAULT_GRAPH = new DefaultGraph();
99
+
100
+ class Quad {
101
+ constructor(subject, predicate, object, graph) {
102
+ // Per spec, a Quad is itself a Term with termType 'Quad', value ''.
103
+ this.termType = 'Quad';
104
+ this.value = '';
105
+ this.subject = subject;
106
+ this.predicate = predicate;
107
+ this.object = object;
108
+ this.graph = graph || DEFAULT_GRAPH;
109
+ Object.freeze(this);
110
+ }
111
+ equals(other) {
112
+ return !!other &&
113
+ (other.termType === 'Quad' || other.termType === undefined) &&
114
+ this.subject.equals(other.subject) &&
115
+ this.predicate.equals(other.predicate) &&
116
+ this.object.equals(other.object) &&
117
+ this.graph.equals(other.graph);
118
+ }
119
+ }
120
+
121
+ // ---------------------------------------------------------------------
122
+ // DataFactory
123
+ // ---------------------------------------------------------------------
124
+
125
+ let blankNodeCounter = 0;
126
+
127
+ const dataFactory = {
128
+ namedNode(value) {
129
+ return new NamedNode(String(value));
130
+ },
131
+ blankNode(label) {
132
+ return new BlankNode(
133
+ label !== undefined && label !== null
134
+ ? String(label)
135
+ : 'fjs_b' + (blankNodeCounter++)
136
+ );
137
+ },
138
+ literal(value, languageOrDatatype) {
139
+ const v = String(value);
140
+ if (languageOrDatatype === undefined || languageOrDatatype === null) {
141
+ return new Literal(v, '', null);
142
+ }
143
+ if (typeof languageOrDatatype === 'string') {
144
+ return new Literal(v, languageOrDatatype, null);
145
+ }
146
+ // RDF/JS Data Model 1.1: {language, direction} for a directional
147
+ // language-tagged string.
148
+ if (typeof languageOrDatatype.language === 'string' && languageOrDatatype.termType === undefined) {
149
+ return new Literal(v, languageOrDatatype.language, null, languageOrDatatype.direction || '');
150
+ }
151
+ // A NamedNode datatype.
152
+ if (languageOrDatatype.termType === 'NamedNode') {
153
+ if (languageOrDatatype.value === RDF_LANGSTRING) {
154
+ // langString without a language tag is not constructible; treat
155
+ // as plain string per the most defensive reading of the spec.
156
+ return new Literal(v, '', null);
157
+ }
158
+ return new Literal(v, '', new NamedNode(languageOrDatatype.value));
159
+ }
160
+ throw new TypeError(
161
+ 'literal: second argument must be a language string or a NamedNode'
162
+ );
163
+ },
164
+ variable(name) {
165
+ return new Variable(String(name));
166
+ },
167
+ defaultGraph() {
168
+ return DEFAULT_GRAPH;
169
+ },
170
+ quad(subject, predicate, object, graph) {
171
+ return new Quad(subject, predicate, object, graph);
172
+ },
173
+ fromTerm(original) {
174
+ if (!original || typeof original.termType !== 'string') {
175
+ throw new TypeError('fromTerm: not a term');
176
+ }
177
+ switch (original.termType) {
178
+ case 'NamedNode': return new NamedNode(original.value);
179
+ case 'BlankNode': return new BlankNode(original.value);
180
+ case 'Variable': return new Variable(original.value);
181
+ case 'DefaultGraph': return DEFAULT_GRAPH;
182
+ case 'Literal':
183
+ return new Literal(
184
+ original.value,
185
+ original.language || '',
186
+ original.datatype ? new NamedNode(original.datatype.value) : null,
187
+ original.direction || ''
188
+ );
189
+ case 'Quad': return dataFactory.fromQuad(original);
190
+ default:
191
+ throw new TypeError(`fromTerm: unknown termType '${original.termType}'`);
192
+ }
193
+ },
194
+ fromQuad(original) {
195
+ if (!original || !original.subject) {
196
+ throw new TypeError('fromQuad: not a quad');
197
+ }
198
+ return new Quad(
199
+ dataFactory.fromTerm(original.subject),
200
+ dataFactory.fromTerm(original.predicate),
201
+ dataFactory.fromTerm(original.object),
202
+ original.graph ? dataFactory.fromTerm(original.graph) : DEFAULT_GRAPH
203
+ );
204
+ },
205
+ };
206
+
207
+ // ---------------------------------------------------------------------
208
+ // SPARQL Results JSON term -> RDF/JS term
209
+ // ---------------------------------------------------------------------
210
+
211
+ /**
212
+ * Convert a SPARQL 1.1 Results JSON term object
213
+ * ({type:'uri'|'bnode'|'literal'|'typed-literal', value, 'xml:lang',
214
+ * datatype}) into an RDF/JS term.
215
+ */
216
+ function termFromSrj(t) {
217
+ return termFromSrjWith(t, dataFactory);
218
+ }
219
+
220
+ function termFromSrjWith(t, f) {
221
+ if (!t || typeof t.type !== 'string') {
222
+ throw new TypeError('termFromSrj: not a results-JSON term');
223
+ }
224
+ switch (t.type) {
225
+ case 'uri':
226
+ return f.namedNode(t.value);
227
+ case 'bnode':
228
+ return f.blankNode(t.value);
229
+ case 'literal':
230
+ case 'typed-literal': {
231
+ const lang = t['xml:lang'];
232
+ if (lang) {
233
+ if (t['its:dir'] && f === dataFactory) {
234
+ return new Literal(t.value, lang,
235
+ t.datatype ? new NamedNode(t.datatype) : null, t['its:dir']);
236
+ }
237
+ return f.literal(t.value, lang);
238
+ }
239
+ if (t.datatype) return f.literal(t.value, f.namedNode(t.datatype));
240
+ return f.literal(t.value);
241
+ }
242
+ case 'triple': {
243
+ // RDF 1.2 triple term:
244
+ // {"type":"triple","value":{"subject":T,"predicate":T,"object":T}}
245
+ // -> an RDF/JS Quad term. The object may itself be a triple term.
246
+ const v = t.value || {};
247
+ return f.quad(termFromSrjWith(v.subject, f), termFromSrjWith(v.predicate, f),
248
+ termFromSrjWith(v.object, f));
249
+ }
250
+ default:
251
+ throw new TypeError(`termFromSrj: unknown term type '${t.type}'`);
252
+ }
253
+ }
254
+
255
+ // ---------------------------------------------------------------------
256
+ // RDF/JS term <-> engine term object (Lean `L4Factoidal.RDF.TermJson`).
257
+ //
258
+ // These functions copy fields; they read and write no RDF syntax. Every
259
+ // N-Quads parse and write below is an engine op
260
+ // (https://github.com/danbri/factoidal/issues/894 items 1 and 2).
261
+ // ---------------------------------------------------------------------
262
+
263
+ /** The engine term object of an RDF/JS term (`TermJson.encodeTerm`'s shape). */
264
+ function termToJson(term) {
265
+ if (term === null || term === undefined) return null;
266
+ // A term given as text is one RDF 1.2 N-Triples term (`<IRI>`, `_:label`,
267
+ // a literal, `<<( s p o )>>`). The engine reads it
268
+ // (L4Factoidal.RDF.TermJson.readTermString); this file copies the text.
269
+ if (typeof term === 'string') return { type: 'nt', value: term };
270
+ switch (term.termType) {
271
+ case 'NamedNode': return { type: 'uri', value: term.value };
272
+ case 'BlankNode': return { type: 'bnode', value: term.value };
273
+ case 'Literal': {
274
+ const o = { type: 'literal', value: term.value };
275
+ if (term.datatype) o.datatype = term.datatype.value;
276
+ if (term.language) o['xml:lang'] = term.language;
277
+ if (term.direction) o['its:dir'] = term.direction;
278
+ return o;
279
+ }
280
+ case 'Quad':
281
+ return { type: 'triple', value: {
282
+ subject: termToJson(term.subject), predicate: termToJson(term.predicate),
283
+ object: termToJson(term.object) } };
284
+ case 'DefaultGraph': return { type: 'default' };
285
+ default:
286
+ throw new TypeError(`termToJson: cannot send termType '${term.termType}' to the engine`);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * The engine term object of a term an application supplies, for example an
292
+ * extension function's answer: an RDF/JS term (duck-typed on termType), an
293
+ * engine term object ({type, value, ...}), or a plain object
294
+ * {value, datatype} or {value, language, direction?}. The components are
295
+ * copied as given; the engine checks them (TermJson.decodeCheckedTerm) and
296
+ * keeps the lexical form and the datatype IRI unchanged.
297
+ */
298
+ function appTermToJson(out) {
299
+ if (typeof out.termType === 'string') return termToJson(out);
300
+ if (typeof out.type === 'string') return out;
301
+ const o = { type: 'literal', value: out.value };
302
+ if (out.datatype !== undefined && out.datatype !== null) {
303
+ o.datatype = typeof out.datatype === 'string' ? out.datatype : out.datatype.value;
304
+ }
305
+ if (out.language !== undefined && out.language !== null && out.language !== '') o['xml:lang'] = out.language;
306
+ if (out.direction !== undefined && out.direction !== null && out.direction !== '') o['its:dir'] = out.direction;
307
+ return o;
308
+ }
309
+
310
+ /** The engine quad array of an RDF/JS quad: [s, p, o] or [s, p, o, g]. */
311
+ function quadToJson(quad) {
312
+ const out = [termToJson(quad.subject), termToJson(quad.predicate), termToJson(quad.object)];
313
+ if (quad.graph && quad.graph.termType !== 'DefaultGraph') out.push(termToJson(quad.graph));
314
+ return out;
315
+ }
316
+
317
+ /** The RDF/JS quad of an engine quad array. */
318
+ function quadFromJson(arr, factory) {
319
+ const f = factory || dataFactory;
320
+ return f.quad(termFromSrjWith(arr[0], f), termFromSrjWith(arr[1], f),
321
+ termFromSrjWith(arr[2], f), arr.length > 3 ? termFromSrjWith(arr[3], f) : f.defaultGraph());
322
+ }
323
+
324
+ // The engine the text functions below call. lib/api.mjs installs it when it
325
+ // loads the engine; until then they throw.
326
+ let textEngine = null;
327
+
328
+ /** @private lib/api.mjs: install the engine ops the text functions call. */
329
+ function _setTextEngine(engine) { textEngine = engine; }
330
+
331
+ function needEngine(who) {
332
+ if (!textEngine) {
333
+ throw new Error(
334
+ `${who}: N-Quads text is read and written by the engine, which is not ` +
335
+ 'loaded yet. Await any @factoidal/core call first (for example ' +
336
+ '`await ready()`), or use parse() and Dataset.toString().');
337
+ }
338
+ return textEngine;
339
+ }
340
+
341
+ /** One RDF/JS term as its canonical N-Quads token (the engine writes it). */
342
+ function termToNQuads(term) {
343
+ if (term && term.termType === 'DefaultGraph') return '';
344
+ return needEngine('termToNQuads').termTokens([termToJson(term)])[0];
345
+ }
346
+
347
+ /** One RDF/JS quad as its canonical N-Quads line (with trailing newline). */
348
+ function quadToNQuads(quad) {
349
+ return needEngine('quadToNQuads').writeQuads([quadToJson(quad)]);
350
+ }
351
+
352
+ /** An iterable of RDF/JS quads as an N-Quads document, one line per quad. */
353
+ function quadsToNQuads(quads) {
354
+ const arr = [];
355
+ for (const q of quads) arr.push(quadToJson(q));
356
+ return needEngine('quadsToNQuads').writeQuads(arr);
357
+ }
358
+
359
+ /**
360
+ * Parse an N-Quads document (RDF 1.2 grammar) into RDF/JS quads; the engine
361
+ * parses it and rejects any line the grammar rejects.
362
+ * The quads come in the engine's order: the default graph, then each named
363
+ * graph in the order of its first quad.
364
+ * options.blankNodePrefix: prepended to every blank-node label (keeps the
365
+ * labels of separate documents apart); options.factory: an RDF/JS
366
+ * DataFactory.
367
+ */
368
+ function nquadsToQuads(text, options) {
369
+ const opts = options || {};
370
+ const factory = opts.factory || dataFactory;
371
+ const f = opts.blankNodePrefix
372
+ ? { ...factory, blankNode: (label) => factory.blankNode(opts.blankNodePrefix + label) }
373
+ : factory;
374
+ const quads = needEngine('nquadsToQuads').parseQuads(String(text));
375
+ return quads.map((q) => quadFromJson(q, f));
376
+ }
377
+
378
+ /** One N-Quads statement as an RDF/JS quad; null for a blank or comment line. */
379
+ function nquadsLineToQuad(line, _lineNo, factory) {
380
+ const qs = nquadsToQuads(line, { factory });
381
+ return qs.length ? qs[0] : null;
382
+ }
383
+
384
+ // ---------------------------------------------------------------------
385
+ // Dataset — a minimal RDF/JS DatasetCore over an in-memory quad array.
386
+ // ---------------------------------------------------------------------
387
+
388
+ // A string that two terms share exactly when equals() holds between them
389
+ // (the fields each equals() above compares). JSON arrays are
390
+ // self-delimiting, so the key of a quad, four term keys in a row, is
391
+ // injective too. The Dataset keeps the keys of its quads in a Set: add()
392
+ // and has() are then one lookup each. Until 2026-10-10 both scanned the
393
+ // quad array, so building a Dataset of n quads cost n^2/2 equals() calls:
394
+ // 12,000 quads took 3.1 s in parse() (issue 713 stage 5).
395
+ function termKey(t) {
396
+ if (!t) return 'null';
397
+ switch (t.termType) {
398
+ case 'Literal':
399
+ return JSON.stringify(['Literal', t.value, t.language, t.datatype ? t.datatype.value : null,
400
+ t.direction || '']);
401
+ case 'DefaultGraph':
402
+ return '["DefaultGraph"]';
403
+ case 'Quad':
404
+ return '["Quad",' + termKey(t.subject) + ',' + termKey(t.predicate) + ',' +
405
+ termKey(t.object) + ',' + termKey(t.graph) + ']';
406
+ default:
407
+ return JSON.stringify([t.termType, t.value]);
408
+ }
409
+ }
410
+
411
+ function quadKey(q) {
412
+ return termKey(q.subject) + termKey(q.predicate) + termKey(q.object) +
413
+ termKey(q.graph || DEFAULT_GRAPH);
414
+ }
415
+
416
+ /**
417
+ * An in-memory RDF/JS DatasetCore over a quad array. The package's Dataset
418
+ * (lib/dataset.mjs) keeps its data in the engine; this class is for callers
419
+ * that build quads in JavaScript, for example to hand to fn.js.
420
+ */
421
+ class DatasetCore {
422
+ constructor(quads, options) {
423
+ this._quads = [];
424
+ // The quadKey() of every quad in _quads, for set semantics in O(1).
425
+ this._keys = new Set();
426
+ if (quads) for (const q of quads) this.add(q);
427
+ const opts = options || {};
428
+ // Own, non-enumerable properties (issue #680/#681): a frozen
429
+ // snapshot of the prefixes/diagnostics the engine reported at
430
+ // parse time, so JSON.stringify()/toArray() (and any caller
431
+ // enumerating own enumerable keys) see only the quads, exactly as
432
+ // before this landed.
433
+ Object.defineProperty(this, 'prefixes', {
434
+ value: Object.freeze({ ...(opts.prefixes || {}) }),
435
+ enumerable: false, writable: false, configurable: false,
436
+ });
437
+ Object.defineProperty(this, 'diagnostics', {
438
+ value: Object.freeze((opts.diagnostics || []).slice()),
439
+ enumerable: false, writable: false, configurable: false,
440
+ });
441
+ }
442
+ get size() {
443
+ return this._quads.length;
444
+ }
445
+ add(quad) {
446
+ const key = quadKey(quad);
447
+ if (!this._keys.has(key)) {
448
+ this._keys.add(key);
449
+ this._quads.push(quad);
450
+ }
451
+ return this;
452
+ }
453
+ delete(quad) {
454
+ if (this._keys.delete(quadKey(quad))) {
455
+ const ix = this._quads.findIndex((q) => q.equals(quad));
456
+ if (ix >= 0) this._quads.splice(ix, 1);
457
+ }
458
+ return this;
459
+ }
460
+ has(quad) {
461
+ return this._keys.has(quadKey(quad));
462
+ }
463
+ match(subject, predicate, object, graph) {
464
+ const out = new DatasetCore();
465
+ for (const q of this._quads) {
466
+ if (subject && !subject.equals(q.subject)) continue;
467
+ if (predicate && !predicate.equals(q.predicate)) continue;
468
+ if (object && !object.equals(q.object)) continue;
469
+ if (graph && !graph.equals(q.graph)) continue;
470
+ out._quads.push(q);
471
+ out._keys.add(quadKey(q));
472
+ }
473
+ return out;
474
+ }
475
+ [Symbol.iterator]() {
476
+ return this._quads[Symbol.iterator]();
477
+ }
478
+ toArray() {
479
+ return this._quads.slice();
480
+ }
481
+ /** N-Quads text, written by the engine. */
482
+ toNQuads() {
483
+ return quadsToNQuads(this._quads);
484
+ }
485
+ toString() {
486
+ return this.toNQuads();
487
+ }
488
+ static fromNQuads(text, options) {
489
+ return new DatasetCore(nquadsToQuads(text, options), options);
490
+ }
491
+ }
492
+
493
+ export {
494
+ dataFactory,
495
+ NamedNode,
496
+ BlankNode,
497
+ Literal,
498
+ Variable,
499
+ DefaultGraph,
500
+ Quad,
501
+ DatasetCore,
502
+ termFromSrj,
503
+ termToJson,
504
+ appTermToJson,
505
+ quadToJson,
506
+ quadFromJson,
507
+ quadKey,
508
+ termKey,
509
+ _setTextEngine,
510
+ nquadsLineToQuad,
511
+ termToNQuads,
512
+ quadToNQuads,
513
+ quadsToNQuads,
514
+ nquadsToQuads,
515
+ XSD_STRING,
516
+ RDF_LANGSTRING,
517
+ }
package/sample-store.d.ts CHANGED
@@ -1,16 +1,8 @@
1
- /** The collection root of the sample Shardborough store bundled with this
2
- * package: the directory that holds CURRENT. */
3
- export declare function sampleStorePath (): string
4
-
5
- export declare const sampleStoreFacts: Readonly<{
6
- triples: number
7
- blocks: number
8
- layout: string
9
- wireVersion: number
10
- source: string
11
- licence: string
12
- licenceUrl: string
13
- publisher: string
14
- }>
15
-
16
- export default sampleStorePath
1
+ // @factoidal/core/sample-store (Node only): a small store packed on demand.
2
+ /** The triples of the sample store, as Turtle. */
3
+ export const SAMPLE_TURTLE: string;
4
+ /** What the sample store holds. */
5
+ export const sampleStoreFacts: Readonly<{ triples: number; source: string; layout: string }>;
6
+ /** Pack the sample store under `dir` (or a new temporary directory) unless it holds CURRENT; return the root. */
7
+ export function sampleStorePath(dir?: string): string;
8
+ export default sampleStorePath;
package/sample-store.mjs CHANGED
@@ -1,37 +1,47 @@
1
- // The sample Shardborough store this package carries, so a fresh install
2
- // answers a SPARQL query with no other download and no native binary.
1
+ // @factoidal/core/sample-store - a small store made on demand (Node only).
3
2
  //
4
- // The store was packed by `l4block-shard-pack … ibk3` and activated by
5
- // `l4block-shard-activate`. Nothing here decodes it; this module only
6
- // resolves its path inside the installed package.
7
- //
8
- // CONTENT AND LICENCE. Five IPTC NewsCodes vocabularies, published by the
9
- // IPTC under CC BY 4.0 and taken from danbri/skosdex third_party/skos:
10
- // spamfstat, videoqualifier, subjectqualifier, videocodec and spct.
11
- // 4,434 triples in 13 predicate blocks. See NOTICE.
3
+ // Owner, 2026-10-20, verbatim: "All the CLIs are still bundled i just didn't
4
+ // want any actual demo triples cluttering the file." So the package ships no
5
+ // store. sampleStorePath() packs the few triples below (written for this
6
+ // package, no third-party content) into a Shardborough store with the
7
+ // package's own `factoidal pack` and `factoidal activate`, under DIR or the
8
+ // OS temporary directory, and returns the collection root. A DIR that
9
+ // already holds CURRENT is returned as it is.
12
10
 
13
- import { fileUrlToPath, joinPath } from './store-host/paths.mjs'
11
+ import { execFileSync } from 'node:child_process'
12
+ import { existsSync } from 'node:fs'
13
+ import { join } from 'node:path'
14
+ import { fileURLToPath } from 'node:url'
14
15
 
15
- /** The collection root of the bundled sample store: the directory holding
16
- * CURRENT. Pass it to `factoidal inspect` / `factoidal query`, or to
17
- * `openStore` from `@factoidal/core/store-host`. */
18
- export function sampleStorePath () {
19
- const packageRoot = fileUrlToPath(new URL('.', import.meta.url).href)
20
- return joinPath(packageRoot, 'sample-store')
21
- }
16
+ /** The triples of the sample store, as Turtle. */
17
+ export const SAMPLE_TURTLE = `@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
18
+ @prefix ex: <http://example.org/codec/> .
19
+ ex:scheme a skos:ConceptScheme ; skos:prefLabel "Video codecs"@en .
20
+ ex:c1 a skos:Concept ; skos:inScheme ex:scheme ; skos:prefLabel "PAL"@en ; skos:notation "c1" .
21
+ ex:c2 a skos:Concept ; skos:inScheme ex:scheme ; skos:prefLabel "NTSC"@en ; skos:notation "c2" .
22
+ ex:c3 a skos:Concept ; skos:inScheme ex:scheme ; skos:prefLabel "SECAM"@en ; skos:notation "c3" ;
23
+ skos:broader ex:c1 .
24
+ `
22
25
 
23
- /** What the sample store holds, as recorded when it was packed. The engine
24
- * is the authority on every one of these numbers at run time; they are here
25
- * so a caller can print something before it opens the store. */
26
+ /** What the sample store holds. */
26
27
  export const sampleStoreFacts = Object.freeze({
27
- triples: 4434,
28
- blocks: 13,
29
- layout: 'predicate-ibk3-ptd1-sri2-tli1-oli2-merkle-v0',
30
- wireVersion: 6,
31
- source: 'IPTC NewsCodes (spamfstat, videoqualifier, subjectqualifier, videocodec, spct)',
32
- licence: 'CC BY 4.0',
33
- licenceUrl: 'https://creativecommons.org/licenses/by/4.0/',
34
- publisher: 'https://iptc.org/'
28
+ triples: 15,
29
+ source: 'SAMPLE_TURTLE in sample-store.mjs (written for this package)',
30
+ layout: 'ibk3'
35
31
  })
36
32
 
33
+ /**
34
+ * Pack the sample store (if DIR holds no CURRENT) and return its root.
35
+ * @param {string} [dir] the collection root to use; default a new
36
+ * directory under the OS temporary directory
37
+ * @returns {string}
38
+ */
39
+ export function sampleStorePath (dir) {
40
+ if (typeof dir === 'string' && existsSync(join(dir, 'CURRENT'))) return dir
41
+ const cli = fileURLToPath(new URL('./bin/factoidal.mjs', import.meta.url))
42
+ const args = [cli, 'sample-store']
43
+ if (typeof dir === 'string') args.push(dir)
44
+ return execFileSync(process.execPath, args, { encoding: 'utf8' }).trim()
45
+ }
46
+
37
47
  export default sampleStorePath