eyeling 1.10.20 → 1.10.21
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/HANDBOOK.md +88 -2
- package/examples/bind-builtins.n3 +11 -0
- package/examples/bind.n3 +7 -0
- package/examples/brussels-brew-club.n3 +119 -0
- package/examples/builtins-string-math.n3 +11 -0
- package/examples/builtins-triple-termtests.n3 +7 -0
- package/examples/family.n3 +10 -0
- package/examples/filter-demorgan.n3 +9 -0
- package/examples/filter-in-notin.n3 +10 -0
- package/examples/filter-nested-or.n3 +10 -0
- package/examples/filter.n3 +8 -0
- package/examples/input/bind-builtins.srl +30 -0
- package/examples/input/bind.srl +12 -0
- package/examples/input/builtins-string-math.srl +38 -0
- package/examples/input/builtins-triple-termtests.srl +27 -0
- package/examples/input/family.srl +12 -0
- package/examples/input/filter-demorgan.srl +15 -0
- package/examples/input/filter-in-notin.srl +15 -0
- package/examples/input/filter-nested-or.srl +15 -0
- package/examples/input/filter.srl +9 -0
- package/examples/input/snaf.srl +6 -0
- package/examples/json-pointer.n3 +75 -0
- package/examples/json-reconcile-vat.n3 +361 -0
- package/examples/output/bind-builtins.n3 +9 -0
- package/examples/output/bind.n3 +3 -0
- package/examples/output/brussels-brew-club.n3 +22 -0
- package/examples/output/builtins-string-math.n3 +0 -0
- package/examples/output/builtins-triple-termtests.n3 +0 -0
- package/examples/output/family.n3 +13 -0
- package/examples/output/filter-demorgan.n3 +3 -0
- package/examples/output/filter-in-notin.n3 +4 -0
- package/examples/output/filter-nested-or.n3 +4 -0
- package/examples/output/filter.n3 +3 -0
- package/examples/output/json-pointer.n3 +13 -0
- package/examples/output/json-reconcile-vat.n3 +226 -0
- package/examples/output/snaf.n3 +3 -0
- package/examples/snaf.n3 +6 -0
- package/eyeling-builtins.ttl +48 -0
- package/eyeling.js +312 -1
- package/lib/engine.js +307 -1
- package/lib/rules.js +5 -0
- package/package.json +1 -1
- package/test/n3gen.test.js +4 -4
- package/test/package.test.js +1 -1
- package/tools/n3gen.js +1883 -6
package/lib/engine.js
CHANGED
|
@@ -129,6 +129,37 @@ function __makeSkolemRunSalt() {
|
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function __randomUuidV4() {
|
|
133
|
+
// Best-effort UUID v4 generator (Node + browsers). Used by log:uuid / log:struuid.
|
|
134
|
+
try {
|
|
135
|
+
if (typeof globalThis !== 'undefined' && globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function') {
|
|
136
|
+
return globalThis.crypto.randomUUID();
|
|
137
|
+
}
|
|
138
|
+
} catch {}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
if (nodeCrypto && typeof nodeCrypto.randomUUID === 'function') return nodeCrypto.randomUUID();
|
|
142
|
+
} catch {}
|
|
143
|
+
|
|
144
|
+
// Fallback: v4 using random bytes (Node) or Math.random
|
|
145
|
+
let bytes = null;
|
|
146
|
+
try {
|
|
147
|
+
if (nodeCrypto && typeof nodeCrypto.randomBytes === 'function') bytes = nodeCrypto.randomBytes(16);
|
|
148
|
+
} catch {}
|
|
149
|
+
if (!bytes) {
|
|
150
|
+
bytes = new Uint8Array(16);
|
|
151
|
+
for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Set version (4) and variant (RFC4122)
|
|
155
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
156
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
157
|
+
|
|
158
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
159
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
132
163
|
function __enterReasoningRun() {
|
|
133
164
|
__skolemRunDepth += 1;
|
|
134
165
|
if (__skolemRunDepth === 1) {
|
|
@@ -175,6 +206,8 @@ const __parseNumCache = new Map(); // lit string -> number|null
|
|
|
175
206
|
const __parseIntCache = new Map(); // lit string -> bigint|null
|
|
176
207
|
const __parseNumericInfoCache = new Map(); // lit string -> info|null
|
|
177
208
|
|
|
209
|
+
// Cache for string:jsonPointer: jsonText -> { parsed: any|null, ptrCache: Map<string, Term|null> }
|
|
210
|
+
const jsonPointerCache = new Map();
|
|
178
211
|
|
|
179
212
|
// -----------------------------------------------------------------------------
|
|
180
213
|
// log:conclusion cache
|
|
@@ -1305,6 +1338,112 @@ function termToJsStringDecoded(t) {
|
|
|
1305
1338
|
return stripQuotes(lex);
|
|
1306
1339
|
}
|
|
1307
1340
|
|
|
1341
|
+
function jsonPointerUnescape(seg) {
|
|
1342
|
+
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
1343
|
+
let out = '';
|
|
1344
|
+
for (let i = 0; i < seg.length; i++) {
|
|
1345
|
+
const c = seg[i];
|
|
1346
|
+
if (c !== '~') {
|
|
1347
|
+
out += c;
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
if (i + 1 >= seg.length) return null;
|
|
1351
|
+
const n = seg[i + 1];
|
|
1352
|
+
if (n === '0') out += '~';
|
|
1353
|
+
else if (n === '1') out += '/';
|
|
1354
|
+
else return null;
|
|
1355
|
+
i++;
|
|
1356
|
+
}
|
|
1357
|
+
return out;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
function jsonToTerm(v) {
|
|
1361
|
+
if (v === null) return makeStringLiteral('null');
|
|
1362
|
+
if (typeof v === 'string') return makeStringLiteral(v);
|
|
1363
|
+
if (typeof v === 'number') return internLiteral(String(v));
|
|
1364
|
+
if (typeof v === 'boolean') return internLiteral(v ? 'true' : 'false');
|
|
1365
|
+
if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
|
|
1366
|
+
|
|
1367
|
+
if (v && typeof v === 'object') {
|
|
1368
|
+
return makeRdfJsonLiteral(JSON.stringify(v));
|
|
1369
|
+
}
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
function jsonPointerLookup(jsonText, pointer) {
|
|
1374
|
+
let ptr = pointer;
|
|
1375
|
+
|
|
1376
|
+
// Support URI fragment form "#/a/b"
|
|
1377
|
+
if (ptr.startsWith('#')) {
|
|
1378
|
+
try {
|
|
1379
|
+
ptr = decodeURIComponent(ptr.slice(1));
|
|
1380
|
+
} catch {
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
let entry = jsonPointerCache.get(jsonText);
|
|
1386
|
+
if (!entry) {
|
|
1387
|
+
let parsed = null;
|
|
1388
|
+
try {
|
|
1389
|
+
parsed = JSON.parse(jsonText);
|
|
1390
|
+
} catch {
|
|
1391
|
+
parsed = null;
|
|
1392
|
+
}
|
|
1393
|
+
entry = { parsed, ptrCache: new Map() };
|
|
1394
|
+
jsonPointerCache.set(jsonText, entry);
|
|
1395
|
+
}
|
|
1396
|
+
if (entry.parsed === null) return null;
|
|
1397
|
+
|
|
1398
|
+
if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
|
|
1399
|
+
|
|
1400
|
+
let cur = entry.parsed;
|
|
1401
|
+
|
|
1402
|
+
if (ptr === '') {
|
|
1403
|
+
const t = jsonToTerm(cur);
|
|
1404
|
+
entry.ptrCache.set(ptr, t);
|
|
1405
|
+
return t;
|
|
1406
|
+
}
|
|
1407
|
+
if (!ptr.startsWith('/')) {
|
|
1408
|
+
entry.ptrCache.set(ptr, null);
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
const parts = ptr.split('/').slice(1);
|
|
1413
|
+
for (const raw of parts) {
|
|
1414
|
+
const seg = jsonPointerUnescape(raw);
|
|
1415
|
+
if (seg === null) {
|
|
1416
|
+
entry.ptrCache.set(ptr, null);
|
|
1417
|
+
return null;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
if (Array.isArray(cur)) {
|
|
1421
|
+
if (!/^(0|[1-9]\d*)$/.test(seg)) {
|
|
1422
|
+
entry.ptrCache.set(ptr, null);
|
|
1423
|
+
return null;
|
|
1424
|
+
}
|
|
1425
|
+
const idx = Number(seg);
|
|
1426
|
+
if (idx < 0 || idx >= cur.length) {
|
|
1427
|
+
entry.ptrCache.set(ptr, null);
|
|
1428
|
+
return null;
|
|
1429
|
+
}
|
|
1430
|
+
cur = cur[idx];
|
|
1431
|
+
} else if (cur !== null && typeof cur === 'object') {
|
|
1432
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) {
|
|
1433
|
+
entry.ptrCache.set(ptr, null);
|
|
1434
|
+
return null;
|
|
1435
|
+
}
|
|
1436
|
+
cur = cur[seg];
|
|
1437
|
+
} else {
|
|
1438
|
+
entry.ptrCache.set(ptr, null);
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
const out = jsonToTerm(cur);
|
|
1444
|
+
entry.ptrCache.set(ptr, out);
|
|
1445
|
+
return out;
|
|
1446
|
+
}
|
|
1308
1447
|
|
|
1309
1448
|
// Tiny subset of sprintf: supports only %s and %%.
|
|
1310
1449
|
// Good enough for most N3 string:format use cases that just splice strings.
|
|
@@ -2423,7 +2562,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
2423
2562
|
? 'sha256'
|
|
2424
2563
|
: pv === CRYPTO_NS + 'sha512'
|
|
2425
2564
|
? 'sha512'
|
|
2426
|
-
:
|
|
2565
|
+
: pv === CRYPTO_NS + 'sha384'
|
|
2566
|
+
? 'sha384'
|
|
2567
|
+
: null;
|
|
2427
2568
|
if (cryptoAlgo) return evalCryptoHashBuiltin(g, subst, cryptoAlgo);
|
|
2428
2569
|
|
|
2429
2570
|
// -----------------------------------------------------------------
|
|
@@ -2916,6 +3057,38 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
2916
3057
|
s2[g.o.name] = lit;
|
|
2917
3058
|
return [s2];
|
|
2918
3059
|
}
|
|
3060
|
+
|
|
3061
|
+
// math:ceiling (Eyeling extension)
|
|
3062
|
+
// Schema: $s+ math:ceiling $o-
|
|
3063
|
+
// Smallest integer >= s (fails on NaN / non-numeric).
|
|
3064
|
+
if (pv === MATH_NS + 'ceiling') {
|
|
3065
|
+
const info = parseNumericLiteralInfo(g.s);
|
|
3066
|
+
if (!info) return [];
|
|
3067
|
+
if (typeof info.value !== 'number') {
|
|
3068
|
+
// BigInt (xsd:integer) – already integral
|
|
3069
|
+
const lit = internLiteral(String(info.value));
|
|
3070
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
3071
|
+
}
|
|
3072
|
+
if (Number.isNaN(info.value) || !Number.isFinite(info.value)) return [];
|
|
3073
|
+
const lit = internLiteral(String(Math.ceil(info.value)));
|
|
3074
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
// math:floor (Eyeling extension)
|
|
3078
|
+
// Schema: $s+ math:floor $o-
|
|
3079
|
+
// Largest integer <= s (fails on NaN / non-numeric).
|
|
3080
|
+
if (pv === MATH_NS + 'floor') {
|
|
3081
|
+
const info = parseNumericLiteralInfo(g.s);
|
|
3082
|
+
if (!info) return [];
|
|
3083
|
+
if (typeof info.value !== 'number') {
|
|
3084
|
+
const lit = internLiteral(String(info.value));
|
|
3085
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
3086
|
+
}
|
|
3087
|
+
if (Number.isNaN(info.value) || !Number.isFinite(info.value)) return [];
|
|
3088
|
+
const lit = internLiteral(String(Math.floor(info.value)));
|
|
3089
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
2919
3092
|
if (g.o instanceof Blank) return [{ ...subst }];
|
|
2920
3093
|
|
|
2921
3094
|
// Accept typed numeric literals too (e.g., "3"^^xsd:float) if numerically equal.
|
|
@@ -3712,6 +3885,44 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
3712
3885
|
s2[g.o.name] = ty;
|
|
3713
3886
|
return [s2];
|
|
3714
3887
|
}
|
|
3888
|
+
|
|
3889
|
+
// log:isIRI / log:isLiteral / log:isBlank / log:isNumeric / log:isTriple (Eyeling extensions)
|
|
3890
|
+
// Schema: $s+ log:isIRI $o? (succeeds when s matches; o may be 'true' or a variable)
|
|
3891
|
+
function unifyBoolTrue(obj, subst0) {
|
|
3892
|
+
if (obj instanceof Blank) return [subst0];
|
|
3893
|
+
const tTrue = internLiteral('true');
|
|
3894
|
+
const s2 = unifyTermMaybe(obj, tTrue, subst0);
|
|
3895
|
+
return s2 ? [s2] : [];
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
if (pv === LOG_NS + 'isIRI') {
|
|
3899
|
+
if (!(g.s instanceof Iri)) return [];
|
|
3900
|
+
return unifyBoolTrue(g.o, subst);
|
|
3901
|
+
}
|
|
3902
|
+
|
|
3903
|
+
if (pv === LOG_NS + 'isLiteral') {
|
|
3904
|
+
if (!(g.s instanceof Literal)) return [];
|
|
3905
|
+
return unifyBoolTrue(g.o, subst);
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
if (pv === LOG_NS + 'isBlank') {
|
|
3909
|
+
if (!(g.s instanceof Blank)) return [];
|
|
3910
|
+
return unifyBoolTrue(g.o, subst);
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
if (pv === LOG_NS + 'isNumeric') {
|
|
3914
|
+
if (!(g.s instanceof Literal)) return [];
|
|
3915
|
+
const dt = numericDatatypeOfTerm(g.s);
|
|
3916
|
+
if (!dt) return [];
|
|
3917
|
+
return unifyBoolTrue(g.o, subst);
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3920
|
+
if (pv === LOG_NS + 'isTriple') {
|
|
3921
|
+
if (!(g.s instanceof GraphTerm)) return [];
|
|
3922
|
+
if (g.s.triples.length !== 1) return [];
|
|
3923
|
+
return unifyBoolTrue(g.o, subst);
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3715
3926
|
if (g.o instanceof Blank) return [{ ...subst }];
|
|
3716
3927
|
|
|
3717
3928
|
const s2 = unifyTerm(g.o, ty, subst);
|
|
@@ -4190,6 +4401,24 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
4190
4401
|
skolemCache.set(key, iri);
|
|
4191
4402
|
}
|
|
4192
4403
|
|
|
4404
|
+
// log:uuid / log:struuid (Eyeling extensions)
|
|
4405
|
+
// NOTE: these generate fresh values and can affect termination; prefer log:skolem for deterministic IDs.
|
|
4406
|
+
//
|
|
4407
|
+
// log:uuid: $s? log:uuid $o- -> binds $o to a fresh <urn:uuid:...> IRI
|
|
4408
|
+
// log:struuid: $s? log:struuid $o- -> binds $o to a fresh UUID string literal
|
|
4409
|
+
if (pv === LOG_NS + 'uuid') {
|
|
4410
|
+
const uuid = __randomUuidV4();
|
|
4411
|
+
const iri = internIri('urn:uuid:' + uuid);
|
|
4412
|
+
return unifyTermMaybe(g.o, iri, subst);
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
if (pv === LOG_NS + 'struuid') {
|
|
4416
|
+
const uuid = __randomUuidV4();
|
|
4417
|
+
const lit = makeStringLiteral(uuid);
|
|
4418
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
4419
|
+
}
|
|
4420
|
+
|
|
4421
|
+
|
|
4193
4422
|
const s2 = unifyTerm(goal.o, iri, subst);
|
|
4194
4423
|
return s2 !== null ? [s2] : [];
|
|
4195
4424
|
}
|
|
@@ -4297,6 +4526,68 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
4297
4526
|
args.push(aStr);
|
|
4298
4527
|
}
|
|
4299
4528
|
|
|
4529
|
+
// string:length (Eyeling extension)
|
|
4530
|
+
// Schema: $s+ string:length $o-
|
|
4531
|
+
if (pv === STRING_NS + 'length') {
|
|
4532
|
+
const s0 = termToJsStringDecoded(g.s);
|
|
4533
|
+
if (s0 === null) return [];
|
|
4534
|
+
const lit = internLiteral(String(s0.length));
|
|
4535
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
// string:upperCase / string:lowerCase (Eyeling extensions)
|
|
4539
|
+
// Schema: $s+ string:upperCase $o- ; $s+ string:lowerCase $o-
|
|
4540
|
+
if (pv === STRING_NS + 'upperCase' || pv === STRING_NS + 'lowerCase') {
|
|
4541
|
+
const s0 = termToJsStringDecoded(g.s);
|
|
4542
|
+
if (s0 === null) return [];
|
|
4543
|
+
const out = pv.endsWith('upperCase') ? s0.toUpperCase() : s0.toLowerCase();
|
|
4544
|
+
const lit = makeStringLiteral(out);
|
|
4545
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// string:encodeForURI (Eyeling extension)
|
|
4549
|
+
// Schema: $s+ string:encodeForURI $o-
|
|
4550
|
+
if (pv === STRING_NS + 'encodeForURI') {
|
|
4551
|
+
const s0 = termToJsStringDecoded(g.s);
|
|
4552
|
+
if (s0 === null) return [];
|
|
4553
|
+
// SPARQL-like: start with encodeURIComponent and also escape [!'()*]
|
|
4554
|
+
const enc = encodeURIComponent(s0).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
4555
|
+
const lit = makeStringLiteral(enc);
|
|
4556
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4559
|
+
// string:substring (Eyeling extension)
|
|
4560
|
+
// Schema: ( $s+ $start+ [$len+] ) string:substring $o-
|
|
4561
|
+
// NOTE: start is 1-based (SPARQL SUBSTR), len is optional.
|
|
4562
|
+
if (pv === STRING_NS + 'substring') {
|
|
4563
|
+
if (!(g.s instanceof ListTerm)) return [];
|
|
4564
|
+
const items = g.s.items;
|
|
4565
|
+
if (items.length !== 2 && items.length !== 3) return [];
|
|
4566
|
+
const s0 = termToJsStringDecoded(items[0]);
|
|
4567
|
+
if (s0 === null) return [];
|
|
4568
|
+
const startInfo = parseNumericLiteralInfo(items[1]);
|
|
4569
|
+
if (!startInfo || typeof startInfo.value !== 'number' || Number.isNaN(startInfo.value)) return [];
|
|
4570
|
+
let start = Math.floor(startInfo.value);
|
|
4571
|
+
if (!Number.isFinite(start)) return [];
|
|
4572
|
+
start = Math.max(1, start);
|
|
4573
|
+
|
|
4574
|
+
let outStr = '';
|
|
4575
|
+
if (items.length === 2) {
|
|
4576
|
+
outStr = s0.slice(start - 1);
|
|
4577
|
+
} else {
|
|
4578
|
+
const lenInfo = parseNumericLiteralInfo(items[2]);
|
|
4579
|
+
if (!lenInfo || typeof lenInfo.value !== 'number' || Number.isNaN(lenInfo.value)) return [];
|
|
4580
|
+
let len = Math.floor(lenInfo.value);
|
|
4581
|
+
if (!Number.isFinite(len)) return [];
|
|
4582
|
+
if (len <= 0) outStr = '';
|
|
4583
|
+
else outStr = s0.slice(start - 1, start - 1 + len);
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
const lit = makeStringLiteral(outStr);
|
|
4587
|
+
return unifyTermMaybe(g.o, lit, subst);
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
|
|
4300
4591
|
const formatted = simpleStringFormat(fmtStr, args);
|
|
4301
4592
|
if (formatted === null) return []; // unsupported format specifier(s)
|
|
4302
4593
|
|
|
@@ -4310,6 +4601,21 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
4310
4601
|
return s2 !== null ? [s2] : [];
|
|
4311
4602
|
}
|
|
4312
4603
|
|
|
4604
|
+
// string:jsonPointer
|
|
4605
|
+
// Schema: ( $jsonText $pointer ) string:jsonPointer $value
|
|
4606
|
+
if (pv === STRING_NS + 'jsonPointer') {
|
|
4607
|
+
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
4608
|
+
|
|
4609
|
+
const jsonText = termToJsonText(g.s.elems[0]);
|
|
4610
|
+
const ptr = termToJsStringDecoded(g.s.elems[1]);
|
|
4611
|
+
if (jsonText === null || ptr === null) return [];
|
|
4612
|
+
|
|
4613
|
+
const valTerm = jsonPointerLookup(jsonText, ptr);
|
|
4614
|
+
if (valTerm === null) return [];
|
|
4615
|
+
|
|
4616
|
+
const s2 = unifyTerm(g.o, valTerm, subst);
|
|
4617
|
+
return s2 !== null ? [s2] : [];
|
|
4618
|
+
}
|
|
4313
4619
|
|
|
4314
4620
|
// string:greaterThan
|
|
4315
4621
|
if (pv === STRING_NS + 'greaterThan') {
|
package/lib/rules.js
CHANGED
|
@@ -94,6 +94,11 @@ function isConstraintBuiltin(tr) {
|
|
|
94
94
|
v === LOG_NS + 'forAllIn' ||
|
|
95
95
|
v === LOG_NS + 'notEqualTo' ||
|
|
96
96
|
v === LOG_NS + 'notIncludes' ||
|
|
97
|
+
v === LOG_NS + 'isIRI' ||
|
|
98
|
+
v === LOG_NS + 'isLiteral' ||
|
|
99
|
+
v === LOG_NS + 'isBlank' ||
|
|
100
|
+
v === LOG_NS + 'isNumeric' ||
|
|
101
|
+
v === LOG_NS + 'isTriple' ||
|
|
97
102
|
v === LOG_NS + 'outputString'
|
|
98
103
|
) {
|
|
99
104
|
return true;
|
package/package.json
CHANGED
package/test/n3gen.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
// Convert examples/input/*.{ttl,trig} -> examples/*.n3 using n3gen.js
|
|
4
|
+
// Convert examples/input/*.{ttl,trig,srl} -> examples/*.n3 using n3gen.js
|
|
5
5
|
// Designed to work both in a git checkout (maintainer mode) and in an npm-installed package.
|
|
6
6
|
//
|
|
7
7
|
// In git mode:
|
|
@@ -109,14 +109,14 @@ function main() {
|
|
|
109
109
|
const IN_GIT = inGitWorktree(root);
|
|
110
110
|
|
|
111
111
|
const inputs = fs.readdirSync(inputDir)
|
|
112
|
-
.filter(f => /\.(ttl|trig)$/i.test(f))
|
|
112
|
+
.filter(f => /\.(ttl|trig|srl)$/i.test(f))
|
|
113
113
|
.sort((a, b) => a.localeCompare(b));
|
|
114
114
|
|
|
115
115
|
info(`Running n3 conversions for ${inputs.length} inputs (${IN_GIT ? 'git worktree mode' : 'npm-installed mode'})`);
|
|
116
116
|
console.log(`${C.dim}node ${process.version}${C.n}`);
|
|
117
117
|
|
|
118
118
|
if (inputs.length === 0) {
|
|
119
|
-
ok('No .ttl/.trig files found in examples/input/');
|
|
119
|
+
ok('No .ttl/.trig/.srl files found in examples/input/');
|
|
120
120
|
process.exit(0);
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -129,7 +129,7 @@ function main() {
|
|
|
129
129
|
const start = Date.now();
|
|
130
130
|
|
|
131
131
|
const inPath = path.join(inputDir, inFile);
|
|
132
|
-
const base = inFile.replace(/\.(ttl|trig)$/i, '');
|
|
132
|
+
const base = inFile.replace(/\.(ttl|trig|srl)$/i, '');
|
|
133
133
|
const outFile = `${base}.n3`;
|
|
134
134
|
|
|
135
135
|
const expectedPath = path.join(examplesDir, outFile);
|