eyeling 1.29.2 → 1.30.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 (50) hide show
  1. package/README.md +153 -0
  2. package/dist/browser/eyeling.browser.js +711 -21
  3. package/examples/input/rdf-surfaces-all-values-from-reverse.ttl +17 -0
  4. package/examples/input/rdf-surfaces-all-values-from.ttl +13 -0
  5. package/examples/input/rdf-surfaces-ancestor.ttl +20 -0
  6. package/examples/input/rdf-surfaces-city.ttl +11 -0
  7. package/examples/input/rdf-surfaces-domain.ttl +11 -0
  8. package/examples/input/rdf-surfaces-multi-premise.ttl +13 -0
  9. package/examples/input/rdf-surfaces-owl-all-values-from-codex.ttl +35 -0
  10. package/examples/input/rdf-surfaces-property-chain.ttl +13 -0
  11. package/examples/input/rdf-surfaces-range.ttl +11 -0
  12. package/examples/input/rdf-surfaces-rdfs-range-codex.ttl +18 -0
  13. package/examples/input/rdf-surfaces-rdfs-subclass-codex.ttl +18 -0
  14. package/examples/output/rdf-surfaces-all-values-from-reverse.n3 +3 -0
  15. package/examples/output/rdf-surfaces-all-values-from.n3 +3 -0
  16. package/examples/output/rdf-surfaces-ancestor.n3 +5 -0
  17. package/examples/output/rdf-surfaces-city.n3 +3 -0
  18. package/examples/output/rdf-surfaces-domain.n3 +3 -0
  19. package/examples/output/rdf-surfaces-multi-premise.n3 +3 -0
  20. package/examples/output/rdf-surfaces-owl-all-values-from-codex.n3 +6 -0
  21. package/examples/output/rdf-surfaces-property-chain.n3 +3 -0
  22. package/examples/output/rdf-surfaces-range.n3 +3 -0
  23. package/examples/output/rdf-surfaces-rdfs-range-codex.n3 +3 -0
  24. package/examples/output/rdf-surfaces-rdfs-subclass-codex.n3 +3 -0
  25. package/examples/rdf-surfaces-all-values-from-reverse.n3 +6 -0
  26. package/examples/rdf-surfaces-all-values-from.n3 +6 -0
  27. package/examples/rdf-surfaces-ancestor.n3 +6 -0
  28. package/examples/rdf-surfaces-city.n3 +6 -0
  29. package/examples/rdf-surfaces-domain.n3 +6 -0
  30. package/examples/rdf-surfaces-multi-premise.n3 +6 -0
  31. package/examples/rdf-surfaces-owl-all-values-from-codex.n3 +10 -0
  32. package/examples/rdf-surfaces-property-chain.n3 +6 -0
  33. package/examples/rdf-surfaces-range.n3 +6 -0
  34. package/examples/rdf-surfaces-rdfs-range-codex.n3 +6 -0
  35. package/examples/rdf-surfaces-rdfs-subclass-codex.n3 +6 -0
  36. package/eyeling.js +711 -21
  37. package/index.d.ts +4 -0
  38. package/index.js +2 -1
  39. package/lib/builtins.js +128 -3
  40. package/lib/cli.js +11 -4
  41. package/lib/engine.js +15 -7
  42. package/lib/lexer.js +4 -0
  43. package/lib/multisource.js +5 -3
  44. package/lib/prelude.js +18 -0
  45. package/lib/rdf_surfaces.js +524 -0
  46. package/lib/rules.js +3 -4
  47. package/package.json +8 -5
  48. package/test/builtins.test.js +36 -0
  49. package/test/examples.test.js +37 -5
  50. package/test/rdf_surfaces.test.js +204 -0
package/eyeling.js CHANGED
@@ -41,6 +41,8 @@ const {
41
41
  PrefixEnv,
42
42
  literalParts,
43
43
  copyQuotedGraphMetadata,
44
+ isInternalBlankVarName,
45
+ internalBlankVarSuffix,
44
46
  } = require('./prelude');
45
47
 
46
48
  const { decodeN3StringEscapes } = require('./lexer');
@@ -143,6 +145,127 @@ function __assertBuiltinHandlerResult(iri, out) {
143
145
  }
144
146
  }
145
147
 
148
+ function collectVarNamesInTerm(t, acc) {
149
+ if (t instanceof Var) {
150
+ acc.add(t.name);
151
+ return;
152
+ }
153
+ if (t instanceof ListTerm) {
154
+ for (const e of t.elems) collectVarNamesInTerm(e, acc);
155
+ return;
156
+ }
157
+ if (t instanceof OpenListTerm) {
158
+ for (const e of t.prefix) collectVarNamesInTerm(e, acc);
159
+ acc.add(t.tailVar);
160
+ return;
161
+ }
162
+ if (t instanceof GraphTerm) {
163
+ for (const tr of t.triples) collectVarNamesInTriple(tr, acc);
164
+ }
165
+ }
166
+
167
+ function collectVarNamesInTriple(tr, acc) {
168
+ collectVarNamesInTerm(tr.s, acc);
169
+ collectVarNamesInTerm(tr.p, acc);
170
+ collectVarNamesInTerm(tr.o, acc);
171
+ }
172
+
173
+ function cloneSubstWithMappedKeys(subst, keyMap, externalizeTerm) {
174
+ const out = Object.create(null);
175
+ for (const [key, val] of Object.entries(subst || {})) {
176
+ out[keyMap.get(key) || key] = externalizeTerm ? externalizeTerm(val) : val;
177
+ }
178
+ return out;
179
+ }
180
+
181
+ function hasInternalBlankVarInSubst(subst) {
182
+ for (const key of Object.keys(subst || {})) {
183
+ if (isInternalBlankVarName(key)) return true;
184
+ }
185
+ return false;
186
+ }
187
+
188
+ function makeCustomBuiltinPublicBridge(goal, subst) {
189
+ const used = new Set(Object.keys(subst || {}).filter((name) => !isInternalBlankVarName(name)));
190
+ collectVarNamesInTriple(goal, used);
191
+ for (const name of Array.from(used)) {
192
+ if (isInternalBlankVarName(name)) used.delete(name);
193
+ }
194
+
195
+ const internalNames = new Set();
196
+ collectVarNamesInTriple(goal, internalNames);
197
+ for (const key of Object.keys(subst || {})) internalNames.add(key);
198
+ for (const name of Array.from(internalNames)) {
199
+ if (!isInternalBlankVarName(name)) internalNames.delete(name);
200
+ }
201
+
202
+ if (internalNames.size === 0 && !hasInternalBlankVarInSubst(subst)) return null;
203
+
204
+ const internalToPublic = new Map();
205
+ const publicToInternal = new Map();
206
+
207
+ function allocatePublicName(internalName) {
208
+ const suffix = internalBlankVarSuffix(internalName) || String(internalToPublic.size + 1);
209
+ const base = /^[$A-Za-z_][0-9A-Za-z_]*$/u.test(`_b${suffix}`) ? `_b${suffix}` : `_b${internalToPublic.size + 1}`;
210
+ let name = base;
211
+ let n = 1;
212
+ while (used.has(name) || publicToInternal.has(name)) {
213
+ n += 1;
214
+ name = `${base}_${n}`;
215
+ }
216
+ used.add(name);
217
+ internalToPublic.set(internalName, name);
218
+ publicToInternal.set(name, internalName);
219
+ return name;
220
+ }
221
+
222
+ for (const name of internalNames) allocatePublicName(name);
223
+
224
+ function externalName(name) {
225
+ if (!isInternalBlankVarName(name)) return name;
226
+ return internalToPublic.get(name) || allocatePublicName(name);
227
+ }
228
+
229
+ function externalizeTerm(t) {
230
+ if (t instanceof Var) return new Var(externalName(t.name));
231
+ if (t instanceof ListTerm) return new ListTerm(t.elems.map(externalizeTerm));
232
+ if (t instanceof OpenListTerm) return new OpenListTerm(t.prefix.map(externalizeTerm), externalName(t.tailVar));
233
+ if (t instanceof GraphTerm) {
234
+ const triples = t.triples.map((tr) => new Triple(externalizeTerm(tr.s), externalizeTerm(tr.p), externalizeTerm(tr.o)));
235
+ return copyQuotedGraphMetadata(t, new GraphTerm(triples));
236
+ }
237
+ return t;
238
+ }
239
+
240
+ function internalizeTerm(t) {
241
+ if (t instanceof Var) return new Var(publicToInternal.get(t.name) || t.name);
242
+ if (t instanceof ListTerm) return new ListTerm(t.elems.map(internalizeTerm));
243
+ if (t instanceof OpenListTerm) return new OpenListTerm(t.prefix.map(internalizeTerm), publicToInternal.get(t.tailVar) || t.tailVar);
244
+ if (t instanceof GraphTerm) {
245
+ const triples = t.triples.map((tr) => new Triple(internalizeTerm(tr.s), internalizeTerm(tr.p), internalizeTerm(tr.o)));
246
+ return copyQuotedGraphMetadata(t, new GraphTerm(triples));
247
+ }
248
+ return t;
249
+ }
250
+
251
+ function internalizeDelta(delta) {
252
+ const out = Object.create(null);
253
+ for (const [key, val] of Object.entries(delta || {})) {
254
+ out[publicToInternal.get(key) || key] = internalizeTerm(val);
255
+ }
256
+ return out;
257
+ }
258
+
259
+ return {
260
+ goal: new Triple(externalizeTerm(goal.s), externalizeTerm(goal.p), externalizeTerm(goal.o)),
261
+ subst: cloneSubstWithMappedKeys(subst, internalToPublic, externalizeTerm),
262
+ internalizeResults(out) {
263
+ if (out == null) return out;
264
+ return out.map(internalizeDelta);
265
+ },
266
+ };
267
+ }
268
+
146
269
  function apiTermToN3(term, prefixes = PrefixEnv.newDefault()) {
147
270
  return termToN3(term, prefixes || PrefixEnv.newDefault());
148
271
  }
@@ -242,10 +365,11 @@ function __evalRegisteredBuiltin(pv, goal, subst, facts, backRules, depth, varGe
242
365
  const handler = __customBuiltinHandlers.get(pv);
243
366
  if (typeof handler !== 'function') return null;
244
367
 
368
+ const bridge = makeCustomBuiltinPublicBridge(goal, subst);
245
369
  const ctx = {
246
370
  iri: pv,
247
- goal,
248
- subst,
371
+ goal: bridge ? bridge.goal : goal,
372
+ subst: bridge ? bridge.subst : subst,
249
373
  facts,
250
374
  backRules,
251
375
  depth,
@@ -255,7 +379,8 @@ function __evalRegisteredBuiltin(pv, goal, subst, facts, backRules, depth, varGe
255
379
  };
256
380
 
257
381
  try {
258
- const out = handler(ctx);
382
+ const raw = handler(ctx);
383
+ const out = bridge ? bridge.internalizeResults(raw) : raw;
259
384
  if (out == null) return [];
260
385
  __assertBuiltinHandlerResult(pv, out);
261
386
  return out;
@@ -5965,7 +6090,7 @@ async function ingestLineBasedRdfSourceToStore(sourceLabel, store, { rdfMode = t
5965
6090
  }
5966
6091
 
5967
6092
 
5968
- async function runStreamMessagesMode(sourceLabels, { rdfMode, storeName = null, storePath = null, storeClear = false } = {}) {
6093
+ async function runStreamMessagesMode(sourceLabels, { rdfMode, rdfSurfacesMode = false, storeName = null, storePath = null, storeClear = false } = {}) {
5969
6094
  const ordinarySourceLabels = [];
5970
6095
  const messageSourceLabels = [];
5971
6096
 
@@ -6003,6 +6128,7 @@ async function runStreamMessagesMode(sourceLabels, { rdfMode, storeName = null,
6003
6128
  keepSourceArtifacts: false,
6004
6129
  sourceLocations: false,
6005
6130
  rdf: rdfMode,
6131
+ rdfSurfaces: rdfSurfacesMode,
6006
6132
  }),
6007
6133
  );
6008
6134
  } catch (e) {
@@ -6036,6 +6162,7 @@ async function runStreamMessagesMode(sourceLabels, { rdfMode, storeName = null,
6036
6162
  keepSourceArtifacts: false,
6037
6163
  sourceLocations: false,
6038
6164
  rdf: false,
6165
+ rdfSurfaces: false,
6039
6166
  });
6040
6167
  } catch (e) {
6041
6168
  if (e && e.name === 'N3SyntaxError') {
@@ -6090,6 +6217,7 @@ async function main() {
6090
6217
  ` -h, --help Show this help and exit.\n` +
6091
6218
  ` -p, --proof Enable proof explanations.\n` +
6092
6219
  ` -r, --rdf Enable RDF/TriG input/output compatibility.\n` +
6220
+ ` --rdf-surfaces Enable RDF Surfaces %not[...%] syntax (implies --rdf).\n` +
6093
6221
  ` --stream-messages Process RDF Message Logs one message at a time under -r.\n` +
6094
6222
  ` --store <name> Use an optional persistent fact store.\n` +
6095
6223
  ` --store-clear Clear the named store before this run.\n` +
@@ -6165,7 +6293,8 @@ async function main() {
6165
6293
  const showAst = argv.includes('--ast') || argv.includes('-a');
6166
6294
  const streamMode = argv.includes('--stream') || argv.includes('-t');
6167
6295
  const streamMessagesMode = argv.includes('--stream-messages');
6168
- const rdfMode = argv.includes('--rdf') || argv.includes('-r');
6296
+ const rdfSurfacesMode = argv.includes('--rdf-surfaces');
6297
+ const rdfMode = argv.includes('--rdf') || argv.includes('-r') || rdfSurfacesMode;
6169
6298
  const storeName = argv.__storeName || null;
6170
6299
  const storePath = argv.__storePath || null;
6171
6300
  const storeClear = argv.includes('--store-clear');
@@ -6234,7 +6363,7 @@ async function main() {
6234
6363
  }
6235
6364
 
6236
6365
  if (streamMessagesMode) {
6237
- await runStreamMessagesMode(sourceLabels, { rdfMode, storeName, storePath, storeClear });
6366
+ await runStreamMessagesMode(sourceLabels, { rdfMode, rdfSurfacesMode, storeName, storePath, storeClear });
6238
6367
  return;
6239
6368
  }
6240
6369
 
@@ -6288,6 +6417,7 @@ async function main() {
6288
6417
  keepSourceArtifacts: false,
6289
6418
  sourceLocations: false,
6290
6419
  rdf: rdfMode,
6420
+ rdfSurfaces: rdfSurfacesMode,
6291
6421
  }),
6292
6422
  );
6293
6423
  } catch (e) {
@@ -6300,7 +6430,7 @@ async function main() {
6300
6430
  }
6301
6431
 
6302
6432
  const mergedRuleDocument = mergeParsedDocuments(parsedRuleSources);
6303
- const result = await engine.runStoreBacked(mergedRuleDocument, store, { rdf: rdfMode });
6433
+ const result = await engine.runStoreBacked(mergedRuleDocument, store, { rdf: rdfMode, rdfSurfaces: rdfSurfacesMode });
6304
6434
  const outTriples = result.queryMode ? result.queryTriples || [] : (result.derived || []).map((df) => df.fact);
6305
6435
  if (result.queryMode) {
6306
6436
  const bodyText = engine.prettyPrintQueryTriples(outTriples, result.prefixes);
@@ -6335,6 +6465,7 @@ async function main() {
6335
6465
  keepSourceArtifacts: false,
6336
6466
  sourceLocations: engine.getProofCommentsEnabled(),
6337
6467
  rdf: rdfMode,
6468
+ rdfSurfaces: rdfSurfacesMode,
6338
6469
  }),
6339
6470
  );
6340
6471
  } catch (e) {
@@ -6435,6 +6566,7 @@ function factsContainOutputStrings(triplesForOutput) {
6435
6566
  {
6436
6567
  proof: engine.getProofCommentsEnabled(),
6437
6568
  rdf: rdfMode,
6569
+ rdfSurfaces: rdfSurfacesMode,
6438
6570
  store: { name: storeName, clear: storeClear, path: storePath || undefined },
6439
6571
  },
6440
6572
  );
@@ -10688,12 +10820,14 @@ function reasonStream(input, opts = {}) {
10688
10820
  skipUnsupportedRdfJs = false,
10689
10821
  builtinModules = null,
10690
10822
  rdf = false,
10823
+ rdfSurfaces = false,
10691
10824
  sourceLabel = '<input>',
10692
10825
  } = opts;
10693
10826
 
10694
- const useRdfCompatibility = !!rdf;
10827
+ const useRdfCompatibility = !!rdf || !!rdfSurfaces;
10828
+ const useRdfSurfaces = !!rdfSurfaces;
10695
10829
 
10696
- const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility, sourceLocations: proof });
10830
+ const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility, rdfSurfaces: useRdfSurfaces, sourceLocations: proof });
10697
10831
  const parsedTextInput = (!parsedSourceList && proof && typeof input === 'string')
10698
10832
  ? parseN3Text(input, {
10699
10833
  baseIri: baseIri || '',
@@ -10701,6 +10835,7 @@ function reasonStream(input, opts = {}) {
10701
10835
  keepSourceArtifacts: false,
10702
10836
  sourceLocations: true,
10703
10837
  rdf: useRdfCompatibility,
10838
+ rdfSurfaces: useRdfSurfaces,
10704
10839
  })
10705
10840
  : null;
10706
10841
  const hasInlineN3 = input && typeof input === 'object' && !Array.isArray(input) && typeof input.n3 === 'string';
@@ -10745,6 +10880,7 @@ function reasonStream(input, opts = {}) {
10745
10880
  keepSourceArtifacts: false,
10746
10881
  sourceLocations: proof,
10747
10882
  rdf: useRdfCompatibility,
10883
+ rdfSurfaces: useRdfSurfaces,
10748
10884
  });
10749
10885
  prefixes = directDoc.prefixes;
10750
10886
  triples = directDoc.triples;
@@ -10856,10 +10992,11 @@ async function __parseRunAsyncInput(input, opts) {
10856
10992
  baseIri = null,
10857
10993
  proof = false,
10858
10994
  rdf = false,
10995
+ rdfSurfaces = false,
10859
10996
  sourceLabel = '<input>',
10860
10997
  } = opts || {};
10861
10998
 
10862
- const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: !!rdf, sourceLocations: !!proof });
10999
+ const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: !!rdf || !!rdfSurfaces, rdfSurfaces: !!rdfSurfaces, sourceLocations: !!proof });
10863
11000
  if (parsedSourceList) return parsedSourceList;
10864
11001
 
10865
11002
  const parsedObject = await normalizeParsedReasonerInputAsync(input);
@@ -10874,7 +11011,8 @@ async function __parseRunAsyncInput(input, opts) {
10874
11011
  label: sourceLabel || '<input>',
10875
11012
  keepSourceArtifacts: false,
10876
11013
  sourceLocations: !!proof,
10877
- rdf: !!rdf,
11014
+ rdf: !!rdf || !!rdfSurfaces,
11015
+ rdfSurfaces: !!rdfSurfaces,
10878
11016
  });
10879
11017
  }
10880
11018
 
@@ -10950,7 +11088,8 @@ async function __proveGoalsAgainstStore(goals, subst, store, backRules, localFac
10950
11088
  async function runStoreBacked(input, store, opts = {}) {
10951
11089
  const parsed = parseN3SourceList(input, {
10952
11090
  baseIri: opts.baseIri || null,
10953
- rdf: !!opts.rdf,
11091
+ rdf: !!opts.rdf || !!opts.rdfSurfaces,
11092
+ rdfSurfaces: !!opts.rdfSurfaces,
10954
11093
  sourceLocations: !!opts.proof,
10955
11094
  }) || input;
10956
11095
 
@@ -10995,7 +11134,7 @@ async function runStoreBacked(input, store, opts = {}) {
10995
11134
  }
10996
11135
 
10997
11136
  let queryTriples = [];
10998
- const queryDerived = [];
11137
+ let queryDerived = [];
10999
11138
  if (qrules.length) {
11000
11139
  for (const r of qrules) {
11001
11140
  const solutions = await __proveGoalsAgainstStore(r.premise || [], __emptySubst(), store, brules, triples, 0, varGen, {});
@@ -11067,7 +11206,8 @@ async function runAsync(input, opts = {}) {
11067
11206
  if (!storeConfig) {
11068
11207
  const normalizedInput = parseN3SourceList(input, {
11069
11208
  baseIri: runOpts.baseIri || null,
11070
- rdf: !!runOpts.rdf,
11209
+ rdf: !!runOpts.rdf || !!runOpts.rdfSurfaces,
11210
+ rdfSurfaces: !!runOpts.rdfSurfaces,
11071
11211
  sourceLocations: !!runOpts.proof,
11072
11212
  }) || (await normalizeReasonerInputAsync(input));
11073
11213
  return reasonStream(normalizedInput, runOpts);
@@ -12317,6 +12457,8 @@ module.exports = { tryParseFastRdfText, parseFastRdfText, parseFastRdfMessageLog
12317
12457
 
12318
12458
  'use strict';
12319
12459
 
12460
+ const { normalizeRdfSurfaces } = require('./rdf_surfaces');
12461
+
12320
12462
  class Token {
12321
12463
  constructor(typ, value = null, offset = null) {
12322
12464
  this.typ = typ;
@@ -13657,7 +13799,9 @@ function isNumericLikeIdentifier(word) {
13657
13799
 
13658
13800
  function lex(inputText, opts = {}) {
13659
13801
  const rdf = !!(opts && opts.rdf);
13802
+ const rdfSurfaces = !!(opts && opts.rdfSurfaces);
13660
13803
  if (rdf) inputText = normalizeRdfCompatibility(inputText);
13804
+ if (rdfSurfaces) inputText = normalizeRdfSurfaces(inputText);
13661
13805
  // Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
13662
13806
  // only needed when the text contains surrogate pairs and we want the old
13663
13807
  // code-point iteration behavior for non-BMP characters.
@@ -14440,9 +14584,10 @@ function parseN3Text(text, opts = {}) {
14440
14584
  collectUsedPrefixes = false,
14441
14585
  sourceLocations = false,
14442
14586
  rdf = false,
14587
+ rdfSurfaces = false,
14443
14588
  } = opts || {};
14444
14589
 
14445
- if (rdf) {
14590
+ if (rdf && !rdfSurfaces) {
14446
14591
  const fastDoc = tryParseFastRdfText(text, { baseIri, label });
14447
14592
  if (fastDoc) {
14448
14593
  if (sourceLocations) annotateParsedSourceLocations(fastDoc, text, label);
@@ -14451,7 +14596,7 @@ function parseN3Text(text, opts = {}) {
14451
14596
  }
14452
14597
  }
14453
14598
 
14454
- const tokens = lex(text, { rdf });
14599
+ const tokens = lex(text, { rdf, rdfSurfaces });
14455
14600
  const parser = new Parser(tokens);
14456
14601
  if (baseIri) parser.prefixes.setBase(baseIri);
14457
14602
  const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
@@ -14650,7 +14795,8 @@ function parseN3SourceList(input, opts = {}) {
14650
14795
  collectUsedPrefixes: true,
14651
14796
  keepSourceArtifacts: !!opts.keepSourceArtifacts,
14652
14797
  sourceLocations: !!opts.sourceLocations,
14653
- rdf: !!opts.rdf,
14798
+ rdf: !!opts.rdf || !!opts.rdfSurfaces,
14799
+ rdfSurfaces: !!opts.rdfSurfaces,
14654
14800
  }),
14655
14801
  );
14656
14802
  return mergeParsedDocuments(parsed, {
@@ -15468,6 +15614,21 @@ const DT_NS = 'https://eyereasoner.github.io/eyeling/datatype#';
15468
15614
  const SKOLEM_NS = 'https://eyereasoner.github.io/.well-known/genid/';
15469
15615
  const RDF_JSON_DT = RDF_NS + 'JSON';
15470
15616
 
15617
+ // Private rule-lifting variable prefix used for blank nodes that appear in
15618
+ // rule-body patterns. The prefix is intentionally not spellable in N3 input,
15619
+ // but public extension APIs should present these variables with stable,
15620
+ // ordinary names and translate them back internally.
15621
+ const INTERNAL_BLANK_VAR_PREFIX = '\uE000eyeling_b';
15622
+
15623
+ function isInternalBlankVarName(name) {
15624
+ return typeof name === 'string' && name.startsWith(INTERNAL_BLANK_VAR_PREFIX);
15625
+ }
15626
+
15627
+ function internalBlankVarSuffix(name) {
15628
+ if (!isInternalBlankVarName(name)) return '';
15629
+ return name.slice(INTERNAL_BLANK_VAR_PREFIX.length);
15630
+ }
15631
+
15471
15632
  function parseUriReferenceForResolution(uri) {
15472
15633
  // RFC 3986 Appendix B-style component parser, with the scheme tightened to
15473
15634
  // the RFC scheme grammar. Capturing delimiter presence matters: `?` with an
@@ -16171,6 +16332,9 @@ module.exports = {
16171
16332
  DT_NS,
16172
16333
  SKOLEM_NS,
16173
16334
  RDF_JSON_DT,
16335
+ INTERNAL_BLANK_VAR_PREFIX,
16336
+ isInternalBlankVarName,
16337
+ internalBlankVarSuffix,
16174
16338
  resolveIriRef,
16175
16339
  literalParts,
16176
16340
  normalizeLiteralForTid,
@@ -16662,6 +16826,533 @@ module.exports = {
16662
16826
  needsRdf12Version,
16663
16827
  };
16664
16828
 
16829
+ };
16830
+ __modules["lib/rdf_surfaces.js"] = function(require, module, exports){
16831
+ /**
16832
+ * Eyeling Reasoner — RDF Surfaces syntax normalizer
16833
+ *
16834
+ * Implements a small RDF Surfaces text convention inspired by Hayes' BLOGIC
16835
+ * slides: `%not[ ... %]` surface parentheses with explicit blank mark binders
16836
+ * such as `_:x _:y` at the beginning of a surface. The supported fragment
16837
+ * covers slide 32, the slide 33 range shape, both slide 33 allValuesFrom
16838
+ * shapes, and top-level fuse surfaces.
16839
+ *
16840
+ * The normalizer rewrites the supported fragment into ordinary Eyeling N3:
16841
+ * %not[ _:x P(?x) . %not[ Q(?x) . %] %]
16842
+ * becomes:
16843
+ * { P(?x) . } => { Q(?x) . } .
16844
+ *
16845
+ * A top-level negative surface without an inner negative surface becomes an
16846
+ * inference fuse:
16847
+ * %not[ _:x P(?x) . %]
16848
+ * becomes:
16849
+ * { P(?x) . } => false .
16850
+ */
16851
+
16852
+ 'use strict';
16853
+
16854
+ function syntaxError(message, offset = null) {
16855
+ const e = new Error(message);
16856
+ e.name = 'N3SyntaxError';
16857
+ if (typeof offset === 'number') e.offset = offset;
16858
+ return e;
16859
+ }
16860
+
16861
+ function isWs(ch) {
16862
+ return ch != null && /\s/.test(ch);
16863
+ }
16864
+
16865
+
16866
+ function readStringAt(s, at) {
16867
+ const quote = s[at];
16868
+ let i = at;
16869
+ let out = quote;
16870
+ const long = s.startsWith(quote.repeat(3), i);
16871
+ if (long) {
16872
+ out = quote.repeat(3);
16873
+ i += 3;
16874
+ while (i < s.length) {
16875
+ if (s.startsWith(quote.repeat(3), i)) {
16876
+ out += quote.repeat(3);
16877
+ i += 3;
16878
+ return { text: out, end: i };
16879
+ }
16880
+ if (s[i] === '\\' && i + 1 < s.length) {
16881
+ out += s.slice(i, i + 2);
16882
+ i += 2;
16883
+ } else {
16884
+ out += s[i++];
16885
+ }
16886
+ }
16887
+ throw syntaxError('Unterminated string literal inside RDF Surface', at);
16888
+ }
16889
+
16890
+ i += 1;
16891
+ let escaped = false;
16892
+ while (i < s.length) {
16893
+ const ch = s[i++];
16894
+ out += ch;
16895
+ if (escaped) escaped = false;
16896
+ else if (ch === '\\') escaped = true;
16897
+ else if (ch === quote) return { text: out, end: i };
16898
+ }
16899
+ throw syntaxError('Unterminated string literal inside RDF Surface', at);
16900
+ }
16901
+
16902
+ function readIriAt(s, at) {
16903
+ let i = at + 1;
16904
+ let out = '<';
16905
+ while (i < s.length) {
16906
+ const ch = s[i++];
16907
+ out += ch;
16908
+ if (ch === '>') return { text: out, end: i };
16909
+ }
16910
+ throw syntaxError('Unterminated IRI inside RDF Surface', at);
16911
+ }
16912
+
16913
+ function skipWsAndComments(s, at) {
16914
+ let i = at;
16915
+ while (i < s.length) {
16916
+ if (isWs(s[i])) {
16917
+ i += 1;
16918
+ continue;
16919
+ }
16920
+ if (s[i] === '#') {
16921
+ while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
16922
+ continue;
16923
+ }
16924
+ break;
16925
+ }
16926
+ return i;
16927
+ }
16928
+
16929
+ function readBareTokenAt(s, at) {
16930
+ const i0 = skipWsAndComments(s, at);
16931
+ if (i0 >= s.length) return null;
16932
+ if (s[i0] === '<') return readIriAt(s, i0);
16933
+ if (s[i0] === '"' || s[i0] === "'") return readStringAt(s, i0);
16934
+ let i = i0;
16935
+ while (i < s.length && !isWs(s[i]) && !'{}[](),;.'.includes(s[i])) i += 1;
16936
+ if (i === i0) return null;
16937
+ return { text: s.slice(i0, i), start: i0, end: i };
16938
+ }
16939
+
16940
+ function readStatementSegment(s) {
16941
+ let i = 0;
16942
+ let depthBrace = 0;
16943
+ let depthBracket = 0;
16944
+ let depthParen = 0;
16945
+ while (i < s.length) {
16946
+ if (s.startsWith('%not[', i) && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
16947
+ return s.slice(0, i);
16948
+ }
16949
+ const ch = s[i];
16950
+ if (ch === '"' || ch === "'") {
16951
+ i = readStringAt(s, i).end;
16952
+ continue;
16953
+ }
16954
+ if (ch === '<') {
16955
+ i = readIriAt(s, i).end;
16956
+ continue;
16957
+ }
16958
+ if (ch === '#') {
16959
+ while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
16960
+ continue;
16961
+ }
16962
+ if (ch === '{') depthBrace += 1;
16963
+ else if (ch === '}' && depthBrace > 0) depthBrace -= 1;
16964
+ else if (ch === '[') depthBracket += 1;
16965
+ else if (ch === ']' && depthBracket > 0) depthBracket -= 1;
16966
+ else if (ch === '(') depthParen += 1;
16967
+ else if (ch === ')' && depthParen > 0) depthParen -= 1;
16968
+ else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) return s.slice(0, i);
16969
+ i += 1;
16970
+ }
16971
+ return s;
16972
+ }
16973
+
16974
+ function tokenizeLeadingSegment(segment) {
16975
+ const toks = [];
16976
+ let pos = 0;
16977
+ while (pos < segment.length) {
16978
+ const tok = readBareTokenAt(segment, pos);
16979
+ if (!tok) break;
16980
+ toks.push(tok);
16981
+ pos = tok.end;
16982
+ }
16983
+ return toks;
16984
+ }
16985
+
16986
+ function extractLeadingBinders(raw) {
16987
+ const text = String(raw || '');
16988
+ const contentStart = skipWsAndComments(text, 0);
16989
+ if (contentStart >= text.length) return { binders: [], text };
16990
+
16991
+ const segment = readStatementSegment(text.slice(contentStart));
16992
+ const toks = tokenizeLeadingSegment(segment);
16993
+ let leadingBlankCount = 0;
16994
+ while (leadingBlankCount < toks.length && /^_:[A-Za-z_][A-Za-z0-9._-]*$/.test(toks[leadingBlankCount].text)) {
16995
+ leadingBlankCount += 1;
16996
+ }
16997
+
16998
+ if (leadingBlankCount === 0) return { binders: [], text };
16999
+
17000
+ let binderCount = 0;
17001
+ if (toks.length >= 3) {
17002
+ // Prefer the longest explicit binder prefix that still leaves at least a
17003
+ // subject, predicate, and object for the first statement. This matches the
17004
+ // BLOGIC slide convention, e.g. `%not[ _:x _:x a :C . ... %]`.
17005
+ binderCount = Math.min(leadingBlankCount, Math.max(0, toks.length - 3));
17006
+ } else {
17007
+ // No own triple before a nested surface: treat the leading marks as binders.
17008
+ binderCount = leadingBlankCount;
17009
+ }
17010
+
17011
+ if (binderCount <= 0) return { binders: [], text };
17012
+
17013
+ const binders = toks.slice(0, binderCount).map((t) => t.text.slice(2));
17014
+ const cut = toks[binderCount - 1].end;
17015
+ return { binders, text: text.slice(0, contentStart) + text.slice(contentStart + cut) };
17016
+ }
17017
+
17018
+ function splitTopLevelStatements(raw, surfaceOffset = null) {
17019
+ const text = String(raw || '');
17020
+ const out = [];
17021
+ let start = 0;
17022
+ let i = 0;
17023
+ let depthBrace = 0;
17024
+ let depthBracket = 0;
17025
+ let depthParen = 0;
17026
+
17027
+ while (i < text.length) {
17028
+ const ch = text[i];
17029
+ if (ch === '"' || ch === "'") {
17030
+ i = readStringAt(text, i).end;
17031
+ continue;
17032
+ }
17033
+ if (ch === '<') {
17034
+ i = readIriAt(text, i).end;
17035
+ continue;
17036
+ }
17037
+ if (ch === '#') {
17038
+ while (i < text.length && text[i] !== '\n' && text[i] !== '\r') i += 1;
17039
+ continue;
17040
+ }
17041
+ if (ch === '{') depthBrace += 1;
17042
+ else if (ch === '}' && depthBrace > 0) depthBrace -= 1;
17043
+ else if (ch === '[') depthBracket += 1;
17044
+ else if (ch === ']' && depthBracket > 0) depthBracket -= 1;
17045
+ else if (ch === '(') depthParen += 1;
17046
+ else if (ch === ')' && depthParen > 0) depthParen -= 1;
17047
+ else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
17048
+ const stmt = text.slice(start, i).trim();
17049
+ if (stmt) out.push(stmt);
17050
+ start = i + 1;
17051
+ }
17052
+ i += 1;
17053
+ }
17054
+
17055
+ const tail = text.slice(start).trim();
17056
+ if (tail) {
17057
+ // A raw binder-only segment is OK; any other dangling text is most likely a
17058
+ // missing dot in the surface body.
17059
+ if (!/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(tail)) {
17060
+ throw syntaxError('RDF Surface statement is missing a terminating dot', surfaceOffset);
17061
+ }
17062
+ }
17063
+
17064
+ return out;
17065
+ }
17066
+
17067
+ function readSurfaceAt(s, at) {
17068
+ if (!s.startsWith('%not[', at)) return null;
17069
+ let i = at + '%not['.length;
17070
+ let current = '';
17071
+ const segments = [];
17072
+ const children = [];
17073
+
17074
+ while (i < s.length) {
17075
+ if (s.startsWith('%]', i)) {
17076
+ segments.push(current);
17077
+ i += 2;
17078
+ const raw = segments.join('\n');
17079
+ const stripped = extractLeadingBinders(raw);
17080
+ return {
17081
+ type: 'not',
17082
+ start: at,
17083
+ end: i,
17084
+ binders: stripped.binders,
17085
+ statements: splitTopLevelStatements(stripped.text, at),
17086
+ children,
17087
+ };
17088
+ }
17089
+
17090
+ if (s.startsWith('%not[', i)) {
17091
+ segments.push(current);
17092
+ current = '';
17093
+ const child = readSurfaceAt(s, i);
17094
+ children.push(child);
17095
+ i = child.end;
17096
+ continue;
17097
+ }
17098
+
17099
+ const ch = s[i];
17100
+ if (ch === '"' || ch === "'") {
17101
+ const str = readStringAt(s, i);
17102
+ current += str.text;
17103
+ i = str.end;
17104
+ continue;
17105
+ }
17106
+ if (ch === '<') {
17107
+ const iri = readIriAt(s, i);
17108
+ current += iri.text;
17109
+ i = iri.end;
17110
+ continue;
17111
+ }
17112
+ if (ch === '#') {
17113
+ while (i < s.length) {
17114
+ const c = s[i++];
17115
+ current += c;
17116
+ if (c === '\n' || c === '\r') break;
17117
+ }
17118
+ continue;
17119
+ }
17120
+
17121
+ current += ch;
17122
+ i += 1;
17123
+ }
17124
+
17125
+ throw syntaxError('Unterminated RDF Surface, expected %]', at);
17126
+ }
17127
+
17128
+ const LOG_FOR_ALL_IN_IRI = '<http://www.w3.org/2000/10/swap/log#forAllIn>';
17129
+
17130
+ function rewriteBlankMarksWithMap(statement, labelToVarName) {
17131
+ const map = labelToVarName instanceof Map ? labelToVarName : new Map();
17132
+ let out = '';
17133
+ let i = 0;
17134
+ while (i < statement.length) {
17135
+ const ch = statement[i];
17136
+ if (ch === '"' || ch === "'") {
17137
+ const str = readStringAt(statement, i);
17138
+ out += str.text;
17139
+ i = str.end;
17140
+ continue;
17141
+ }
17142
+ if (ch === '<') {
17143
+ const iri = readIriAt(statement, i);
17144
+ out += iri.text;
17145
+ i = iri.end;
17146
+ continue;
17147
+ }
17148
+ if (ch === '#') {
17149
+ while (i < statement.length) {
17150
+ const c = statement[i++];
17151
+ out += c;
17152
+ if (c === '\n' || c === '\r') break;
17153
+ }
17154
+ continue;
17155
+ }
17156
+ if (statement.startsWith('_:', i)) {
17157
+ let j = i + 2;
17158
+ while (j < statement.length && !isWs(statement[j]) && !'{}[](),;.'.includes(statement[j])) j += 1;
17159
+ const label = statement.slice(i + 2, j);
17160
+ const mapped = label ? map.get(label) : null;
17161
+ if (mapped) {
17162
+ out += `?${mapped}`;
17163
+ i = j;
17164
+ continue;
17165
+ }
17166
+ }
17167
+ out += ch;
17168
+ i += 1;
17169
+ }
17170
+ return out.trim();
17171
+ }
17172
+
17173
+ function formatGraphWithMap(statements, labelMap) {
17174
+ const body = (statements || [])
17175
+ .map((st) => rewriteBlankMarksWithMap(st, labelMap))
17176
+ .filter(Boolean)
17177
+ .map((st) => ` ${st} .`)
17178
+ .join('\n');
17179
+ return body ? `{
17180
+ ${body}\n}` : '{ }';
17181
+ }
17182
+
17183
+ function formatGraphFromRewritten(statements) {
17184
+ const body = (statements || [])
17185
+ .map((st) => String(st || '').trim())
17186
+ .filter(Boolean)
17187
+ .map((st) => ` ${st} .`)
17188
+ .join('\n');
17189
+ return body ? `{
17190
+ ${body}\n}` : '{ }';
17191
+ }
17192
+
17193
+ function makeVarMap(labels, prefix = '') {
17194
+ const map = new Map();
17195
+ for (const label of labels || []) map.set(label, `${prefix}${label}`);
17196
+ return map;
17197
+ }
17198
+
17199
+ function mergeVarMaps(...maps) {
17200
+ const out = new Map();
17201
+ for (const m of maps) {
17202
+ for (const [k, v] of m.entries()) out.set(k, v);
17203
+ }
17204
+ return out;
17205
+ }
17206
+
17207
+ function slide33ReverseAllValuesFromRule(node, inheritedMap = new Map(), extraPremises = []) {
17208
+ const outerBinders = node.binders || [];
17209
+ const own = node.statements || [];
17210
+ const children = node.children || [];
17211
+
17212
+ if (own.length !== 0 || outerBinders.length === 0 || children.length !== 2) return null;
17213
+
17214
+ let bodyChild = null;
17215
+ let headChild = null;
17216
+ for (const child of children) {
17217
+ const childChildren = child && child.children ? child.children : [];
17218
+ if (childChildren.length === 1) bodyChild = child;
17219
+ else if (childChildren.length === 0) headChild = child;
17220
+ else return null;
17221
+ }
17222
+
17223
+ if (!bodyChild || !headChild) return null;
17224
+ if (!bodyChild.statements || bodyChild.statements.length === 0) return null;
17225
+ if (!headChild.statements || headChild.statements.length === 0) return null;
17226
+
17227
+ const thenChild = bodyChild.children[0];
17228
+ if (!thenChild || (thenChild.children && thenChild.children.length)) return null;
17229
+ if (!thenChild.statements || thenChild.statements.length === 0) return null;
17230
+
17231
+ const outerMap = mergeVarMaps(inheritedMap, makeVarMap(outerBinders));
17232
+ const witnessMap = makeVarMap(bodyChild.binders || [], '__rs_witness_');
17233
+ const localMap = makeVarMap(bodyChild.binders || [], '__rs_');
17234
+
17235
+ const mappedExtra = (extraPremises || [])
17236
+ .map((st) => rewriteBlankMarksWithMap(st, outerMap))
17237
+ .filter(Boolean);
17238
+ const premiseStmts = bodyChild.statements
17239
+ .map((st) => rewriteBlankMarksWithMap(st, mergeVarMaps(outerMap, witnessMap)))
17240
+ .filter(Boolean);
17241
+
17242
+ const whereGraph = formatGraphWithMap(bodyChild.statements, mergeVarMaps(outerMap, localMap));
17243
+ const thenGraph = formatGraphWithMap(thenChild.statements, mergeVarMaps(outerMap, localMap));
17244
+ const forAllLine = `( ${whereGraph} ${thenGraph} ) ${LOG_FOR_ALL_IN_IRI} 1`;
17245
+
17246
+ const premise = formatGraphFromRewritten([...mappedExtra, ...premiseStmts, forAllLine]);
17247
+ const conclusion = formatGraphWithMap(headChild.statements, outerMap);
17248
+ return `${premise} => ${conclusion} .`;
17249
+ }
17250
+
17251
+
17252
+ function translateHeadSurface(node, extraPremises, inheritedMap = new Map()) {
17253
+ const rules = [];
17254
+ const map = inheritedMap instanceof Map ? inheritedMap : new Map();
17255
+ const own = node.statements || [];
17256
+ if (own.length) {
17257
+ rules.push(`${formatGraphWithMap(extraPremises, map)} => ${formatGraphWithMap(own, map)} .`);
17258
+ }
17259
+ for (const child of node.children || []) {
17260
+ rules.push(...translateRuleSurface(child, extraPremises, map));
17261
+ }
17262
+ return rules;
17263
+ }
17264
+
17265
+ function translateRuleSurface(node, extraPremises = [], inheritedMap = new Map()) {
17266
+ const slide33Reverse = slide33ReverseAllValuesFromRule(node, inheritedMap, extraPremises);
17267
+ if (slide33Reverse) return [slide33Reverse];
17268
+
17269
+ const map = mergeVarMaps(inheritedMap, makeVarMap(node.binders || []));
17270
+ const own = node.statements || [];
17271
+ const premise = [...(extraPremises || []), ...own];
17272
+ const children = node.children || [];
17273
+
17274
+ if (children.length === 0) {
17275
+ return own.length ? [`${formatGraphWithMap(premise, map)} => false .`] : [];
17276
+ }
17277
+
17278
+ return children.flatMap((child) => translateHeadSurface(child, premise, map));
17279
+ }
17280
+
17281
+ function translateTopLevelSurface(node) {
17282
+ const map = makeVarMap(node.binders || []);
17283
+ const own = node.statements || [];
17284
+
17285
+ if (!node.children || node.children.length === 0) {
17286
+ return own.length ? [`${formatGraphWithMap(own, map)} => false .`] : [];
17287
+ }
17288
+
17289
+ const slide33Reverse = slide33ReverseAllValuesFromRule(node);
17290
+ if (slide33Reverse) return [slide33Reverse];
17291
+
17292
+ return node.children.flatMap((child) => translateHeadSurface(child, own, map));
17293
+ }
17294
+
17295
+ function normalizeRdfSurfaces(inputText) {
17296
+ const s = String(inputText ?? '');
17297
+ if (!s.includes('%not[')) return s;
17298
+
17299
+ let out = '';
17300
+ const generated = [];
17301
+ let i = 0;
17302
+ let braceDepth = 0;
17303
+ let bracketDepth = 0;
17304
+ let parenDepth = 0;
17305
+
17306
+ while (i < s.length) {
17307
+ if (s.startsWith('%not[', i) && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
17308
+ const surface = readSurfaceAt(s, i);
17309
+ generated.push(...translateTopLevelSurface(surface));
17310
+ i = surface.end;
17311
+ continue;
17312
+ }
17313
+
17314
+ const ch = s[i];
17315
+ if (ch === '"' || ch === "'") {
17316
+ const str = readStringAt(s, i);
17317
+ out += str.text;
17318
+ i = str.end;
17319
+ continue;
17320
+ }
17321
+ if (ch === '<') {
17322
+ const iri = readIriAt(s, i);
17323
+ out += iri.text;
17324
+ i = iri.end;
17325
+ continue;
17326
+ }
17327
+ if (ch === '#') {
17328
+ while (i < s.length) {
17329
+ const c = s[i++];
17330
+ out += c;
17331
+ if (c === '\n' || c === '\r') break;
17332
+ }
17333
+ continue;
17334
+ }
17335
+
17336
+ if (ch === '{') braceDepth += 1;
17337
+ else if (ch === '}' && braceDepth > 0) braceDepth -= 1;
17338
+ else if (ch === '[') bracketDepth += 1;
17339
+ else if (ch === ']' && bracketDepth > 0) bracketDepth -= 1;
17340
+ else if (ch === '(') parenDepth += 1;
17341
+ else if (ch === ')' && parenDepth > 0) parenDepth -= 1;
17342
+
17343
+ out += ch;
17344
+ i += 1;
17345
+ }
17346
+
17347
+ if (generated.length === 0) return out;
17348
+ const sep = out.trim() ? (out.endsWith('\n') ? '\n' : '\n\n') : '';
17349
+ return out + sep + generated.join('\n\n') + '\n';
17350
+ }
17351
+
17352
+ module.exports = {
17353
+ normalizeRdfSurfaces,
17354
+ };
17355
+
16665
17356
  };
16666
17357
  __modules["lib/rdfjs.js"] = function(require, module, exports){
16667
17358
  /**
@@ -17645,6 +18336,7 @@ const {
17645
18336
  GraphTerm,
17646
18337
  Triple,
17647
18338
  copyQuotedGraphMetadata,
18339
+ INTERNAL_BLANK_VAR_PREFIX,
17648
18340
  } = require('./prelude');
17649
18341
 
17650
18342
  function liftBlankRuleVars(premise, conclusion) {
@@ -17660,10 +18352,8 @@ function liftBlankRuleVars(premise, conclusion) {
17660
18352
  // These variables are implementation details used to correlate one blank
17661
18353
  // node across the lifted rule body. Their names must not be spellable by
17662
18354
  // user input; otherwise a user variable such as ?_b1 can capture the
17663
- // lifted blank node and leak it into the rule head. U+E000 is a private-use
17664
- // code point and is not accepted by the lexer as part of a variable name.
17665
- const INTERNAL_BLANK_VAR_PREFIX = '\uE000eyeling_b';
17666
-
18355
+ // lifted blank node and leak it into the rule head. The public custom
18356
+ // builtin API maps these names back to ordinary-looking ?_bN variables.
17667
18357
  function blankToVar(label) {
17668
18358
  let name = mapping[label];
17669
18359
  if (name === undefined) {