eyeling 1.10.1 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/eyeling.js CHANGED
@@ -357,6 +357,10 @@ const { liftBlankRuleVars, reorderPremiseForConstraints, isConstraintBuiltin } =
357
357
 
358
358
  const { termToN3, tripleToN3 } = require('./printing');
359
359
 
360
+ const trace = require('./trace');
361
+ const time = require('./time');
362
+ const { deterministicSkolemIdFromKey } = require('./skolem');
363
+
360
364
  let version = 'dev';
361
365
  try {
362
366
  // Node: keep package.json version if available
@@ -726,146 +730,6 @@ let proofCommentsEnabled = false;
726
730
  // Super restricted mode: disable *all* builtins except => / <= (log:implies / log:impliedBy)
727
731
  let superRestrictedMode = false;
728
732
 
729
- // Debug/trace printing support (log:trace)
730
- let __tracePrefixes = null;
731
-
732
- function __traceWriteLine(line) {
733
- // Prefer stderr in Node, fall back to console.error elsewhere.
734
- try {
735
- if (__IS_NODE && typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
736
- process.stderr.write(String(line) + '\n');
737
- return;
738
- }
739
- } catch (_) {}
740
- try {
741
- if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
742
- } catch (_) {}
743
- }
744
-
745
- // ----------------------------------------------------------------------------
746
- // Deterministic time support
747
- // ----------------------------------------------------------------------------
748
- // If set, overrides time:localTime across the whole run (and across runs if you
749
- // pass the same value). Store as xsd:dateTime *lexical* string (no quotes).
750
- let fixedNowLex = null;
751
-
752
- // If not fixed, we still memoize one value per run to avoid re-firing rules.
753
- let runNowLex = null;
754
-
755
- // ===========================================================================
756
- // Run-level time helpers
757
- // ===========================================================================
758
-
759
- function localIsoDateTimeString(d) {
760
- function pad(n, width = 2) {
761
- return String(n).padStart(width, '0');
762
- }
763
- const year = d.getFullYear();
764
- const month = d.getMonth() + 1;
765
- const day = d.getDate();
766
- const hour = d.getHours();
767
- const min = d.getMinutes();
768
- const sec = d.getSeconds();
769
- const ms = d.getMilliseconds();
770
- const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
771
- const sign = offsetMin >= 0 ? '+' : '-';
772
- const abs = Math.abs(offsetMin);
773
- const oh = Math.floor(abs / 60);
774
- const om = abs % 60;
775
- const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
776
- return (
777
- pad(year, 4) +
778
- '-' +
779
- pad(month) +
780
- '-' +
781
- pad(day) +
782
- 'T' +
783
- pad(hour) +
784
- ':' +
785
- pad(min) +
786
- ':' +
787
- pad(sec) +
788
- msPart +
789
- sign +
790
- pad(oh) +
791
- ':' +
792
- pad(om)
793
- );
794
- }
795
-
796
- function utcIsoDateTimeStringFromEpochSeconds(sec) {
797
- const ms = sec * 1000;
798
- const d = new Date(ms);
799
- function pad(n, w = 2) {
800
- return String(n).padStart(w, '0');
801
- }
802
- const year = d.getUTCFullYear();
803
- const month = d.getUTCMonth() + 1;
804
- const day = d.getUTCDate();
805
- const hour = d.getUTCHours();
806
- const min = d.getUTCMinutes();
807
- const s2 = d.getUTCSeconds();
808
- const ms2 = d.getUTCMilliseconds();
809
- const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
810
- return (
811
- pad(year, 4) +
812
- '-' +
813
- pad(month) +
814
- '-' +
815
- pad(day) +
816
- 'T' +
817
- pad(hour) +
818
- ':' +
819
- pad(min) +
820
- ':' +
821
- pad(s2) +
822
- msPart +
823
- '+00:00'
824
- );
825
- }
826
-
827
- function getNowLex() {
828
- if (fixedNowLex) return fixedNowLex;
829
- if (runNowLex) return runNowLex;
830
- runNowLex = localIsoDateTimeString(new Date());
831
- return runNowLex;
832
- }
833
-
834
- // Deterministic pseudo-UUID from a string key (for log:skolem).
835
- // Not cryptographically strong, but stable and platform-independent.
836
- function deterministicSkolemIdFromKey(key) {
837
- // Four 32-bit FNV-1a style accumulators with slight variation
838
- let h1 = 0x811c9dc5;
839
- let h2 = 0x811c9dc5;
840
- let h3 = 0x811c9dc5;
841
- let h4 = 0x811c9dc5;
842
-
843
- for (let i = 0; i < key.length; i++) {
844
- const c = key.charCodeAt(i);
845
-
846
- h1 ^= c;
847
- h1 = (h1 * 0x01000193) >>> 0;
848
-
849
- h2 ^= c + 1;
850
- h2 = (h2 * 0x01000193) >>> 0;
851
-
852
- h3 ^= c + 2;
853
- h3 = (h3 * 0x01000193) >>> 0;
854
-
855
- h4 ^= c + 3;
856
- h4 = (h4 * 0x01000193) >>> 0;
857
- }
858
-
859
- const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
860
-
861
- // Format like a UUID: 8-4-4-4-12
862
- return (
863
- hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20)
864
- );
865
- }
866
-
867
- let runLocalTimeCache = null;
868
-
869
733
  // ===========================================================================
870
734
  function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
871
735
  if (t instanceof Blank) {
@@ -3157,7 +3021,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3157
3021
  const secs = parseNumOrDuration(b0);
3158
3022
  if (secs !== null) {
3159
3023
  const outSecs = aDt.getTime() / 1000.0 - secs;
3160
- const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
3024
+ const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
3161
3025
  const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
3162
3026
  if (g.o instanceof Var) {
3163
3027
  const s2 = { ...subst };
@@ -3693,7 +3557,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3693
3557
  // time:localTime
3694
3558
  // "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
3695
3559
  if (pv === TIME_NS + 'localTime') {
3696
- const now = getNowLex();
3560
+ const now = time.getNowLex();
3697
3561
 
3698
3562
  if (g.o instanceof Var) {
3699
3563
  const s2 = { ...subst };
@@ -4599,12 +4463,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4599
4463
  // Side-effecting debug output (to stderr). Always succeeds once.
4600
4464
  // to mimic EYE's fm(...) formatting branch.
4601
4465
  if (pv === LOG_NS + 'trace') {
4602
- const pref = __tracePrefixes || PrefixEnv.newDefault();
4466
+ const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
4603
4467
 
4604
4468
  const xStr = termToN3(g.s, pref);
4605
4469
  const yStr = termToN3(g.o, pref);
4606
4470
 
4607
- __traceWriteLine(`${xStr} TRACE ${yStr}`);
4471
+ trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
4608
4472
  return [{ ...subst }];
4609
4473
  }
4610
4474
 
@@ -5930,7 +5794,7 @@ function reasonStream(n3Text, opts = {}) {
5930
5794
  let prefixes, triples, frules, brules;
5931
5795
  [prefixes, triples, frules, brules] = parser.parseDocument();
5932
5796
  // Make the parsed prefixes available to log:trace output
5933
- __tracePrefixes = prefixes;
5797
+ trace.setTracePrefixes(prefixes);
5934
5798
 
5935
5799
  materializeRdfLists(triples, frules, brules);
5936
5800
 
@@ -5995,11 +5859,11 @@ function setSuperRestrictedMode(v) {
5995
5859
  }
5996
5860
 
5997
5861
  function getTracePrefixes() {
5998
- return __tracePrefixes;
5862
+ return trace.getTracePrefixes();
5999
5863
  }
6000
5864
 
6001
5865
  function setTracePrefixes(v) {
6002
- __tracePrefixes = v;
5866
+ trace.setTracePrefixes(v);
6003
5867
  }
6004
5868
 
6005
5869
  module.exports = {
@@ -7883,6 +7747,202 @@ module.exports = {
7883
7747
  reorderPremiseForConstraints,
7884
7748
  };
7885
7749
 
7750
+ };
7751
+ __modules["lib/skolem.js"] = function(require, module, exports){
7752
+ 'use strict';
7753
+
7754
+ // Deterministic pseudo-UUID from a string key (for log:skolem).
7755
+ // Not cryptographically strong, but stable and platform-independent.
7756
+
7757
+ function deterministicSkolemIdFromKey(key) {
7758
+ // Four 32-bit FNV-1a style accumulators with slight variation
7759
+ let h1 = 0x811c9dc5;
7760
+ let h2 = 0x811c9dc5;
7761
+ let h3 = 0x811c9dc5;
7762
+ let h4 = 0x811c9dc5;
7763
+
7764
+ for (let i = 0; i < key.length; i++) {
7765
+ const c = key.charCodeAt(i);
7766
+
7767
+ h1 ^= c;
7768
+ h1 = (h1 * 0x01000193) >>> 0;
7769
+
7770
+ h2 ^= c + 1;
7771
+ h2 = (h2 * 0x01000193) >>> 0;
7772
+
7773
+ h3 ^= c + 2;
7774
+ h3 = (h3 * 0x01000193) >>> 0;
7775
+
7776
+ h4 ^= c + 3;
7777
+ h4 = (h4 * 0x01000193) >>> 0;
7778
+ }
7779
+
7780
+ const hex = [h1, h2, h3, h4]
7781
+ .map((h) => h.toString(16).padStart(8, '0'))
7782
+ .join(''); // 32 hex chars
7783
+
7784
+ // Format like a UUID: 8-4-4-4-12
7785
+ return (
7786
+ hex.slice(0, 8) +
7787
+ '-' +
7788
+ hex.slice(8, 12) +
7789
+ '-' +
7790
+ hex.slice(12, 16) +
7791
+ '-' +
7792
+ hex.slice(16, 20) +
7793
+ '-' +
7794
+ hex.slice(20)
7795
+ );
7796
+ }
7797
+
7798
+ module.exports = {
7799
+ deterministicSkolemIdFromKey,
7800
+ };
7801
+
7802
+ };
7803
+ __modules["lib/time.js"] = function(require, module, exports){
7804
+ 'use strict';
7805
+
7806
+ // Deterministic time support used by time:* builtins.
7807
+ // This logic is kept in its own module so the core engine stays focused.
7808
+
7809
+ // If set, overrides time:localTime across the whole run.
7810
+ // Store as xsd:dateTime *lexical* string (no quotes).
7811
+ let fixedNowLex = null;
7812
+
7813
+ // If not fixed, memoize one value per run to avoid re-firing rules.
7814
+ let runNowLex = null;
7815
+
7816
+ function localIsoDateTimeString(d) {
7817
+ function pad(n, width = 2) {
7818
+ return String(n).padStart(width, '0');
7819
+ }
7820
+ const year = d.getFullYear();
7821
+ const month = d.getMonth() + 1;
7822
+ const day = d.getDate();
7823
+ const hour = d.getHours();
7824
+ const min = d.getMinutes();
7825
+ const sec = d.getSeconds();
7826
+ const ms = d.getMilliseconds();
7827
+ const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
7828
+ const sign = offsetMin >= 0 ? '+' : '-';
7829
+ const abs = Math.abs(offsetMin);
7830
+ const oh = Math.floor(abs / 60);
7831
+ const om = abs % 60;
7832
+ const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
7833
+ return (
7834
+ pad(year, 4) +
7835
+ '-' +
7836
+ pad(month) +
7837
+ '-' +
7838
+ pad(day) +
7839
+ 'T' +
7840
+ pad(hour) +
7841
+ ':' +
7842
+ pad(min) +
7843
+ ':' +
7844
+ pad(sec) +
7845
+ msPart +
7846
+ sign +
7847
+ pad(oh) +
7848
+ ':' +
7849
+ pad(om)
7850
+ );
7851
+ }
7852
+
7853
+ function utcIsoDateTimeStringFromEpochSeconds(sec) {
7854
+ const ms = sec * 1000;
7855
+ const d = new Date(ms);
7856
+ function pad(n, w = 2) {
7857
+ return String(n).padStart(w, '0');
7858
+ }
7859
+ const year = d.getUTCFullYear();
7860
+ const month = d.getUTCMonth() + 1;
7861
+ const day = d.getUTCDate();
7862
+ const hour = d.getUTCHours();
7863
+ const min = d.getUTCMinutes();
7864
+ const s2 = d.getUTCSeconds();
7865
+ const ms2 = d.getUTCMilliseconds();
7866
+ const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
7867
+ return (
7868
+ pad(year, 4) +
7869
+ '-' +
7870
+ pad(month) +
7871
+ '-' +
7872
+ pad(day) +
7873
+ 'T' +
7874
+ pad(hour) +
7875
+ ':' +
7876
+ pad(min) +
7877
+ ':' +
7878
+ pad(s2) +
7879
+ msPart +
7880
+ '+00:00'
7881
+ );
7882
+ }
7883
+
7884
+ function getNowLex() {
7885
+ if (fixedNowLex) return fixedNowLex;
7886
+ if (runNowLex) return runNowLex;
7887
+ runNowLex = localIsoDateTimeString(new Date());
7888
+ return runNowLex;
7889
+ }
7890
+
7891
+ function setFixedNowLex(v) {
7892
+ fixedNowLex = v ? String(v) : null;
7893
+ // When fixed changes, clear memoized run value.
7894
+ runNowLex = null;
7895
+ }
7896
+
7897
+ function resetRunNowLex() {
7898
+ runNowLex = null;
7899
+ }
7900
+
7901
+ module.exports = {
7902
+ getNowLex,
7903
+ setFixedNowLex,
7904
+ resetRunNowLex,
7905
+ utcIsoDateTimeStringFromEpochSeconds,
7906
+ };
7907
+
7908
+ };
7909
+ __modules["lib/trace.js"] = function(require, module, exports){
7910
+ /* eslint-disable no-console */
7911
+ 'use strict';
7912
+
7913
+ // Small module for debug/trace printing (log:trace) and its run-level state.
7914
+ // Kept separate from engine.js so browser demo + CLI can share behavior.
7915
+
7916
+ let tracePrefixes = null;
7917
+
7918
+ function getTracePrefixes() {
7919
+ return tracePrefixes;
7920
+ }
7921
+
7922
+ function setTracePrefixes(v) {
7923
+ tracePrefixes = v;
7924
+ }
7925
+
7926
+ function writeTraceLine(line) {
7927
+ // Prefer stderr in Node, fall back to console.error elsewhere.
7928
+ try {
7929
+ // eslint-disable-next-line no-undef
7930
+ if (typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
7931
+ process.stderr.write(String(line) + '\n');
7932
+ return;
7933
+ }
7934
+ } catch (_) {}
7935
+ try {
7936
+ if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
7937
+ } catch (_) {}
7938
+ }
7939
+
7940
+ module.exports = {
7941
+ getTracePrefixes,
7942
+ setTracePrefixes,
7943
+ writeTraceLine,
7944
+ };
7945
+
7886
7946
  };
7887
7947
 
7888
7948
  function __normPath(p){
package/lib/engine.js CHANGED
@@ -39,6 +39,10 @@ const { liftBlankRuleVars, reorderPremiseForConstraints, isConstraintBuiltin } =
39
39
 
40
40
  const { termToN3, tripleToN3 } = require('./printing');
41
41
 
42
+ const trace = require('./trace');
43
+ const time = require('./time');
44
+ const { deterministicSkolemIdFromKey } = require('./skolem');
45
+
42
46
  let version = 'dev';
43
47
  try {
44
48
  // Node: keep package.json version if available
@@ -408,146 +412,6 @@ let proofCommentsEnabled = false;
408
412
  // Super restricted mode: disable *all* builtins except => / <= (log:implies / log:impliedBy)
409
413
  let superRestrictedMode = false;
410
414
 
411
- // Debug/trace printing support (log:trace)
412
- let __tracePrefixes = null;
413
-
414
- function __traceWriteLine(line) {
415
- // Prefer stderr in Node, fall back to console.error elsewhere.
416
- try {
417
- if (__IS_NODE && typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
418
- process.stderr.write(String(line) + '\n');
419
- return;
420
- }
421
- } catch (_) {}
422
- try {
423
- if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
424
- } catch (_) {}
425
- }
426
-
427
- // ----------------------------------------------------------------------------
428
- // Deterministic time support
429
- // ----------------------------------------------------------------------------
430
- // If set, overrides time:localTime across the whole run (and across runs if you
431
- // pass the same value). Store as xsd:dateTime *lexical* string (no quotes).
432
- let fixedNowLex = null;
433
-
434
- // If not fixed, we still memoize one value per run to avoid re-firing rules.
435
- let runNowLex = null;
436
-
437
- // ===========================================================================
438
- // Run-level time helpers
439
- // ===========================================================================
440
-
441
- function localIsoDateTimeString(d) {
442
- function pad(n, width = 2) {
443
- return String(n).padStart(width, '0');
444
- }
445
- const year = d.getFullYear();
446
- const month = d.getMonth() + 1;
447
- const day = d.getDate();
448
- const hour = d.getHours();
449
- const min = d.getMinutes();
450
- const sec = d.getSeconds();
451
- const ms = d.getMilliseconds();
452
- const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
453
- const sign = offsetMin >= 0 ? '+' : '-';
454
- const abs = Math.abs(offsetMin);
455
- const oh = Math.floor(abs / 60);
456
- const om = abs % 60;
457
- const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
458
- return (
459
- pad(year, 4) +
460
- '-' +
461
- pad(month) +
462
- '-' +
463
- pad(day) +
464
- 'T' +
465
- pad(hour) +
466
- ':' +
467
- pad(min) +
468
- ':' +
469
- pad(sec) +
470
- msPart +
471
- sign +
472
- pad(oh) +
473
- ':' +
474
- pad(om)
475
- );
476
- }
477
-
478
- function utcIsoDateTimeStringFromEpochSeconds(sec) {
479
- const ms = sec * 1000;
480
- const d = new Date(ms);
481
- function pad(n, w = 2) {
482
- return String(n).padStart(w, '0');
483
- }
484
- const year = d.getUTCFullYear();
485
- const month = d.getUTCMonth() + 1;
486
- const day = d.getUTCDate();
487
- const hour = d.getUTCHours();
488
- const min = d.getUTCMinutes();
489
- const s2 = d.getUTCSeconds();
490
- const ms2 = d.getUTCMilliseconds();
491
- const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
492
- return (
493
- pad(year, 4) +
494
- '-' +
495
- pad(month) +
496
- '-' +
497
- pad(day) +
498
- 'T' +
499
- pad(hour) +
500
- ':' +
501
- pad(min) +
502
- ':' +
503
- pad(s2) +
504
- msPart +
505
- '+00:00'
506
- );
507
- }
508
-
509
- function getNowLex() {
510
- if (fixedNowLex) return fixedNowLex;
511
- if (runNowLex) return runNowLex;
512
- runNowLex = localIsoDateTimeString(new Date());
513
- return runNowLex;
514
- }
515
-
516
- // Deterministic pseudo-UUID from a string key (for log:skolem).
517
- // Not cryptographically strong, but stable and platform-independent.
518
- function deterministicSkolemIdFromKey(key) {
519
- // Four 32-bit FNV-1a style accumulators with slight variation
520
- let h1 = 0x811c9dc5;
521
- let h2 = 0x811c9dc5;
522
- let h3 = 0x811c9dc5;
523
- let h4 = 0x811c9dc5;
524
-
525
- for (let i = 0; i < key.length; i++) {
526
- const c = key.charCodeAt(i);
527
-
528
- h1 ^= c;
529
- h1 = (h1 * 0x01000193) >>> 0;
530
-
531
- h2 ^= c + 1;
532
- h2 = (h2 * 0x01000193) >>> 0;
533
-
534
- h3 ^= c + 2;
535
- h3 = (h3 * 0x01000193) >>> 0;
536
-
537
- h4 ^= c + 3;
538
- h4 = (h4 * 0x01000193) >>> 0;
539
- }
540
-
541
- const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
542
-
543
- // Format like a UUID: 8-4-4-4-12
544
- return (
545
- hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20)
546
- );
547
- }
548
-
549
- let runLocalTimeCache = null;
550
-
551
415
  // ===========================================================================
552
416
  function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
553
417
  if (t instanceof Blank) {
@@ -2839,7 +2703,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2839
2703
  const secs = parseNumOrDuration(b0);
2840
2704
  if (secs !== null) {
2841
2705
  const outSecs = aDt.getTime() / 1000.0 - secs;
2842
- const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
2706
+ const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
2843
2707
  const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
2844
2708
  if (g.o instanceof Var) {
2845
2709
  const s2 = { ...subst };
@@ -3375,7 +3239,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3375
3239
  // time:localTime
3376
3240
  // "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
3377
3241
  if (pv === TIME_NS + 'localTime') {
3378
- const now = getNowLex();
3242
+ const now = time.getNowLex();
3379
3243
 
3380
3244
  if (g.o instanceof Var) {
3381
3245
  const s2 = { ...subst };
@@ -4281,12 +4145,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4281
4145
  // Side-effecting debug output (to stderr). Always succeeds once.
4282
4146
  // to mimic EYE's fm(...) formatting branch.
4283
4147
  if (pv === LOG_NS + 'trace') {
4284
- const pref = __tracePrefixes || PrefixEnv.newDefault();
4148
+ const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
4285
4149
 
4286
4150
  const xStr = termToN3(g.s, pref);
4287
4151
  const yStr = termToN3(g.o, pref);
4288
4152
 
4289
- __traceWriteLine(`${xStr} TRACE ${yStr}`);
4153
+ trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
4290
4154
  return [{ ...subst }];
4291
4155
  }
4292
4156
 
@@ -5612,7 +5476,7 @@ function reasonStream(n3Text, opts = {}) {
5612
5476
  let prefixes, triples, frules, brules;
5613
5477
  [prefixes, triples, frules, brules] = parser.parseDocument();
5614
5478
  // Make the parsed prefixes available to log:trace output
5615
- __tracePrefixes = prefixes;
5479
+ trace.setTracePrefixes(prefixes);
5616
5480
 
5617
5481
  materializeRdfLists(triples, frules, brules);
5618
5482
 
@@ -5677,11 +5541,11 @@ function setSuperRestrictedMode(v) {
5677
5541
  }
5678
5542
 
5679
5543
  function getTracePrefixes() {
5680
- return __tracePrefixes;
5544
+ return trace.getTracePrefixes();
5681
5545
  }
5682
5546
 
5683
5547
  function setTracePrefixes(v) {
5684
- __tracePrefixes = v;
5548
+ trace.setTracePrefixes(v);
5685
5549
  }
5686
5550
 
5687
5551
  module.exports = {
package/lib/skolem.js ADDED
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ // Deterministic pseudo-UUID from a string key (for log:skolem).
4
+ // Not cryptographically strong, but stable and platform-independent.
5
+
6
+ function deterministicSkolemIdFromKey(key) {
7
+ // Four 32-bit FNV-1a style accumulators with slight variation
8
+ let h1 = 0x811c9dc5;
9
+ let h2 = 0x811c9dc5;
10
+ let h3 = 0x811c9dc5;
11
+ let h4 = 0x811c9dc5;
12
+
13
+ for (let i = 0; i < key.length; i++) {
14
+ const c = key.charCodeAt(i);
15
+
16
+ h1 ^= c;
17
+ h1 = (h1 * 0x01000193) >>> 0;
18
+
19
+ h2 ^= c + 1;
20
+ h2 = (h2 * 0x01000193) >>> 0;
21
+
22
+ h3 ^= c + 2;
23
+ h3 = (h3 * 0x01000193) >>> 0;
24
+
25
+ h4 ^= c + 3;
26
+ h4 = (h4 * 0x01000193) >>> 0;
27
+ }
28
+
29
+ const hex = [h1, h2, h3, h4]
30
+ .map((h) => h.toString(16).padStart(8, '0'))
31
+ .join(''); // 32 hex chars
32
+
33
+ // Format like a UUID: 8-4-4-4-12
34
+ return (
35
+ hex.slice(0, 8) +
36
+ '-' +
37
+ hex.slice(8, 12) +
38
+ '-' +
39
+ hex.slice(12, 16) +
40
+ '-' +
41
+ hex.slice(16, 20) +
42
+ '-' +
43
+ hex.slice(20)
44
+ );
45
+ }
46
+
47
+ module.exports = {
48
+ deterministicSkolemIdFromKey,
49
+ };
package/lib/time.js ADDED
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ // Deterministic time support used by time:* builtins.
4
+ // This logic is kept in its own module so the core engine stays focused.
5
+
6
+ // If set, overrides time:localTime across the whole run.
7
+ // Store as xsd:dateTime *lexical* string (no quotes).
8
+ let fixedNowLex = null;
9
+
10
+ // If not fixed, memoize one value per run to avoid re-firing rules.
11
+ let runNowLex = null;
12
+
13
+ function localIsoDateTimeString(d) {
14
+ function pad(n, width = 2) {
15
+ return String(n).padStart(width, '0');
16
+ }
17
+ const year = d.getFullYear();
18
+ const month = d.getMonth() + 1;
19
+ const day = d.getDate();
20
+ const hour = d.getHours();
21
+ const min = d.getMinutes();
22
+ const sec = d.getSeconds();
23
+ const ms = d.getMilliseconds();
24
+ const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
25
+ const sign = offsetMin >= 0 ? '+' : '-';
26
+ const abs = Math.abs(offsetMin);
27
+ const oh = Math.floor(abs / 60);
28
+ const om = abs % 60;
29
+ const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
30
+ return (
31
+ pad(year, 4) +
32
+ '-' +
33
+ pad(month) +
34
+ '-' +
35
+ pad(day) +
36
+ 'T' +
37
+ pad(hour) +
38
+ ':' +
39
+ pad(min) +
40
+ ':' +
41
+ pad(sec) +
42
+ msPart +
43
+ sign +
44
+ pad(oh) +
45
+ ':' +
46
+ pad(om)
47
+ );
48
+ }
49
+
50
+ function utcIsoDateTimeStringFromEpochSeconds(sec) {
51
+ const ms = sec * 1000;
52
+ const d = new Date(ms);
53
+ function pad(n, w = 2) {
54
+ return String(n).padStart(w, '0');
55
+ }
56
+ const year = d.getUTCFullYear();
57
+ const month = d.getUTCMonth() + 1;
58
+ const day = d.getUTCDate();
59
+ const hour = d.getUTCHours();
60
+ const min = d.getUTCMinutes();
61
+ const s2 = d.getUTCSeconds();
62
+ const ms2 = d.getUTCMilliseconds();
63
+ const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
64
+ return (
65
+ pad(year, 4) +
66
+ '-' +
67
+ pad(month) +
68
+ '-' +
69
+ pad(day) +
70
+ 'T' +
71
+ pad(hour) +
72
+ ':' +
73
+ pad(min) +
74
+ ':' +
75
+ pad(s2) +
76
+ msPart +
77
+ '+00:00'
78
+ );
79
+ }
80
+
81
+ function getNowLex() {
82
+ if (fixedNowLex) return fixedNowLex;
83
+ if (runNowLex) return runNowLex;
84
+ runNowLex = localIsoDateTimeString(new Date());
85
+ return runNowLex;
86
+ }
87
+
88
+ function setFixedNowLex(v) {
89
+ fixedNowLex = v ? String(v) : null;
90
+ // When fixed changes, clear memoized run value.
91
+ runNowLex = null;
92
+ }
93
+
94
+ function resetRunNowLex() {
95
+ runNowLex = null;
96
+ }
97
+
98
+ module.exports = {
99
+ getNowLex,
100
+ setFixedNowLex,
101
+ resetRunNowLex,
102
+ utcIsoDateTimeStringFromEpochSeconds,
103
+ };
package/lib/trace.js ADDED
@@ -0,0 +1,35 @@
1
+ /* eslint-disable no-console */
2
+ 'use strict';
3
+
4
+ // Small module for debug/trace printing (log:trace) and its run-level state.
5
+ // Kept separate from engine.js so browser demo + CLI can share behavior.
6
+
7
+ let tracePrefixes = null;
8
+
9
+ function getTracePrefixes() {
10
+ return tracePrefixes;
11
+ }
12
+
13
+ function setTracePrefixes(v) {
14
+ tracePrefixes = v;
15
+ }
16
+
17
+ function writeTraceLine(line) {
18
+ // Prefer stderr in Node, fall back to console.error elsewhere.
19
+ try {
20
+ // eslint-disable-next-line no-undef
21
+ if (typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
22
+ process.stderr.write(String(line) + '\n');
23
+ return;
24
+ }
25
+ } catch (_) {}
26
+ try {
27
+ if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
28
+ } catch (_) {}
29
+ }
30
+
31
+ module.exports = {
32
+ getTracePrefixes,
33
+ setTracePrefixes,
34
+ writeTraceLine,
35
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [