eyeling 1.6.17 → 1.6.19

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 +220 -241
  2. package/package.json +1 -1
package/eyeling.js CHANGED
@@ -19,9 +19,9 @@
19
19
  const { version } = require('./package.json');
20
20
  const nodeCrypto = require('crypto');
21
21
 
22
- // ============================================================================
22
+ // ===========================================================================
23
23
  // Namespace constants
24
- // ============================================================================
24
+ // ===========================================================================
25
25
 
26
26
  const RDF_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
27
27
  const RDFS_NS = 'http://www.w3.org/2000/01/rdf-schema#';
@@ -87,14 +87,45 @@ let fixedNowLex = null;
87
87
  // If not fixed, we still memoize one value per run to avoid re-firing rules.
88
88
  let runNowLex = null;
89
89
 
90
- function normalizeDateTimeLex(s) {
91
- // Accept: 2025-... , "2025-..." , "2025-..."^^xsd:dateTime , "..."^^<...>
92
- if (s == null) return null;
93
- let t = String(s).trim();
94
- const caret = t.indexOf('^^');
95
- if (caret >= 0) t = t.slice(0, caret).trim();
96
- if (t.startsWith('"') && t.endsWith('"') && t.length >= 2) t = t.slice(1, -1);
97
- return t.trim();
90
+ // ===========================================================================
91
+ // Run-level time helpers
92
+ // ===========================================================================
93
+
94
+ function localIsoDateTimeString(d) {
95
+ function pad(n, width = 2) {
96
+ return String(n).padStart(width, '0');
97
+ }
98
+ const year = d.getFullYear();
99
+ const month = d.getMonth() + 1;
100
+ const day = d.getDate();
101
+ const hour = d.getHours();
102
+ const min = d.getMinutes();
103
+ const sec = d.getSeconds();
104
+ const ms = d.getMilliseconds();
105
+ const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
106
+ const sign = offsetMin >= 0 ? '+' : '-';
107
+ const abs = Math.abs(offsetMin);
108
+ const oh = Math.floor(abs / 60);
109
+ const om = abs % 60;
110
+ const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
111
+ return (
112
+ pad(year, 4) +
113
+ '-' +
114
+ pad(month) +
115
+ '-' +
116
+ pad(day) +
117
+ 'T' +
118
+ pad(hour) +
119
+ ':' +
120
+ pad(min) +
121
+ ':' +
122
+ pad(sec) +
123
+ msPart +
124
+ sign +
125
+ pad(oh) +
126
+ ':' +
127
+ pad(om)
128
+ );
98
129
  }
99
130
 
100
131
  function utcIsoDateTimeStringFromEpochSeconds(sec) {
@@ -154,9 +185,9 @@ function deterministicSkolemIdFromKey(key) {
154
185
 
155
186
  let runLocalTimeCache = null;
156
187
 
157
- // ============================================================================
188
+ // ===========================================================================
158
189
  // AST (Abstract Syntax Tree)
159
- // ============================================================================
190
+ // ===========================================================================
160
191
 
161
192
  class Term {}
162
193
 
@@ -238,9 +269,9 @@ class DerivedFact {
238
269
  }
239
270
  }
240
271
 
241
- // ============================================================================
272
+ // ===========================================================================
242
273
  // LEXER
243
- // ============================================================================
274
+ // ===========================================================================
244
275
 
245
276
  class Token {
246
277
  constructor(typ, value = null) {
@@ -631,9 +662,9 @@ function lex(inputText) {
631
662
  return tokens;
632
663
  }
633
664
 
634
- // ============================================================================
665
+ // ===========================================================================
635
666
  // PREFIX ENVIRONMENT
636
- // ============================================================================
667
+ // ===========================================================================
637
668
 
638
669
  class PrefixEnv {
639
670
  constructor(map) {
@@ -789,9 +820,9 @@ function collectBlankLabelsInTriples(triples) {
789
820
  return acc;
790
821
  }
791
822
 
792
- // ============================================================================
823
+ // ===========================================================================
793
824
  // PARSER
794
- // ============================================================================
825
+ // ===========================================================================
795
826
 
796
827
  class Parser {
797
828
  constructor(tokens) {
@@ -1231,9 +1262,9 @@ class Parser {
1231
1262
  }
1232
1263
  }
1233
1264
 
1234
- // ============================================================================
1265
+ // ===========================================================================
1235
1266
  // Blank-node lifting and Skolemization
1236
- // ============================================================================
1267
+ // ===========================================================================
1237
1268
 
1238
1269
  function liftBlankRuleVars(premise, conclusion) {
1239
1270
  function convertTerm(t, mapping, counter) {
@@ -1340,9 +1371,9 @@ function skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter, f
1340
1371
  );
1341
1372
  }
1342
1373
 
1343
- // ============================================================================
1374
+ // ===========================================================================
1344
1375
  // Alpha equivalence helpers
1345
- // ============================================================================
1376
+ // ===========================================================================
1346
1377
 
1347
1378
  function termsEqual(a, b) {
1348
1379
  if (a === b) return true;
@@ -1610,13 +1641,9 @@ function alphaEqTriple(a, b) {
1610
1641
  return alphaEqTerm(a.s, b.s, bmap) && alphaEqTerm(a.p, b.p, bmap) && alphaEqTerm(a.o, b.o, bmap);
1611
1642
  }
1612
1643
 
1613
- function hasAlphaEquiv(triples, tr) {
1614
- return triples.some((t) => alphaEqTriple(t, tr));
1615
- }
1616
-
1617
- // ============================================================================
1644
+ // ===========================================================================
1618
1645
  // Indexes (facts + backward rules)
1619
- // ============================================================================
1646
+ // ===========================================================================
1620
1647
  //
1621
1648
  // Facts:
1622
1649
  // - __byPred: Map<predicateIRI, Triple[]>
@@ -1784,9 +1811,9 @@ function indexBackRule(backRules, r) {
1784
1811
  }
1785
1812
  }
1786
1813
 
1787
- // ============================================================================
1814
+ // ===========================================================================
1788
1815
  // Special predicate helpers
1789
- // ============================================================================
1816
+ // ===========================================================================
1790
1817
 
1791
1818
  function isRdfTypePred(p) {
1792
1819
  return p instanceof Iri && p.value === RDF_NS + 'type';
@@ -1804,9 +1831,9 @@ function isLogImpliedBy(p) {
1804
1831
  return p instanceof Iri && p.value === LOG_NS + 'impliedBy';
1805
1832
  }
1806
1833
 
1807
- // ============================================================================
1834
+ // ===========================================================================
1808
1835
  // Constraint / "test" builtins
1809
- // ============================================================================
1836
+ // ===========================================================================
1810
1837
 
1811
1838
  function isConstraintBuiltin(tr) {
1812
1839
  if (!(tr.p instanceof Iri)) return false;
@@ -1855,12 +1882,10 @@ function isConstraintBuiltin(tr) {
1855
1882
  return false;
1856
1883
  }
1857
1884
 
1858
- /**
1859
- * Move constraint builtins to the end of the rule premise.
1860
- * This is a simple "delaying" strategy similar in spirit to Prolog's when/2:
1861
- * - normal goals first (can bind variables),
1862
- * - pure test / constraint builtins last (checked once bindings are in place).
1863
- */
1885
+ // Move constraint builtins to the end of the rule premise.
1886
+ // This is a simple "delaying" strategy similar in spirit to Prolog's when/2:
1887
+ // - normal goals first (can bind variables),
1888
+ // - pure test / constraint builtins last (checked once bindings are in place).
1864
1889
  function reorderPremiseForConstraints(premise) {
1865
1890
  if (!premise || premise.length === 0) return premise;
1866
1891
 
@@ -1874,9 +1899,9 @@ function reorderPremiseForConstraints(premise) {
1874
1899
  return normal.concat(delayed);
1875
1900
  }
1876
1901
 
1877
- // ============================================================================
1902
+ // ===========================================================================
1878
1903
  // Unification + substitution
1879
- // ============================================================================
1904
+ // ===========================================================================
1880
1905
 
1881
1906
  function containsVarTerm(t, v) {
1882
1907
  if (t instanceof Var) return t.name === v;
@@ -2188,9 +2213,9 @@ function composeSubst(outer, delta) {
2188
2213
  return out;
2189
2214
  }
2190
2215
 
2191
- // ============================================================================
2216
+ // ===========================================================================
2192
2217
  // BUILTINS
2193
- // ============================================================================
2218
+ // ===========================================================================
2194
2219
 
2195
2220
  function literalParts(lit) {
2196
2221
  // Split a literal into lexical form and datatype IRI (if any).
@@ -2528,9 +2553,9 @@ function parseXsdFloatSpecialLex(s) {
2528
2553
  return null;
2529
2554
  }
2530
2555
 
2531
- // ============================================================================
2556
+ // ===========================================================================
2532
2557
  // Math builtin helpers
2533
- // ============================================================================
2558
+ // ===========================================================================
2534
2559
 
2535
2560
  function formatXsdFloatSpecialLex(n) {
2536
2561
  if (n === Infinity) return 'INF';
@@ -2635,15 +2660,6 @@ function parseIntLiteral(t) {
2635
2660
  }
2636
2661
  }
2637
2662
 
2638
- function parseNumberLiteral(t) {
2639
- // Prefer BigInt for integers, fall back to Number for other numeric literals.
2640
- const bi = parseIntLiteral(t);
2641
- if (bi !== null) return bi;
2642
- const n = parseNum(t);
2643
- if (n !== null) return n;
2644
- return null;
2645
- }
2646
-
2647
2663
  function formatNum(n) {
2648
2664
  return String(n);
2649
2665
  }
@@ -2686,9 +2702,9 @@ function pow10n(k) {
2686
2702
  return 10n ** BigInt(k);
2687
2703
  }
2688
2704
 
2689
- // ============================================================================
2705
+ // ===========================================================================
2690
2706
  // Time & duration builtin helpers
2691
- // ============================================================================
2707
+ // ===========================================================================
2692
2708
 
2693
2709
  function parseXsdDateTerm(t) {
2694
2710
  if (!(t instanceof Literal)) return null;
@@ -3017,9 +3033,9 @@ function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
3017
3033
  return [];
3018
3034
  }
3019
3035
 
3020
- // ============================================================================
3036
+ // ===========================================================================
3021
3037
  // List builtin helpers
3022
- // ============================================================================
3038
+ // ===========================================================================
3023
3039
 
3024
3040
  function listAppendSplit(parts, resElems, subst) {
3025
3041
  if (!parts.length) {
@@ -3070,9 +3086,142 @@ function evalListRestLikeBuiltin(sTerm, oTerm, subst) {
3070
3086
  return [];
3071
3087
  }
3072
3088
 
3073
- // ============================================================================
3089
+ // ===========================================================================
3090
+ // RDF list materialization
3091
+ // ===========================================================================
3092
+
3093
+ // Turn RDF Collections described with rdf:first/rdf:rest (+ rdf:nil) into ListTerm terms.
3094
+ // This mutates triples/rules in-place so list:* builtins work on RDF-serialized lists too.
3095
+ function materializeRdfLists(triples, forwardRules, backwardRules) {
3096
+ const RDF_FIRST = RDF_NS + 'first';
3097
+ const RDF_REST = RDF_NS + 'rest';
3098
+ const RDF_NIL = RDF_NS + 'nil';
3099
+
3100
+ function nodeKey(t) {
3101
+ if (t instanceof Blank) return 'B:' + t.label;
3102
+ if (t instanceof Iri) return 'I:' + t.value;
3103
+ return null;
3104
+ }
3105
+
3106
+ // Collect first/rest arcs from *input triples*
3107
+ const firstMap = new Map(); // key(subject) -> Term (object)
3108
+ const restMap = new Map(); // key(subject) -> Term (object)
3109
+ for (const tr of triples) {
3110
+ if (!(tr.p instanceof Iri)) continue;
3111
+ const k = nodeKey(tr.s);
3112
+ if (!k) continue;
3113
+ if (tr.p.value === RDF_FIRST) firstMap.set(k, tr.o);
3114
+ else if (tr.p.value === RDF_REST) restMap.set(k, tr.o);
3115
+ }
3116
+ if (!firstMap.size && !restMap.size) return;
3117
+
3118
+ const cache = new Map(); // key(node) -> ListTerm
3119
+ const visiting = new Set(); // cycle guard
3120
+
3121
+ function buildListForKey(k) {
3122
+ if (cache.has(k)) return cache.get(k);
3123
+ if (visiting.has(k)) return null; // cycle => not a well-formed list
3124
+ visiting.add(k);
3125
+
3126
+ // rdf:nil => ()
3127
+ if (k === 'I:' + RDF_NIL) {
3128
+ const empty = new ListTerm([]);
3129
+ cache.set(k, empty);
3130
+ visiting.delete(k);
3131
+ return empty;
3132
+ }
3133
+
3134
+ const head = firstMap.get(k);
3135
+ const tail = restMap.get(k);
3136
+ if (head === undefined || tail === undefined) {
3137
+ visiting.delete(k);
3138
+ return null; // not a full cons cell
3139
+ }
3140
+
3141
+ const headTerm = rewriteTerm(head);
3142
+
3143
+ let tailListElems = null;
3144
+ if (tail instanceof Iri && tail.value === RDF_NIL) {
3145
+ tailListElems = [];
3146
+ } else {
3147
+ const tk = nodeKey(tail);
3148
+ if (!tk) {
3149
+ visiting.delete(k);
3150
+ return null;
3151
+ }
3152
+ const tailList = buildListForKey(tk);
3153
+ if (!tailList) {
3154
+ visiting.delete(k);
3155
+ return null;
3156
+ }
3157
+ tailListElems = tailList.elems;
3158
+ }
3159
+
3160
+ const out = new ListTerm([headTerm, ...tailListElems]);
3161
+ cache.set(k, out);
3162
+ visiting.delete(k);
3163
+ return out;
3164
+ }
3165
+
3166
+ function rewriteTerm(t) {
3167
+ // Replace list nodes (Blank/Iri) by their constructed ListTerm when possible
3168
+ const k = nodeKey(t);
3169
+ if (k) {
3170
+ const built = buildListForKey(k);
3171
+ if (built) return built;
3172
+ // Also rewrite rdf:nil even if not otherwise referenced
3173
+ if (t instanceof Iri && t.value === RDF_NIL) return new ListTerm([]);
3174
+ return t;
3175
+ }
3176
+ if (t instanceof ListTerm) {
3177
+ let changed = false;
3178
+ const elems = t.elems.map((e) => {
3179
+ const r = rewriteTerm(e);
3180
+ if (r !== e) changed = true;
3181
+ return r;
3182
+ });
3183
+ return changed ? new ListTerm(elems) : t;
3184
+ }
3185
+ if (t instanceof OpenListTerm) {
3186
+ let changed = false;
3187
+ const prefix = t.prefix.map((e) => {
3188
+ const r = rewriteTerm(e);
3189
+ if (r !== e) changed = true;
3190
+ return r;
3191
+ });
3192
+ return changed ? new OpenListTerm(prefix, t.tailVar) : t;
3193
+ }
3194
+ if (t instanceof FormulaTerm) {
3195
+ for (const tr of t.triples) rewriteTriple(tr);
3196
+ return t;
3197
+ }
3198
+ return t;
3199
+ }
3200
+
3201
+ function rewriteTriple(tr) {
3202
+ tr.s = rewriteTerm(tr.s);
3203
+ tr.p = rewriteTerm(tr.p);
3204
+ tr.o = rewriteTerm(tr.o);
3205
+ }
3206
+
3207
+ // Pre-build all reachable list heads
3208
+ for (const k of firstMap.keys()) buildListForKey(k);
3209
+
3210
+ // Rewrite input triples + rules in-place
3211
+ for (const tr of triples) rewriteTriple(tr);
3212
+ for (const r of forwardRules) {
3213
+ for (const tr of r.premise) rewriteTriple(tr);
3214
+ for (const tr of r.conclusion) rewriteTriple(tr);
3215
+ }
3216
+ for (const r of backwardRules) {
3217
+ for (const tr of r.premise) rewriteTriple(tr);
3218
+ for (const tr of r.conclusion) rewriteTriple(tr);
3219
+ }
3220
+ }
3221
+
3222
+ // ===========================================================================
3074
3223
  // Crypto builtin helpers
3075
- // ============================================================================
3224
+ // ===========================================================================
3076
3225
 
3077
3226
  function hashLiteralTerm(t, algo) {
3078
3227
  if (!(t instanceof Literal)) return null;
@@ -3098,9 +3247,9 @@ function evalCryptoHashBuiltin(g, subst, algo) {
3098
3247
  return s2 !== null ? [s2] : [];
3099
3248
  }
3100
3249
 
3101
- // ============================================================================
3250
+ // ===========================================================================
3102
3251
  // Builtin evaluation
3103
- // ============================================================================
3252
+ // ===========================================================================
3104
3253
  // Backward proof & builtins mutual recursion — declarations first
3105
3254
 
3106
3255
  function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
@@ -4560,9 +4709,9 @@ function isBuiltinPred(p) {
4560
4709
  );
4561
4710
  }
4562
4711
 
4563
- // ============================================================================
4712
+ // ===========================================================================
4564
4713
  // Backward proof (SLD-style)
4565
- // ============================================================================
4714
+ // ===========================================================================
4566
4715
 
4567
4716
  function standardizeRule(rule, gen) {
4568
4717
  function renameTerm(t, vmap, genArr) {
@@ -4609,9 +4758,9 @@ function listHasTriple(list, tr) {
4609
4758
  return list.some((t) => triplesEqual(t, tr));
4610
4759
  }
4611
4760
 
4612
- // ============================================================================
4761
+ // ===========================================================================
4613
4762
  // Substitution compaction (to avoid O(depth^2) in deep backward chains)
4614
- // ============================================================================
4763
+ // ===========================================================================
4615
4764
  //
4616
4765
  // Why: backward chaining with standardizeRule introduces fresh variables at
4617
4766
  // each step. composeSubst frequently copies a growing substitution object.
@@ -4846,9 +4995,9 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
4846
4995
  return results;
4847
4996
  }
4848
4997
 
4849
- // ============================================================================
4998
+ // ===========================================================================
4850
4999
  // Forward chaining to fixpoint
4851
- // ============================================================================
5000
+ // ===========================================================================
4852
5001
 
4853
5002
  function forwardChain(facts, forwardRules, backRules) {
4854
5003
  ensureFactIndexes(facts);
@@ -5032,9 +5181,9 @@ function forwardChain(facts, forwardRules, backRules) {
5032
5181
  return derivedForward;
5033
5182
  }
5034
5183
 
5035
- // ============================================================================
5184
+ // ===========================================================================
5036
5185
  // Pretty printing as N3/Turtle
5037
- // ============================================================================
5186
+ // ===========================================================================
5038
5187
 
5039
5188
  function termToN3(t, pref) {
5040
5189
  if (t instanceof Iri) {
@@ -5201,179 +5350,9 @@ function printExplanation(df, prefixes) {
5201
5350
  console.log('# ----------------------------------------------------------------------\n');
5202
5351
  }
5203
5352
 
5204
- // ============================================================================
5205
- // Misc helpers
5206
- // ============================================================================
5207
-
5208
- // Turn RDF Collections described with rdf:first/rdf:rest (+ rdf:nil) into ListTerm terms.
5209
- // This mutates triples/rules in-place so list:* builtins work on RDF-serialized lists too.
5210
- function materializeRdfLists(triples, forwardRules, backwardRules) {
5211
- const RDF_FIRST = RDF_NS + 'first';
5212
- const RDF_REST = RDF_NS + 'rest';
5213
- const RDF_NIL = RDF_NS + 'nil';
5214
-
5215
- function nodeKey(t) {
5216
- if (t instanceof Blank) return 'B:' + t.label;
5217
- if (t instanceof Iri) return 'I:' + t.value;
5218
- return null;
5219
- }
5220
-
5221
- // Collect first/rest arcs from *input triples*
5222
- const firstMap = new Map(); // key(subject) -> Term (object)
5223
- const restMap = new Map(); // key(subject) -> Term (object)
5224
- for (const tr of triples) {
5225
- if (!(tr.p instanceof Iri)) continue;
5226
- const k = nodeKey(tr.s);
5227
- if (!k) continue;
5228
- if (tr.p.value === RDF_FIRST) firstMap.set(k, tr.o);
5229
- else if (tr.p.value === RDF_REST) restMap.set(k, tr.o);
5230
- }
5231
- if (!firstMap.size && !restMap.size) return;
5232
-
5233
- const cache = new Map(); // key(node) -> ListTerm
5234
- const visiting = new Set(); // cycle guard
5235
-
5236
- function buildListForKey(k) {
5237
- if (cache.has(k)) return cache.get(k);
5238
- if (visiting.has(k)) return null; // cycle => not a well-formed list
5239
- visiting.add(k);
5240
-
5241
- // rdf:nil => ()
5242
- if (k === 'I:' + RDF_NIL) {
5243
- const empty = new ListTerm([]);
5244
- cache.set(k, empty);
5245
- visiting.delete(k);
5246
- return empty;
5247
- }
5248
-
5249
- const head = firstMap.get(k);
5250
- const tail = restMap.get(k);
5251
- if (head === undefined || tail === undefined) {
5252
- visiting.delete(k);
5253
- return null; // not a full cons cell
5254
- }
5255
-
5256
- const headTerm = rewriteTerm(head);
5257
-
5258
- let tailListElems = null;
5259
- if (tail instanceof Iri && tail.value === RDF_NIL) {
5260
- tailListElems = [];
5261
- } else {
5262
- const tk = nodeKey(tail);
5263
- if (!tk) {
5264
- visiting.delete(k);
5265
- return null;
5266
- }
5267
- const tailList = buildListForKey(tk);
5268
- if (!tailList) {
5269
- visiting.delete(k);
5270
- return null;
5271
- }
5272
- tailListElems = tailList.elems;
5273
- }
5274
-
5275
- const out = new ListTerm([headTerm, ...tailListElems]);
5276
- cache.set(k, out);
5277
- visiting.delete(k);
5278
- return out;
5279
- }
5280
-
5281
- function rewriteTerm(t) {
5282
- // Replace list nodes (Blank/Iri) by their constructed ListTerm when possible
5283
- const k = nodeKey(t);
5284
- if (k) {
5285
- const built = buildListForKey(k);
5286
- if (built) return built;
5287
- // Also rewrite rdf:nil even if not otherwise referenced
5288
- if (t instanceof Iri && t.value === RDF_NIL) return new ListTerm([]);
5289
- return t;
5290
- }
5291
- if (t instanceof ListTerm) {
5292
- let changed = false;
5293
- const elems = t.elems.map((e) => {
5294
- const r = rewriteTerm(e);
5295
- if (r !== e) changed = true;
5296
- return r;
5297
- });
5298
- return changed ? new ListTerm(elems) : t;
5299
- }
5300
- if (t instanceof OpenListTerm) {
5301
- let changed = false;
5302
- const prefix = t.prefix.map((e) => {
5303
- const r = rewriteTerm(e);
5304
- if (r !== e) changed = true;
5305
- return r;
5306
- });
5307
- return changed ? new OpenListTerm(prefix, t.tailVar) : t;
5308
- }
5309
- if (t instanceof FormulaTerm) {
5310
- for (const tr of t.triples) rewriteTriple(tr);
5311
- return t;
5312
- }
5313
- return t;
5314
- }
5315
-
5316
- function rewriteTriple(tr) {
5317
- tr.s = rewriteTerm(tr.s);
5318
- tr.p = rewriteTerm(tr.p);
5319
- tr.o = rewriteTerm(tr.o);
5320
- }
5321
-
5322
- // Pre-build all reachable list heads
5323
- for (const k of firstMap.keys()) buildListForKey(k);
5324
-
5325
- // Rewrite input triples + rules in-place
5326
- for (const tr of triples) rewriteTriple(tr);
5327
- for (const r of forwardRules) {
5328
- for (const tr of r.premise) rewriteTriple(tr);
5329
- for (const tr of r.conclusion) rewriteTriple(tr);
5330
- }
5331
- for (const r of backwardRules) {
5332
- for (const tr of r.premise) rewriteTriple(tr);
5333
- for (const tr of r.conclusion) rewriteTriple(tr);
5334
- }
5335
- }
5336
-
5337
- function localIsoDateTimeString(d) {
5338
- function pad(n, width = 2) {
5339
- return String(n).padStart(width, '0');
5340
- }
5341
- const year = d.getFullYear();
5342
- const month = d.getMonth() + 1;
5343
- const day = d.getDate();
5344
- const hour = d.getHours();
5345
- const min = d.getMinutes();
5346
- const sec = d.getSeconds();
5347
- const ms = d.getMilliseconds();
5348
- const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
5349
- const sign = offsetMin >= 0 ? '+' : '-';
5350
- const abs = Math.abs(offsetMin);
5351
- const oh = Math.floor(abs / 60);
5352
- const om = abs % 60;
5353
- const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
5354
- return (
5355
- pad(year, 4) +
5356
- '-' +
5357
- pad(month) +
5358
- '-' +
5359
- pad(day) +
5360
- 'T' +
5361
- pad(hour) +
5362
- ':' +
5363
- pad(min) +
5364
- ':' +
5365
- pad(sec) +
5366
- msPart +
5367
- sign +
5368
- pad(oh) +
5369
- ':' +
5370
- pad(om)
5371
- );
5372
- }
5373
-
5374
- // ============================================================================
5353
+ // ===========================================================================
5375
5354
  // CLI entry point
5376
- // ============================================================================
5355
+ // ===========================================================================
5377
5356
  function main() {
5378
5357
  // Drop "node" and script name; keep only user-provided args
5379
5358
  const argv = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.6.17",
3
+ "version": "1.6.19",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [