eyeling 1.5.32 → 1.5.34

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.
@@ -1,5 +1,6 @@
1
1
  @prefix : <http://example.org/math-tests#> .
2
2
  @prefix math: <http://www.w3.org/2000/10/swap/math#> .
3
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
3
4
 
4
5
  # ----------------------------------------------------------------------
5
6
  # Proof for derived triple:
@@ -3431,16 +3432,16 @@
3431
3432
  # Proof for derived triple:
3432
3433
  # :test-rounded-1 a :MathBuiltinTest .
3433
3434
  # It holds because the following instance of the rule body is provable:
3434
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3435
+ # "3.3"^^xsd:double math:rounded 3 .
3435
3436
  # 3 math:equalTo 3 .
3436
3437
  # via the schematic forward rule:
3437
3438
  # {
3438
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3439
+ # "3.3"^^xsd:double math:rounded ?r .
3439
3440
  # ?r math:equalTo 3 .
3440
3441
  # } => {
3441
3442
  # :test-rounded-1 a :MathBuiltinTest .
3442
3443
  # :test-rounded-1 :builtin math:rounded .
3443
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3444
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3444
3445
  # :test-rounded-1 :expected 3 .
3445
3446
  # :test-rounded-1 :actual ?r .
3446
3447
  # :test-rounded-1 :status :pass .
@@ -3456,16 +3457,16 @@
3456
3457
  # Proof for derived triple:
3457
3458
  # :test-rounded-1 :builtin math:rounded .
3458
3459
  # It holds because the following instance of the rule body is provable:
3459
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3460
+ # "3.3"^^xsd:double math:rounded 3 .
3460
3461
  # 3 math:equalTo 3 .
3461
3462
  # via the schematic forward rule:
3462
3463
  # {
3463
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3464
+ # "3.3"^^xsd:double math:rounded ?r .
3464
3465
  # ?r math:equalTo 3 .
3465
3466
  # } => {
3466
3467
  # :test-rounded-1 a :MathBuiltinTest .
3467
3468
  # :test-rounded-1 :builtin math:rounded .
3468
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3469
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3469
3470
  # :test-rounded-1 :expected 3 .
3470
3471
  # :test-rounded-1 :actual ?r .
3471
3472
  # :test-rounded-1 :status :pass .
@@ -3479,18 +3480,18 @@
3479
3480
 
3480
3481
  # ----------------------------------------------------------------------
3481
3482
  # Proof for derived triple:
3482
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3483
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3483
3484
  # It holds because the following instance of the rule body is provable:
3484
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3485
+ # "3.3"^^xsd:double math:rounded 3 .
3485
3486
  # 3 math:equalTo 3 .
3486
3487
  # via the schematic forward rule:
3487
3488
  # {
3488
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3489
+ # "3.3"^^xsd:double math:rounded ?r .
3489
3490
  # ?r math:equalTo 3 .
3490
3491
  # } => {
3491
3492
  # :test-rounded-1 a :MathBuiltinTest .
3492
3493
  # :test-rounded-1 :builtin math:rounded .
3493
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3494
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3494
3495
  # :test-rounded-1 :expected 3 .
3495
3496
  # :test-rounded-1 :actual ?r .
3496
3497
  # :test-rounded-1 :status :pass .
@@ -3500,22 +3501,22 @@
3500
3501
  # Therefore the derived triple above is entailed by the rules and facts.
3501
3502
  # ----------------------------------------------------------------------
3502
3503
 
3503
- :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3504
+ :test-rounded-1 :input "3.3"^^xsd:double .
3504
3505
 
3505
3506
  # ----------------------------------------------------------------------
3506
3507
  # Proof for derived triple:
3507
3508
  # :test-rounded-1 :expected 3 .
3508
3509
  # It holds because the following instance of the rule body is provable:
3509
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3510
+ # "3.3"^^xsd:double math:rounded 3 .
3510
3511
  # 3 math:equalTo 3 .
3511
3512
  # via the schematic forward rule:
3512
3513
  # {
3513
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3514
+ # "3.3"^^xsd:double math:rounded ?r .
3514
3515
  # ?r math:equalTo 3 .
3515
3516
  # } => {
3516
3517
  # :test-rounded-1 a :MathBuiltinTest .
3517
3518
  # :test-rounded-1 :builtin math:rounded .
3518
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3519
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3519
3520
  # :test-rounded-1 :expected 3 .
3520
3521
  # :test-rounded-1 :actual ?r .
3521
3522
  # :test-rounded-1 :status :pass .
@@ -3531,16 +3532,16 @@
3531
3532
  # Proof for derived triple:
3532
3533
  # :test-rounded-1 :actual 3 .
3533
3534
  # It holds because the following instance of the rule body is provable:
3534
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3535
+ # "3.3"^^xsd:double math:rounded 3 .
3535
3536
  # 3 math:equalTo 3 .
3536
3537
  # via the schematic forward rule:
3537
3538
  # {
3538
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3539
+ # "3.3"^^xsd:double math:rounded ?r .
3539
3540
  # ?r math:equalTo 3 .
3540
3541
  # } => {
3541
3542
  # :test-rounded-1 a :MathBuiltinTest .
3542
3543
  # :test-rounded-1 :builtin math:rounded .
3543
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3544
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3544
3545
  # :test-rounded-1 :expected 3 .
3545
3546
  # :test-rounded-1 :actual ?r .
3546
3547
  # :test-rounded-1 :status :pass .
@@ -3556,16 +3557,16 @@
3556
3557
  # Proof for derived triple:
3557
3558
  # :test-rounded-1 :status :pass .
3558
3559
  # It holds because the following instance of the rule body is provable:
3559
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded 3 .
3560
+ # "3.3"^^xsd:double math:rounded 3 .
3560
3561
  # 3 math:equalTo 3 .
3561
3562
  # via the schematic forward rule:
3562
3563
  # {
3563
- # "3.3"^^<http://www.w3.org/2001/XMLSchema#double> math:rounded ?r .
3564
+ # "3.3"^^xsd:double math:rounded ?r .
3564
3565
  # ?r math:equalTo 3 .
3565
3566
  # } => {
3566
3567
  # :test-rounded-1 a :MathBuiltinTest .
3567
3568
  # :test-rounded-1 :builtin math:rounded .
3568
- # :test-rounded-1 :input "3.3"^^<http://www.w3.org/2001/XMLSchema#double> .
3569
+ # :test-rounded-1 :input "3.3"^^xsd:double .
3569
3570
  # :test-rounded-1 :expected 3 .
3570
3571
  # :test-rounded-1 :actual ?r .
3571
3572
  # :test-rounded-1 :status :pass .
package/eyeling.js CHANGED
@@ -34,6 +34,28 @@ const LIST_NS = "http://www.w3.org/2000/10/swap/list#";
34
34
  const LOG_NS = "http://www.w3.org/2000/10/swap/log#";
35
35
  const STRING_NS = "http://www.w3.org/2000/10/swap/string#";
36
36
  const SKOLEM_NS = "https://eyereasoner.github.io/.well-known/genid/";
37
+ const RDF_JSON_DT = RDF_NS + "JSON";
38
+
39
+ function isRdfJsonDatatype(dt) {
40
+ // dt comes from literalParts() and may be expanded or prefixed depending on parsing/printing.
41
+ return dt === null || dt === RDF_JSON_DT || dt === "rdf:JSON";
42
+ }
43
+
44
+ function termToJsonText(t) {
45
+ if (!(t instanceof Literal)) return null;
46
+ const [lex, dt] = literalParts(t.value);
47
+ if (!isRdfJsonDatatype(dt)) return null;
48
+ // decode escapes for short literals; long literals are taken verbatim
49
+ return termToJsStringDecoded(t);
50
+ }
51
+
52
+ function makeRdfJsonLiteral(jsonText) {
53
+ // Prefer a readable long literal when safe; fall back to short if needed.
54
+ if (!jsonText.includes('"""')) {
55
+ return new Literal('"""' + jsonText + '"""^^<' + RDF_JSON_DT + '>');
56
+ }
57
+ return new Literal(JSON.stringify(jsonText) + '^^<' + RDF_JSON_DT + '>');
58
+ }
37
59
 
38
60
  // For a single reasoning run, this maps a canonical representation
39
61
  // of the subject term in log:skolem to a Skolem IRI.
@@ -552,6 +574,9 @@ function collectIrisInTerm(t) {
552
574
  const out = [];
553
575
  if (t instanceof Iri) {
554
576
  out.push(t.value);
577
+ } else if (t instanceof Literal) {
578
+ const [_lex, dt] = literalParts(t.value);
579
+ if (dt) out.push(dt); // so rdf/xsd prefixes are emitted when only used in ^^...
555
580
  } else if (t instanceof ListTerm) {
556
581
  for (const x of t.elems) out.push(...collectIrisInTerm(x));
557
582
  } else if (t instanceof OpenListTerm) {
@@ -1842,91 +1867,6 @@ function termToJsStringDecoded(t) {
1842
1867
  return stripQuotes(lex);
1843
1868
  }
1844
1869
 
1845
- function _jsonPointerUnescape(seg) {
1846
- // RFC6901: ~1 -> '/', ~0 -> '~'
1847
- // Any other '~' escape is invalid.
1848
- let out = "";
1849
- for (let i = 0; i < seg.length; i++) {
1850
- const c = seg[i];
1851
- if (c !== "~") { out += c; continue; }
1852
- if (i + 1 >= seg.length) return null;
1853
- const n = seg[i + 1];
1854
- if (n === "0") out += "~";
1855
- else if (n === "1") out += "/";
1856
- else return null;
1857
- i++;
1858
- }
1859
- return out;
1860
- }
1861
-
1862
- function _jsonToTerm(v) {
1863
- if (v === null) return makeStringLiteral("null");
1864
- if (typeof v === "string") return makeStringLiteral(v);
1865
- if (typeof v === "number") return new Literal(String(v));
1866
- if (typeof v === "boolean") return new Literal(v ? "true" : "false");
1867
- if (Array.isArray(v)) return new ListTerm(v.map(_jsonToTerm));
1868
- if (typeof v === "object") return makeStringLiteral(JSON.stringify(v));
1869
- return null;
1870
- }
1871
-
1872
- function _jsonPointerLookup(jsonText, pointer) {
1873
- // Support URI fragment form "#/a/b" (percent-decoded) as well.
1874
- let ptr = pointer;
1875
- if (ptr.startsWith("#")) {
1876
- try { ptr = decodeURIComponent(ptr.slice(1)); } catch (e) { return null; }
1877
- }
1878
-
1879
- // Cache per JSON document
1880
- let entry = jsonPointerCache.get(jsonText);
1881
- if (!entry) {
1882
- let parsed = null;
1883
- try { parsed = JSON.parse(jsonText); } catch (e) { parsed = null; }
1884
- entry = { parsed, ptrCache: new Map() };
1885
- jsonPointerCache.set(jsonText, entry);
1886
- }
1887
- if (entry.parsed === null) return null;
1888
-
1889
- // Cache per pointer within this doc
1890
- if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
1891
-
1892
- let cur = entry.parsed;
1893
-
1894
- if (ptr === "") {
1895
- const t = _jsonToTerm(cur);
1896
- entry.ptrCache.set(ptr, t);
1897
- return t;
1898
- }
1899
- if (!ptr.startsWith("/")) { entry.ptrCache.set(ptr, null); return null; }
1900
-
1901
- const parts = ptr.split("/").slice(1);
1902
- for (const raw of parts) {
1903
- const seg = _jsonPointerUnescape(raw);
1904
- if (seg === null) { entry.ptrCache.set(ptr, null); return null; }
1905
-
1906
- if (Array.isArray(cur)) {
1907
- // JSON Pointer uses array indices as decimal strings
1908
- if (!/^(0|[1-9]\d*)$/.test(seg)) { entry.ptrCache.set(ptr, null); return null; }
1909
- const idx = Number(seg);
1910
- if (!Number.isFinite(idx) || idx < 0 || idx >= cur.length) { entry.ptrCache.set(ptr, null); return null; }
1911
- cur = cur[idx];
1912
- continue;
1913
- }
1914
-
1915
- if (cur !== null && typeof cur === "object") {
1916
- if (!Object.prototype.hasOwnProperty.call(cur, seg)) { entry.ptrCache.set(ptr, null); return null; }
1917
- cur = cur[seg];
1918
- continue;
1919
- }
1920
-
1921
- entry.ptrCache.set(ptr, null);
1922
- return null;
1923
- }
1924
-
1925
- const out = _jsonToTerm(cur);
1926
- entry.ptrCache.set(ptr, out);
1927
- return out;
1928
- }
1929
-
1930
1870
  function jsonPointerUnescape(seg) {
1931
1871
  // RFC6901: ~1 -> '/', ~0 -> '~'
1932
1872
  let out = "";
@@ -1951,10 +1891,7 @@ function jsonToTerm(v) {
1951
1891
  if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
1952
1892
 
1953
1893
  if (v && typeof v === "object") {
1954
- // IMPORTANT: long literal so it can be parsed again via termToJsString()
1955
- // without needing escape decoding.
1956
- const raw = JSON.stringify(v);
1957
- return new Literal('"""' + raw + '"""');
1894
+ return makeRdfJsonLiteral(JSON.stringify(v));
1958
1895
  }
1959
1896
  return null;
1960
1897
  }
@@ -3566,8 +3503,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3566
3503
  // Schema: ( $jsonText $pointer ) string:jsonPointer $value
3567
3504
  if (g.p instanceof Iri && g.p.value === STRING_NS + "jsonPointer") {
3568
3505
  if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
3569
- const jsonText = termToJsString(g.s.elems[0]);
3570
- const ptr = termToJsString(g.s.elems[1]);
3506
+
3507
+ const jsonText = termToJsonText(g.s.elems[0]); // <-- changed
3508
+ const ptr = termToJsStringDecoded(g.s.elems[1]);
3571
3509
  if (jsonText === null || ptr === null) return [];
3572
3510
 
3573
3511
  const valTerm = jsonPointerLookup(jsonText, ptr);
@@ -3817,28 +3755,28 @@ function listHasTriple(list, tr) {
3817
3755
  //
3818
3756
  // This is semantics-preserving for the ongoing proof state.
3819
3757
 
3820
- function _gcCollectVarsInTerm(t, out) {
3758
+ function gcCollectVarsInTerm(t, out) {
3821
3759
  if (t instanceof Var) { out.add(t.name); return; }
3822
- if (t instanceof ListTerm) { for (const e of t.elems) _gcCollectVarsInTerm(e, out); return; }
3760
+ if (t instanceof ListTerm) { for (const e of t.elems) gcCollectVarsInTerm(e, out); return; }
3823
3761
  if (t instanceof OpenListTerm) {
3824
- for (const e of t.prefix) _gcCollectVarsInTerm(e, out);
3762
+ for (const e of t.prefix) gcCollectVarsInTerm(e, out);
3825
3763
  out.add(t.tailVar);
3826
3764
  return;
3827
3765
  }
3828
- if (t instanceof FormulaTerm) { for (const tr of t.triples) _gcCollectVarsInTriple(tr, out); return; }
3766
+ if (t instanceof FormulaTerm) { for (const tr of t.triples) gcCollectVarsInTriple(tr, out); return; }
3829
3767
  }
3830
3768
 
3831
- function _gcCollectVarsInTriple(tr, out) {
3832
- _gcCollectVarsInTerm(tr.s, out);
3833
- _gcCollectVarsInTerm(tr.p, out);
3834
- _gcCollectVarsInTerm(tr.o, out);
3769
+ function gcCollectVarsInTriple(tr, out) {
3770
+ gcCollectVarsInTerm(tr.s, out);
3771
+ gcCollectVarsInTerm(tr.p, out);
3772
+ gcCollectVarsInTerm(tr.o, out);
3835
3773
  }
3836
3774
 
3837
- function _gcCollectVarsInGoals(goals, out) {
3838
- for (const g of goals) _gcCollectVarsInTriple(g, out);
3775
+ function gcCollectVarsInGoals(goals, out) {
3776
+ for (const g of goals) gcCollectVarsInTriple(g, out);
3839
3777
  }
3840
3778
 
3841
- function _substSizeOver(subst, limit) {
3779
+ function substSizeOver(subst, limit) {
3842
3780
  let c = 0;
3843
3781
  for (const _k in subst) {
3844
3782
  if (++c > limit) return true;
@@ -3846,9 +3784,9 @@ function _substSizeOver(subst, limit) {
3846
3784
  return false;
3847
3785
  }
3848
3786
 
3849
- function _gcCompactForGoals(subst, goals, answerVars) {
3787
+ function gcCompactForGoals(subst, goals, answerVars) {
3850
3788
  const keep = new Set(answerVars);
3851
- _gcCollectVarsInGoals(goals, keep);
3789
+ gcCollectVarsInGoals(goals, keep);
3852
3790
 
3853
3791
  const expanded = new Set();
3854
3792
  const queue = Array.from(keep);
@@ -3862,7 +3800,7 @@ function _gcCompactForGoals(subst, goals, answerVars) {
3862
3800
  if (bound === undefined) continue;
3863
3801
 
3864
3802
  const before = keep.size;
3865
- _gcCollectVarsInTerm(bound, keep);
3803
+ gcCollectVarsInTerm(bound, keep);
3866
3804
  if (keep.size !== before) {
3867
3805
  for (const nv of keep) {
3868
3806
  if (!expanded.has(nv)) queue.push(nv);
@@ -3877,12 +3815,12 @@ function _gcCompactForGoals(subst, goals, answerVars) {
3877
3815
  return out;
3878
3816
  }
3879
3817
 
3880
- function _maybeCompactSubst(subst, goals, answerVars, depth) {
3818
+ function maybeCompactSubst(subst, goals, answerVars, depth) {
3881
3819
  // Keep the fast path fast.
3882
3820
  // Only compact when the substitution is clearly getting large, or
3883
3821
  // we are in a deep chain (where the quadratic behavior shows up).
3884
- if (depth < 128 && !_substSizeOver(subst, 256)) return subst;
3885
- return _gcCompactForGoals(subst, goals, answerVars);
3822
+ if (depth < 128 && !substSizeOver(subst, 256)) return subst;
3823
+ return gcCompactForGoals(subst, goals, answerVars);
3886
3824
  }
3887
3825
 
3888
3826
 
@@ -3898,9 +3836,9 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
3898
3836
 
3899
3837
  // Variables from the original goal list (needed by the caller to instantiate conclusions)
3900
3838
  const answerVars = new Set();
3901
- _gcCollectVarsInGoals(initialGoals, answerVars);
3839
+ gcCollectVarsInGoals(initialGoals, answerVars);
3902
3840
  if (!initialGoals.length) {
3903
- results.push(_gcCompactForGoals(initialSubst, [], answerVars));
3841
+ results.push(gcCompactForGoals(initialSubst, [], answerVars));
3904
3842
  return results;
3905
3843
  }
3906
3844
 
@@ -3912,7 +3850,7 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
3912
3850
  const state = stack.pop();
3913
3851
 
3914
3852
  if (!state.goals.length) {
3915
- results.push(_gcCompactForGoals(state.subst, [], answerVars));
3853
+ results.push(gcCompactForGoals(state.subst, [], answerVars));
3916
3854
  continue;
3917
3855
  }
3918
3856
 
@@ -3928,9 +3866,9 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
3928
3866
  if (composed === null) continue;
3929
3867
 
3930
3868
  if (!restGoals.length) {
3931
- results.push(_gcCompactForGoals(composed, [], answerVars));
3869
+ results.push(gcCompactForGoals(composed, [], answerVars));
3932
3870
  } else {
3933
- const nextSubst = _maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3871
+ const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3934
3872
  stack.push({
3935
3873
  goals: restGoals,
3936
3874
  subst: nextSubst,
@@ -3957,9 +3895,9 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
3957
3895
  if (composed === null) continue;
3958
3896
 
3959
3897
  if (!restGoals.length) {
3960
- results.push(_gcCompactForGoals(composed, [], answerVars));
3898
+ results.push(gcCompactForGoals(composed, [], answerVars));
3961
3899
  } else {
3962
- const nextSubst = _maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3900
+ const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3963
3901
  stack.push({
3964
3902
  goals: restGoals,
3965
3903
  subst: nextSubst,
@@ -3978,9 +3916,9 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
3978
3916
  if (composed === null) continue;
3979
3917
 
3980
3918
  if (!restGoals.length) {
3981
- results.push(_gcCompactForGoals(composed, [], answerVars));
3919
+ results.push(gcCompactForGoals(composed, [], answerVars));
3982
3920
  } else {
3983
- const nextSubst = _maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3921
+ const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
3984
3922
  stack.push({
3985
3923
  goals: restGoals,
3986
3924
  subst: nextSubst,
@@ -4013,7 +3951,7 @@ function proveGoals( goals, subst, facts, backRules, depth, visited, varGen ) {
4013
3951
  if (composed === null) continue;
4014
3952
 
4015
3953
  const newGoals = body.concat(restGoals);
4016
- const nextSubst = _maybeCompactSubst(composed, newGoals, answerVars, state.depth + 1);
3954
+ const nextSubst = maybeCompactSubst(composed, newGoals, answerVars, state.depth + 1);
4017
3955
  stack.push({
4018
3956
  goals: newGoals,
4019
3957
  subst: nextSubst,
@@ -4174,7 +4112,13 @@ function termToN3(t, pref) {
4174
4112
  if (i.startsWith("_:")) return i;
4175
4113
  return `<${i}>`;
4176
4114
  }
4177
- if (t instanceof Literal) return t.value;
4115
+ if (t instanceof Literal) {
4116
+ const [lex, dt] = literalParts(t.value);
4117
+ if (!dt) return t.value; // keep numbers, booleans, lang-tagged strings, etc.
4118
+ const qdt = pref.shrinkIri(dt);
4119
+ if (qdt !== null) return `${lex}^^${qdt}`; // e.g. ^^rdf:JSON
4120
+ return `${lex}^^<${dt}>`; // fallback
4121
+ }
4178
4122
  if (t instanceof Var) return `?${t.name}`;
4179
4123
  if (t instanceof Blank) return t.label;
4180
4124
  if (t instanceof ListTerm) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.5.32",
3
+ "version": "1.5.34",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [