eyeling 1.7.11 → 1.7.13

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 (2) hide show
  1. package/eyeling.js +244 -37
  2. package/package.json +1 -1
package/eyeling.js CHANGED
@@ -16,8 +16,20 @@
16
16
  * 5) Print only newly derived forward facts with explanations.
17
17
  */
18
18
 
19
- const { version } = require('./package.json');
20
- const nodeCrypto = require('crypto');
19
+ // -----------------------------------------------------------------------------
20
+ // Browser/Worker-safe version + crypto wiring
21
+ // -----------------------------------------------------------------------------
22
+ let version = 'dev';
23
+ try {
24
+ // Node: keep package.json version if available
25
+ if (typeof require === 'function') version = require('./package.json').version || version;
26
+ } catch (_) {}
27
+
28
+ let nodeCrypto = null;
29
+ try {
30
+ // Node: crypto available
31
+ if (typeof require === 'function') nodeCrypto = require('crypto');
32
+ } catch (_) {}
21
33
 
22
34
  // ===========================================================================
23
35
  // Namespace constants
@@ -105,7 +117,8 @@ function __resolveBrowserUrl(ref) {
105
117
  if (!ref) return ref;
106
118
  // If already absolute, keep as-is.
107
119
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return ref;
108
- const base = (typeof document !== 'undefined' && document.baseURI) || (typeof location !== 'undefined' && location.href) || '';
120
+ const base =
121
+ (typeof document !== 'undefined' && document.baseURI) || (typeof location !== 'undefined' && location.href) || '';
109
122
  try {
110
123
  return new URL(ref, base).toString();
111
124
  } catch {
@@ -119,7 +132,10 @@ function __fetchHttpTextSyncBrowser(url) {
119
132
  const xhr = new XMLHttpRequest();
120
133
  xhr.open('GET', url, false); // synchronous
121
134
  try {
122
- xhr.setRequestHeader('Accept', 'text/n3, text/turtle, application/n-triples, application/n-quads, text/plain;q=0.1, */*;q=0.01');
135
+ xhr.setRequestHeader(
136
+ 'Accept',
137
+ 'text/n3, text/turtle, application/n-triples, application/n-quads, text/plain;q=0.1, */*;q=0.01',
138
+ );
123
139
  } catch {
124
140
  // Some environments restrict setting headers (ignore).
125
141
  }
@@ -449,7 +465,21 @@ function utcIsoDateTimeStringFromEpochSeconds(sec) {
449
465
  const s2 = d.getUTCSeconds();
450
466
  const ms2 = d.getUTCMilliseconds();
451
467
  const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
452
- return pad(year, 4) + '-' + pad(month) + '-' + pad(day) + 'T' + pad(hour) + ':' + pad(min) + ':' + pad(s2) + msPart + '+00:00';
468
+ return (
469
+ pad(year, 4) +
470
+ '-' +
471
+ pad(month) +
472
+ '-' +
473
+ pad(day) +
474
+ 'T' +
475
+ pad(hour) +
476
+ ':' +
477
+ pad(min) +
478
+ ':' +
479
+ pad(s2) +
480
+ msPart +
481
+ '+00:00'
482
+ );
453
483
  }
454
484
 
455
485
  function getNowLex() {
@@ -487,7 +517,9 @@ function deterministicSkolemIdFromKey(key) {
487
517
  const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
488
518
 
489
519
  // Format like a UUID: 8-4-4-4-12
490
- return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
520
+ return (
521
+ hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20)
522
+ );
491
523
  }
492
524
 
493
525
  let runLocalTimeCache = null;
@@ -1892,7 +1924,12 @@ function liftBlankRuleVars(premise, conclusion) {
1892
1924
  }
1893
1925
  if (t instanceof GraphTerm) {
1894
1926
  const triples = t.triples.map(
1895
- (tr) => new Triple(convertTerm(tr.s, mapping, counter), convertTerm(tr.p, mapping, counter), convertTerm(tr.o, mapping, counter)),
1927
+ (tr) =>
1928
+ new Triple(
1929
+ convertTerm(tr.s, mapping, counter),
1930
+ convertTerm(tr.p, mapping, counter),
1931
+ convertTerm(tr.o, mapping, counter),
1932
+ ),
1896
1933
  );
1897
1934
  return new GraphTerm(triples);
1898
1935
  }
@@ -1900,7 +1937,11 @@ function liftBlankRuleVars(premise, conclusion) {
1900
1937
  }
1901
1938
 
1902
1939
  function convertTriple(tr, mapping, counter) {
1903
- return new Triple(convertTerm(tr.s, mapping, counter), convertTerm(tr.p, mapping, counter), convertTerm(tr.o, mapping, counter));
1940
+ return new Triple(
1941
+ convertTerm(tr.s, mapping, counter),
1942
+ convertTerm(tr.p, mapping, counter),
1943
+ convertTerm(tr.o, mapping, counter),
1944
+ );
1904
1945
  }
1905
1946
 
1906
1947
  const mapping = {};
@@ -1949,7 +1990,9 @@ function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firi
1949
1990
  }
1950
1991
 
1951
1992
  if (t instanceof ListTerm) {
1952
- return new ListTerm(t.elems.map((e) => skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter, firingKey, globalMap)));
1993
+ return new ListTerm(
1994
+ t.elems.map((e) => skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter, firingKey, globalMap)),
1995
+ );
1953
1996
  }
1954
1997
 
1955
1998
  if (t instanceof OpenListTerm) {
@@ -1961,7 +2004,9 @@ function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firi
1961
2004
 
1962
2005
  if (t instanceof GraphTerm) {
1963
2006
  return new GraphTerm(
1964
- t.triples.map((tr) => skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter, firingKey, globalMap)),
2007
+ t.triples.map((tr) =>
2008
+ skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter, firingKey, globalMap),
2009
+ ),
1965
2010
  );
1966
2011
  }
1967
2012
 
@@ -2170,7 +2215,11 @@ function alphaEqTermInGraph(a, b, vmap, bmap) {
2170
2215
  }
2171
2216
 
2172
2217
  function alphaEqTripleInGraph(a, b, vmap, bmap) {
2173
- return alphaEqTermInGraph(a.s, b.s, vmap, bmap) && alphaEqTermInGraph(a.p, b.p, vmap, bmap) && alphaEqTermInGraph(a.o, b.o, vmap, bmap);
2218
+ return (
2219
+ alphaEqTermInGraph(a.s, b.s, vmap, bmap) &&
2220
+ alphaEqTermInGraph(a.p, b.p, vmap, bmap) &&
2221
+ alphaEqTermInGraph(a.o, b.o, vmap, bmap)
2222
+ );
2174
2223
  }
2175
2224
 
