eyeling 1.5.31 → 1.5.33
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/README.md +1 -1
- package/examples/json-pointer.n3 +70 -0
- package/examples/json-reconcile-vat.n3 +356 -0
- package/examples/output/age.n3 +2 -2
- package/examples/output/json-pointer.n3 +800 -0
- package/examples/output/json-reconcile-vat.n3 +33530 -0
- package/examples/output/math-builtins-tests.n3 +21 -20
- package/eyeling.js +237 -1
- package/package.json +1 -1
|
@@ -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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
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,11 +34,36 @@ 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.
|
|
40
62
|
const skolemCache = new Map();
|
|
41
63
|
|
|
64
|
+
// Cache for string:jsonPointer: jsonText -> { parsed: any|null, ptrCache: Map<string, Term|null> }
|
|
65
|
+
const jsonPointerCache = new Map();
|
|
66
|
+
|
|
42
67
|
// Controls whether human-readable proof comments are printed.
|
|
43
68
|
let proofCommentsEnabled = true;
|
|
44
69
|
|
|
@@ -549,6 +574,9 @@ function collectIrisInTerm(t) {
|
|
|
549
574
|
const out = [];
|
|
550
575
|
if (t instanceof Iri) {
|
|
551
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 ^^...
|
|
552
580
|
} else if (t instanceof ListTerm) {
|
|
553
581
|
for (const x of t.elems) out.push(...collectIrisInTerm(x));
|
|
554
582
|
} else if (t instanceof OpenListTerm) {
|
|
@@ -1819,6 +1847,192 @@ function makeStringLiteral(str) {
|
|
|
1819
1847
|
return new Literal(JSON.stringify(str));
|
|
1820
1848
|
}
|
|
1821
1849
|
|
|
1850
|
+
function termToJsStringDecoded(t) {
|
|
1851
|
+
// Like termToJsString, but for short literals it *also* interprets escapes
|
|
1852
|
+
// (\" \n \uXXXX …) by attempting JSON.parse on the quoted lexical form.
|
|
1853
|
+
if (!(t instanceof Literal)) return null;
|
|
1854
|
+
const [lex, _dt] = literalParts(t.value);
|
|
1855
|
+
|
|
1856
|
+
// Long strings: """ ... """ are taken verbatim.
|
|
1857
|
+
if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
|
|
1858
|
+
return lex.slice(3, -3);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// Short strings: try to decode escapes (this makes "{\"a\":1}" usable too).
|
|
1862
|
+
if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
|
|
1863
|
+
try { return JSON.parse(lex); } catch (e) { /* fall through */ }
|
|
1864
|
+
return stripQuotes(lex);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
return stripQuotes(lex);
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
function _jsonPointerUnescape(seg) {
|
|
1871
|
+
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
1872
|
+
// Any other '~' escape is invalid.
|
|
1873
|
+
let out = "";
|
|
1874
|
+
for (let i = 0; i < seg.length; i++) {
|
|
1875
|
+
const c = seg[i];
|
|
1876
|
+
if (c !== "~") { out += c; continue; }
|
|
1877
|
+
if (i + 1 >= seg.length) return null;
|
|
1878
|
+
const n = seg[i + 1];
|
|
1879
|
+
if (n === "0") out += "~";
|
|
1880
|
+
else if (n === "1") out += "/";
|
|
1881
|
+
else return null;
|
|
1882
|
+
i++;
|
|
1883
|
+
}
|
|
1884
|
+
return out;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
function _jsonToTerm(v) {
|
|
1888
|
+
if (v === null) return makeStringLiteral("null");
|
|
1889
|
+
if (typeof v === "string") return makeStringLiteral(v);
|
|
1890
|
+
if (typeof v === "number") return new Literal(String(v));
|
|
1891
|
+
if (typeof v === "boolean") return new Literal(v ? "true" : "false");
|
|
1892
|
+
if (Array.isArray(v)) return new ListTerm(v.map(_jsonToTerm));
|
|
1893
|
+
if (typeof v === "object") return makeStringLiteral(JSON.stringify(v));
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
function _jsonPointerLookup(jsonText, pointer) {
|
|
1898
|
+
// Support URI fragment form "#/a/b" (percent-decoded) as well.
|
|
1899
|
+
let ptr = pointer;
|
|
1900
|
+
if (ptr.startsWith("#")) {
|
|
1901
|
+
try { ptr = decodeURIComponent(ptr.slice(1)); } catch (e) { return null; }
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
// Cache per JSON document
|
|
1905
|
+
let entry = jsonPointerCache.get(jsonText);
|
|
1906
|
+
if (!entry) {
|
|
1907
|
+
let parsed = null;
|
|
1908
|
+
try { parsed = JSON.parse(jsonText); } catch (e) { parsed = null; }
|
|
1909
|
+
entry = { parsed, ptrCache: new Map() };
|
|
1910
|
+
jsonPointerCache.set(jsonText, entry);
|
|
1911
|
+
}
|
|
1912
|
+
if (entry.parsed === null) return null;
|
|
1913
|
+
|
|
1914
|
+
// Cache per pointer within this doc
|
|
1915
|
+
if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
|
|
1916
|
+
|
|
1917
|
+
let cur = entry.parsed;
|
|
1918
|
+
|
|
1919
|
+
if (ptr === "") {
|
|
1920
|
+
const t = _jsonToTerm(cur);
|
|
1921
|
+
entry.ptrCache.set(ptr, t);
|
|
1922
|
+
return t;
|
|
1923
|
+
}
|
|
1924
|
+
if (!ptr.startsWith("/")) { entry.ptrCache.set(ptr, null); return null; }
|
|
1925
|
+
|
|
1926
|
+
const parts = ptr.split("/").slice(1);
|
|
1927
|
+
for (const raw of parts) {
|
|
1928
|
+
const seg = _jsonPointerUnescape(raw);
|
|
1929
|
+
if (seg === null) { entry.ptrCache.set(ptr, null); return null; }
|
|
1930
|
+
|
|
1931
|
+
if (Array.isArray(cur)) {
|
|
1932
|
+
// JSON Pointer uses array indices as decimal strings
|
|
1933
|
+
if (!/^(0|[1-9]\d*)$/.test(seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
1934
|
+
const idx = Number(seg);
|
|
1935
|
+
if (!Number.isFinite(idx) || idx < 0 || idx >= cur.length) { entry.ptrCache.set(ptr, null); return null; }
|
|
1936
|
+
cur = cur[idx];
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
if (cur !== null && typeof cur === "object") {
|
|
1941
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
1942
|
+
cur = cur[seg];
|
|
1943
|
+
continue;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
entry.ptrCache.set(ptr, null);
|
|
1947
|
+
return null;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
const out = _jsonToTerm(cur);
|
|
1951
|
+
entry.ptrCache.set(ptr, out);
|
|
1952
|
+
return out;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
function jsonPointerUnescape(seg) {
|
|
1956
|
+
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
1957
|
+
let out = "";
|
|
1958
|
+
for (let i = 0; i < seg.length; i++) {
|
|
1959
|
+
const c = seg[i];
|
|
1960
|
+
if (c !== "~") { out += c; continue; }
|
|
1961
|
+
if (i + 1 >= seg.length) return null;
|
|
1962
|
+
const n = seg[i + 1];
|
|
1963
|
+
if (n === "0") out += "~";
|
|
1964
|
+
else if (n === "1") out += "/";
|
|
1965
|
+
else return null;
|
|
1966
|
+
i++;
|
|
1967
|
+
}
|
|
1968
|
+
return out;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
function jsonToTerm(v) {
|
|
1972
|
+
if (v === null) return makeStringLiteral("null");
|
|
1973
|
+
if (typeof v === "string") return makeStringLiteral(v);
|
|
1974
|
+
if (typeof v === "number") return new Literal(String(v));
|
|
1975
|
+
if (typeof v === "boolean") return new Literal(v ? "true" : "false");
|
|
1976
|
+
if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
|
|
1977
|
+
|
|
1978
|
+
if (v && typeof v === "object") {
|
|
1979
|
+
return makeRdfJsonLiteral(JSON.stringify(v));
|
|
1980
|
+
}
|
|
1981
|
+
return null;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
function jsonPointerLookup(jsonText, pointer) {
|
|
1985
|
+
let ptr = pointer;
|
|
1986
|
+
|
|
1987
|
+
// Support URI fragment form "#/a/b"
|
|
1988
|
+
if (ptr.startsWith("#")) {
|
|
1989
|
+
try { ptr = decodeURIComponent(ptr.slice(1)); } catch { return null; }
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
let entry = jsonPointerCache.get(jsonText);
|
|
1993
|
+
if (!entry) {
|
|
1994
|
+
let parsed = null;
|
|
1995
|
+
try { parsed = JSON.parse(jsonText); } catch { parsed = null; }
|
|
1996
|
+
entry = { parsed, ptrCache: new Map() };
|
|
1997
|
+
jsonPointerCache.set(jsonText, entry);
|
|
1998
|
+
}
|
|
1999
|
+
if (entry.parsed === null) return null;
|
|
2000
|
+
|
|
2001
|
+
if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
|
|
2002
|
+
|
|
2003
|
+
let cur = entry.parsed;
|
|
2004
|
+
|
|
2005
|
+
if (ptr === "") {
|
|
2006
|
+
const t = jsonToTerm(cur);
|
|
2007
|
+
entry.ptrCache.set(ptr, t);
|
|
2008
|
+
return t;
|
|
2009
|
+
}
|
|
2010
|
+
if (!ptr.startsWith("/")) { entry.ptrCache.set(ptr, null); return null; }
|
|
2011
|
+
|
|
2012
|
+
const parts = ptr.split("/").slice(1);
|
|
2013
|
+
for (const raw of parts) {
|
|
2014
|
+
const seg = jsonPointerUnescape(raw);
|
|
2015
|
+
if (seg === null) { entry.ptrCache.set(ptr, null); return null; }
|
|
2016
|
+
|
|
2017
|
+
if (Array.isArray(cur)) {
|
|
2018
|
+
if (!/^(0|[1-9]\d*)$/.test(seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
2019
|
+
const idx = Number(seg);
|
|
2020
|
+
if (idx < 0 || idx >= cur.length) { entry.ptrCache.set(ptr, null); return null; }
|
|
2021
|
+
cur = cur[idx];
|
|
2022
|
+
} else if (cur !== null && typeof cur === "object") {
|
|
2023
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
2024
|
+
cur = cur[seg];
|
|
2025
|
+
} else {
|
|
2026
|
+
entry.ptrCache.set(ptr, null);
|
|
2027
|
+
return null;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
const out = jsonToTerm(cur);
|
|
2032
|
+
entry.ptrCache.set(ptr, out);
|
|
2033
|
+
return out;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
1822
2036
|
// Tiny subset of sprintf: supports only %s and %%.
|
|
1823
2037
|
// Good enough for most N3 string:format use cases that just splice strings.
|
|
1824
2038
|
function simpleStringFormat(fmt, args) {
|
|
@@ -3370,6 +3584,22 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3370
3584
|
return s2 !== null ? [s2] : [];
|
|
3371
3585
|
}
|
|
3372
3586
|
|
|
3587
|
+
// string:jsonPointer
|
|
3588
|
+
// Schema: ( $jsonText $pointer ) string:jsonPointer $value
|
|
3589
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + "jsonPointer") {
|
|
3590
|
+
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3591
|
+
|
|
3592
|
+
const jsonText = termToJsonText(g.s.elems[0]); // <-- changed
|
|
3593
|
+
const ptr = termToJsStringDecoded(g.s.elems[1]);
|
|
3594
|
+
if (jsonText === null || ptr === null) return [];
|
|
3595
|
+
|
|
3596
|
+
const valTerm = jsonPointerLookup(jsonText, ptr);
|
|
3597
|
+
if (valTerm === null) return [];
|
|
3598
|
+
|
|
3599
|
+
const s2 = unifyTerm(g.o, valTerm, subst);
|
|
3600
|
+
return s2 !== null ? [s2] : [];
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3373
3603
|
// string:greaterThan
|
|
3374
3604
|
if (g.p instanceof Iri && g.p.value === STRING_NS + "greaterThan") {
|
|
3375
3605
|
const sStr = termToJsString(g.s);
|
|
@@ -3967,7 +4197,13 @@ function termToN3(t, pref) {
|
|
|
3967
4197
|
if (i.startsWith("_:")) return i;
|
|
3968
4198
|
return `<${i}>`;
|
|
3969
4199
|
}
|
|
3970
|
-
|
|
4200
|
+
if (t instanceof Literal) {
|
|
4201
|
+
const [lex, dt] = literalParts(t.value);
|
|
4202
|
+
if (!dt) return t.value; // keep numbers, booleans, lang-tagged strings, etc.
|
|
4203
|
+
const qdt = pref.shrinkIri(dt);
|
|
4204
|
+
if (qdt !== null) return `${lex}^^${qdt}`; // e.g. ^^rdf:JSON
|
|
4205
|
+
return `${lex}^^<${dt}>`; // fallback
|
|
4206
|
+
}
|
|
3971
4207
|
if (t instanceof Var) return `?${t.name}`;
|
|
3972
4208
|
if (t instanceof Blank) return t.label;
|
|
3973
4209
|
if (t instanceof ListTerm) {
|