2176
2225
  function alphaEqGraphTriples(xs, ys) {
@@ -2492,7 +2541,12 @@ function isConstraintBuiltin(tr) {
2492
2541
  }
2493
2542
 
2494
2543
  // log: tests that are purely constraints (no new bindings)
2495
- if (v === LOG_NS + 'forAllIn' || v === LOG_NS + 'notEqualTo' || v === LOG_NS + 'notIncludes') {
2544
+ if (
2545
+ v === LOG_NS + 'forAllIn' ||
2546
+ v === LOG_NS + 'notEqualTo' ||
2547
+ v === LOG_NS + 'notIncludes' ||
2548
+ v === LOG_NS + 'outputString'
2549
+ ) {
2496
2550
  return true;
2497
2551
  }
2498
2552
 
@@ -2705,13 +2759,19 @@ function unifyGraphTriples(xs, ys, subst) {
2705
2759
  }
2706
2760
 
2707
2761
  function unifyTerm(a, b, subst) {
2708
- return unifyTermWithOptions(a, b, subst, { boolValueEq: true, intDecimalEq: false });
2762
+ return unifyTermWithOptions(a, b, subst, {
2763
+ boolValueEq: true,
2764
+ intDecimalEq: false,
2765
+ });
2709
2766
  }
2710
2767
 
2711
2768
  function unifyTermListAppend(a, b, subst) {
2712
2769
  // Keep list:append behavior: allow integer<->decimal exact equality,
2713
2770
  // but do NOT add boolean-value equivalence (preserves current semantics).
2714
- return unifyTermWithOptions(a, b, subst, { boolValueEq: false, intDecimalEq: true });
2771
+ return unifyTermWithOptions(a, b, subst, {
2772
+ boolValueEq: false,
2773
+ intDecimalEq: true,
2774
+ });
2715
2775
  }
2716
2776
 
2717
2777
  function unifyTermWithOptions(a, b, subst, opts) {
@@ -3270,7 +3330,8 @@ function isQuotedLexical(lex) {
3270
3330
  // long: """...""" or '''...'''
3271
3331
  if (typeof lex !== 'string') return false;
3272
3332
  const n = lex.length;
3273
- if (n >= 6 && ((lex.startsWith('"""') && lex.endsWith('"""')) || (lex.startsWith("'''") && lex.endsWith("'''")))) return true;
3333
+ if (n >= 6 && ((lex.startsWith('"""') && lex.endsWith('"""')) || (lex.startsWith("'''") && lex.endsWith("'''"))))
3334
+ return true;
3274
3335
  if (n >= 2) {
3275
3336
  const a = lex[0];
3276
3337
  const b = lex[n - 1];
@@ -3550,7 +3611,13 @@ function parseIso8601DurationToSeconds(s) {
3550
3611
  }
3551
3612
 
3552
3613
  const totalDays =
3553
- years * 365.2425 + months * 30.436875 + weeks * 7.0 + days + hours / 24.0 + minutes / (24.0 * 60.0) + seconds / (24.0 * 3600.0);
3614
+ years * 365.2425 +
3615
+ months * 30.436875 +
3616
+ weeks * 7.0 +
3617
+ days +
3618
+ hours / 24.0 +
3619
+ minutes / (24.0 * 60.0) +
3620
+ seconds / (24.0 * 3600.0);
3554
3621
 
3555
3622
  return totalDays * 86400.0;
3556
3623
  }
@@ -5545,7 +5612,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5545
5612
 
5546
5613
  const scopeFacts = g.s.triples.slice();
5547
5614
  ensureFactIndexes(scopeFacts);
5548
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5615
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', {
5616
+ value: scopeFacts,
5617
+ enumerable: false,
5618
+ writable: true,
5619
+ });
5549
5620
 
5550
5621
  const visited2 = [];
5551
5622
  // Start from the incoming substitution so bindings flow outward.
@@ -5563,7 +5634,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5563
5634
 
5564
5635
  const scopeFacts = g.s.triples.slice();
5565
5636
  ensureFactIndexes(scopeFacts);
5566
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5637
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', {
5638
+ value: scopeFacts,
5639
+ enumerable: false,
5640
+ writable: true,
5641
+ });
5567
5642
 
5568
5643
  const visited2 = [];
5569
5644
  const sols = proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen);
@@ -5596,7 +5671,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5596
5671
  if (g.o instanceof GraphTerm) {
5597
5672
  scopeFacts = g.o.triples.slice();
5598
5673
  ensureFactIndexes(scopeFacts);
5599
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5674
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', {
5675
+ value: scopeFacts,
5676
+ enumerable: false,
5677
+ writable: true,
5678
+ });
5600
5679
  scopeBackRules = [];
5601
5680
  } else {
5602
5681
  scopeFacts = facts.__scopedSnapshot || null;
@@ -5609,7 +5688,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5609
5688
  }
5610
5689
 
5611
5690
  const visited2 = [];
5612
- const sols = proveGoals(Array.from(clauseTerm.triples), {}, scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
5691
+ const sols = proveGoals(
5692
+ Array.from(clauseTerm.triples),
5693
+ {},
5694
+ scopeFacts,
5695
+ scopeBackRules,
5696
+ depth + 1,
5697
+ visited2,
5698
+ varGen,
5699
+ );
5613
5700
 
5614
5701
  const collected = sols.map((sBody) => applySubstTerm(valueTempl, sBody));
5615
5702
  const collectedList = new ListTerm(collected);
@@ -5630,7 +5717,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5630
5717
  if (g.o instanceof GraphTerm) {
5631
5718
  scopeFacts = g.o.triples.slice();
5632
5719
  ensureFactIndexes(scopeFacts);
5633
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5720
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', {
5721
+ value: scopeFacts,
5722
+ enumerable: false,
5723
+ writable: true,
5724
+ });
5634
5725
  scopeBackRules = [];
5635
5726
  } else {
5636
5727
  scopeFacts = facts.__scopedSnapshot || null;
@@ -5638,11 +5729,27 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5638
5729
  }
5639
5730
 
5640
5731
  const visited1 = [];
5641
- const sols1 = proveGoals(Array.from(whereClause.triples), {}, scopeFacts, scopeBackRules, depth + 1, visited1, varGen);
5732
+ const sols1 = proveGoals(
5733
+ Array.from(whereClause.triples),
5734
+ {},
5735
+ scopeFacts,
5736
+ scopeBackRules,
5737
+ depth + 1,
5738
+ visited1,
5739
+ varGen,
5740
+ );
5642
5741
 
5643
5742
  for (const s1 of sols1) {
5644
5743
  const visited2 = [];
5645
- const sols2 = proveGoals(Array.from(thenClause.triples), s1, scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
5744
+ const sols2 = proveGoals(
5745
+ Array.from(thenClause.triples),
5746
+ s1,
5747
+ scopeFacts,
5748
+ scopeBackRules,
5749
+ depth + 1,
5750
+ visited2,
5751
+ varGen,
5752
+ );
5646
5753
  if (!sols2.length) return [];
5647
5754
  }
5648
5755
  return [{ ...subst }];
@@ -6158,7 +6265,12 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6158
6265
  results.push(gcCompactForGoals(composed, [], answerVars));
6159
6266
  } else {
6160
6267
  const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
6161
- nextStates.push({ goals: restGoals, subst: nextSubst, depth: state.depth + 1, visited: state.visited });
6268
+ nextStates.push({
6269
+ goals: restGoals,
6270
+ subst: nextSubst,
6271
+ depth: state.depth + 1,
6272
+ visited: state.visited,
6273
+ });
6162
6274
  }
6163
6275
  }
6164
6276
  // Push in reverse so the *first* generated alternative is explored first (LIFO stack).
@@ -6183,7 +6295,12 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6183
6295
  results.push(gcCompactForGoals(composed, [], answerVars));
6184
6296
  } else {
6185
6297
  const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
6186
- nextStates.push({ goals: restGoals, subst: nextSubst, depth: state.depth + 1, visited: state.visited });
6298
+ nextStates.push({
6299
+ goals: restGoals,
6300
+ subst: nextSubst,
6301
+ depth: state.depth + 1,
6302
+ visited: state.visited,
6303
+ });
6187
6304
  }
6188
6305
  }
6189
6306
  for (let i = nextStates.length - 1; i >= 0; i--) stack.push(nextStates[i]);
@@ -6199,7 +6316,12 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6199
6316
  results.push(gcCompactForGoals(composed, [], answerVars));
6200
6317
  } else {
6201
6318
  const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
6202
- nextStates.push({ goals: restGoals, subst: nextSubst, depth: state.depth + 1, visited: state.visited });
6319
+ nextStates.push({
6320
+ goals: restGoals,
6321
+ subst: nextSubst,
6322
+ depth: state.depth + 1,
6323
+ visited: state.visited,
6324
+ });
6203
6325
  }
6204
6326
  }
6205
6327
  for (let i = nextStates.length - 1; i >= 0; i--) stack.push(nextStates[i]);
@@ -6224,7 +6346,12 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6224
6346
  if (composed === null) continue;
6225
6347
  const newGoals = body.concat(restGoals);
6226
6348
  const nextSubst = maybeCompactSubst(composed, newGoals, answerVars, state.depth + 1);
6227
- nextStates.push({ goals: newGoals, subst: nextSubst, depth: state.depth + 1, visited: visitedForRules });
6349
+ nextStates.push({
6350
+ goals: newGoals,
6351
+ subst: nextSubst,
6352
+ depth: state.depth + 1,
6353
+ visited: visitedForRules,
6354
+ });
6228
6355
  }
6229
6356
  for (let i = nextStates.length - 1; i >= 0; i--) stack.push(nextStates[i]);
6230
6357
  }
@@ -6237,7 +6364,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6237
6364
  // Forward chaining to fixpoint
6238
6365
  // ===========================================================================
6239
6366
 
6240
- function forwardChain(facts, forwardRules, backRules) {
6367
+ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */) {
6241
6368
  ensureFactIndexes(facts);
6242
6369
  ensureBackRuleIndexes(backRules);
6243
6370
 
@@ -6266,7 +6393,12 @@ function forwardChain(facts, forwardRules, backRules) {
6266
6393
 
6267
6394
  function setScopedSnapshot(snap) {
6268
6395
  if (!Object.prototype.hasOwnProperty.call(facts, '__scopedSnapshot')) {
6269
- Object.defineProperty(facts, '__scopedSnapshot', { value: snap, enumerable: false, writable: true, configurable: true });
6396
+ Object.defineProperty(facts, '__scopedSnapshot', {
6397
+ value: snap,
6398
+ enumerable: false,
6399
+ writable: true,
6400
+ configurable: true,
6401
+ });
6270
6402
  } else {
6271
6403
  facts.__scopedSnapshot = snap;
6272
6404
  }
@@ -6275,7 +6407,12 @@ function forwardChain(facts, forwardRules, backRules) {
6275
6407
  function makeScopedSnapshot() {
6276
6408
  const snap = facts.slice();
6277
6409
  ensureFactIndexes(snap);
6278
- Object.defineProperty(snap, '__scopedSnapshot', { value: snap, enumerable: false, writable: true, configurable: true });
6410
+ Object.defineProperty(snap, '__scopedSnapshot', {
6411
+ value: snap,
6412
+ enumerable: false,
6413
+ writable: true,
6414
+ configurable: true,
6415
+ });
6279
6416
  return snap;
6280
6417
  }
6281
6418
 
@@ -6309,20 +6446,31 @@ function forwardChain(facts, forwardRules, backRules) {
6309
6446
  const isFwRuleTriple =
6310
6447
  isLogImplies(instantiated.p) &&
6311
6448
  ((instantiated.s instanceof GraphTerm && instantiated.o instanceof GraphTerm) ||
6312
- (instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof GraphTerm) ||
6313
- (instantiated.s instanceof GraphTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true'));
6449
+ (instantiated.s instanceof Literal &&
6450
+ instantiated.s.value === 'true' &&
6451
+ instantiated.o instanceof GraphTerm) ||
6452
+ (instantiated.s instanceof GraphTerm &&
6453
+ instantiated.o instanceof Literal &&
6454
+ instantiated.o.value === 'true'));
6314
6455
 
6315
6456
  const isBwRuleTriple =
6316
6457
  isLogImpliedBy(instantiated.p) &&
6317
6458
  ((instantiated.s instanceof GraphTerm && instantiated.o instanceof GraphTerm) ||
6318
- (instantiated.s instanceof GraphTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true') ||
6319
- (instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof GraphTerm));
6459
+ (instantiated.s instanceof GraphTerm &&
6460
+ instantiated.o instanceof Literal &&
6461
+ instantiated.o.value === 'true') ||
6462
+ (instantiated.s instanceof Literal &&
6463
+ instantiated.s.value === 'true' &&
6464
+ instantiated.o instanceof GraphTerm));
6320
6465
 
6321
6466
  if (isFwRuleTriple || isBwRuleTriple) {
6322
6467
  if (!hasFactIndexed(facts, instantiated)) {
6323
6468
  factList.push(instantiated);
6324
6469
  pushFactIndexed(facts, instantiated);
6325
- derivedForward.push(new DerivedFact(instantiated, r, instantiatedPremises.slice(), { ...s }));
6470
+ const df = new DerivedFact(instantiated, r, instantiatedPremises.slice(), { ...s });
6471
+ derivedForward.push(df);
6472
+ if (typeof onDerived === 'function') onDerived(df);
6473
+
6326
6474
  changed = true;
6327
6475
  }
6328
6476
 
@@ -6379,14 +6527,26 @@ function forwardChain(facts, forwardRules, backRules) {
6379
6527
  }
6380
6528
 
6381
6529
  // Only skolemize blank nodes that occur explicitly in the rule head
6382
- const inst = skolemizeTripleForHeadBlanks(instantiated, r.headBlankLabels, skMap, skCounter, fireKey, headSkolemCache);
6530
+ const inst = skolemizeTripleForHeadBlanks(
6531
+ instantiated,
6532
+ r.headBlankLabels,
6533
+ skMap,
6534
+ skCounter,
6535
+ fireKey,
6536
+ headSkolemCache,
6537
+ );
6383
6538
 
6384
6539
  if (!isGroundTriple(inst)) continue;
6385
6540
  if (hasFactIndexed(facts, inst)) continue;
6386
6541
 
6387
6542
  factList.push(inst);
6388
6543
  pushFactIndexed(facts, inst);
6389
- derivedForward.push(new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s }));
6544
+ const df = new DerivedFact(inst, r, instantiatedPremises.slice(), {
6545
+ ...s,
6546
+ });
6547
+ derivedForward.push(df);
6548
+ if (typeof onDerived === 'function') onDerived(df);
6549
+
6390
6550
  changed = true;
6391
6551
  }
6392
6552
  }
@@ -6722,6 +6882,53 @@ function __collectOutputStringsFromFacts(facts, prefixes) {
6722
6882
  return pairs.map((p) => p.text).join('');
6723
6883
  }
6724
6884
 
6885
+ function reasonStream(n3Text, opts = {}) {
6886
+ const { baseIri = null, proof = false, onDerived = null, includeInputFactsInClosure = true } = opts;
6887
+
6888
+ proofCommentsEnabled = !!proof;
6889
+
6890
+ const toks = lex(n3Text);
6891
+ const parser = new Parser(toks);
6892
+ if (baseIri) parser.prefixes.setBase(baseIri);
6893
+
6894
+ let prefixes, triples, frules, brules;
6895
+ [prefixes, triples, frules, brules] = parser.parseDocument();
6896
+
6897
+ materializeRdfLists(triples, frules, brules);
6898
+
6899
+ // facts becomes the saturated closure because pushFactIndexed(...) appends into it
6900
+ const facts = triples.filter((tr) => isGroundTriple(tr));
6901
+
6902
+ const derived = forwardChain(facts, frules, brules, (df) => {
6903
+ if (typeof onDerived === 'function') {
6904
+ onDerived({
6905
+ triple: tripleToN3(df.fact, prefixes),
6906
+ df,
6907
+ });
6908
+ }
6909
+ });
6910
+
6911
+ const closureTriples = includeInputFactsInClosure ? facts : derived.map((d) => d.fact);
6912
+
6913
+ return {
6914
+ prefixes,
6915
+ facts, // saturated closure (Triple[])
6916
+ derived, // DerivedFact[]
6917
+ closureN3: closureTriples.map((t) => tripleToN3(t, prefixes)).join('\n'),
6918
+ };
6919
+ }
6920
+
6921
+ // Minimal export surface for Node + browser/worker
6922
+ const EYELING_API = { reasonStream };
6923
+
6924
+ try {
6925
+ if (typeof module !== 'undefined' && module.exports) module.exports = EYELING_API;
6926
+ } catch (_) {}
6927
+
6928
+ try {
6929
+ if (typeof self !== 'undefined') self.eyeling = EYELING_API;
6930
+ } catch (_) {}
6931
+
6725
6932
  function main() {
6726
6933
  // Drop "node" and script name; keep only user-provided args
6727
6934
  const argv = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.7.11",
3
+ "version": "1.7.13",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [