eyeling 1.16.0 → 1.16.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.
@@ -2,6 +2,8 @@
2
2
 
3
3
  ARCtifacts are trustworthy programs telling a concise story in three parts. First comes the **Answer** to a specific question. This is followed by the **Reason Why** that answer is correct, articulated in everyday language and supported by the relevant identities, rules, or ideas. Finally, every case includes a **Check**—a concrete test designed to fail loudly if an assumption doesn't hold or an edge case bites. The result is a computation with a complete, auditable trail: you can see precisely what was done, why it was valid, and how the page verifies its own work.
4
4
 
5
+ At the core of this approach are three familiar ingredients: **Data**, **Logic**, and a **Question**. We summarize the workflow as **P3 — Prompt → Program → Proof**: the prompt supplies the task and materials, the program turns them into a concrete, repeatable procedure, and the proof is practical rather than ceremonial, consisting of the **Reason Why** together with the **Check**. This is what makes each ARCtifact not just a result, but a portable, auditable, and trustworthy computational artifact.
6
+
5
7
  ## Science
6
8
 
7
9
  - [**Body Mass Index**](https://eyereasoner.github.io/eyeling/arctifacts/bmi.html) — Compute BMI categories with explainable thresholds and sanity checks.
package/eyeling.js CHANGED
@@ -135,6 +135,33 @@ function __builtinCollectVarsInTriple(tr, out) {
135
135
  __builtinCollectVarsInTerm(tr.o, out);
136
136
  }
137
137
 
138
+ function __isRuleFormulaLikeTerm(t) {
139
+ return t instanceof GraphTerm || (t instanceof Literal && (t.value === 'true' || t.value === 'false'));
140
+ }
141
+
142
+ function __expandScopedVarPredicateGoals(goals) {
143
+ if (!Array.isArray(goals) || goals.length === 0) return [{ goals, bind: null }];
144
+
145
+ let variants = [{ goals: goals.slice(), bind: null }];
146
+ const impliesIri = internIri(LOG_NS + 'implies');
147
+
148
+ for (let i = 0; i < goals.length; i++) {
149
+ const tr = goals[i];
150
+ if (!(tr.p instanceof Var)) continue;
151
+ if (!__isRuleFormulaLikeTerm(tr.s) && !__isRuleFormulaLikeTerm(tr.o)) continue;
152
+
153
+ const next = variants.slice();
154
+ for (const v of variants) {
155
+ const altGoals = v.goals.slice();
156
+ altGoals[i] = new Triple(altGoals[i].s, impliesIri, altGoals[i].o);
157
+ const altBind = { ...(v.bind || {}), [tr.p.name]: impliesIri };
158
+ next.push({ goals: altGoals, bind: altBind });
159
+ }
160
+ variants = next;
161
+ }
162
+ return variants;
163
+ }
164
+
138
165
  function __builtinCollectVarsInTriples(triples, out) {
139
166
  for (const tr of triples) __builtinCollectVarsInTriple(tr, out);
140
167
  }
@@ -267,7 +294,7 @@ function termToJsString(t) {
267
294
  if (t instanceof Iri) return t.value;
268
295
  if (!(t instanceof Literal)) return null;
269
296
 
270
- const [lex, _dt] = literalParts(t.value);
297
+ const [lex] = literalParts(t.value);
271
298
 
272
299
  if (isQuotedLexical(lex)) {
273
300
  // Interpret N3/Turtle string escapes (\" \n \uXXXX \UXXXXXXXX …)
@@ -289,7 +316,7 @@ function termToJsStringDecoded(t) {
289
316
  // Like termToJsString, but for short literals it *also* interprets escapes
290
317
  // (\" \n \uXXXX …) by attempting JSON.parse on the quoted lexical form.
291
318
  if (!(t instanceof Literal)) return null;
292
- const [lex, _dt] = literalParts(t.value);
319
+ const [lex] = literalParts(t.value);
293
320
 
294
321
  // Long strings: """ ... """ are taken verbatim.
295
322
  if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
@@ -300,7 +327,7 @@ function termToJsStringDecoded(t) {
300
327
  if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
301
328
  try {
302
329
  return JSON.parse(lex);
303
- } catch (_e) {
330
+ } catch {
304
331
  /* fall through */
305
332
  }
306
333
  return stripQuotes(lex);
@@ -365,13 +392,13 @@ function compileSwapRegex(pattern, extraFlags) {
365
392
  const flags = (extraFlags || '') + (needU ? 'u' : '');
366
393
  try {
367
394
  return new RegExp(pattern, flags);
368
- } catch (_e) {
395
+ } catch {
369
396
  if (needU) {
370
397
  const p2 = sanitizeForUnicodeMode(pattern);
371
398
  if (p2 !== pattern) {
372
399
  try {
373
400
  return new RegExp(p2, flags);
374
- } catch (_e2) {}
401
+ } catch {}
375
402
  }
376
403
  }
377
404
  return null;
@@ -1393,7 +1420,7 @@ function hashLiteralTerm(t, algo) {
1393
1420
  try {
1394
1421
  const digest = nodeCrypto.createHash(algo).update(input, 'utf8').digest('hex');
1395
1422
  return internLiteral(JSON.stringify(digest));
1396
- } catch (_e) {
1423
+ } catch {
1397
1424
  return null;
1398
1425
  }
1399
1426
  }
@@ -2590,7 +2617,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2590
2617
 
2591
2618
  const results = [];
2592
2619
  for (const el of inputList) {
2593
- const yvar = new Var('_mapY');
2620
+ const yvar = new Var('mapY');
2594
2621
  const goal2 = new Triple(el, pred, yvar);
2595
2622
  const sols = proveGoals([goal2], subst, facts, backRules, depth + 1, [], varGen);
2596
2623
 
@@ -3071,18 +3098,39 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3071
3098
  const visited2 = [];
3072
3099
  const keepVars = new Set();
3073
3100
  if (g.s instanceof GraphTerm) __builtinCollectVarsInTriples(g.s.triples, keepVars);
3074
- // Start from the incoming substitution so bindings flow outward.
3075
- return proveGoals(
3076
- Array.from(g.o.triples),
3077
- { ...subst },
3078
- scopeFacts,
3079
- scopeBackRules,
3080
- depth + 1,
3081
- visited2,
3082
- varGen,
3083
- maxResults,
3084
- keepVars.size ? { keepVars } : undefined,
3085
- );
3101
+
3102
+ const goalVariants = __expandScopedVarPredicateGoals(Array.from(g.o.triples));
3103
+ const out = [];
3104
+ for (const variant of goalVariants) {
3105
+ const sols = proveGoals(
3106
+ variant.goals,
3107
+ { ...subst },
3108
+ scopeFacts,
3109
+ scopeBackRules,
3110
+ depth + 1,
3111
+ visited2,
3112
+ varGen,
3113
+ maxResults,
3114
+ keepVars.size ? { keepVars } : undefined,
3115
+ );
3116
+ for (const s2 of sols) {
3117
+ const merged = { ...s2 };
3118
+ let ok = true;
3119
+ if (variant.bind) {
3120
+ for (const [k, v] of Object.entries(variant.bind)) {
3121
+ if (Object.prototype.hasOwnProperty.call(merged, k) && !termsEqual(merged[k], v)) {
3122
+ ok = false;
3123
+ break;
3124
+ }
3125
+ merged[k] = v;
3126
+ }
3127
+ }
3128
+ if (!ok) continue;
3129
+ out.push(merged);
3130
+ if (typeof maxResults === 'number' && maxResults > 0 && out.length >= maxResults) return out;
3131
+ }
3132
+ }
3133
+ return out;
3086
3134
  }
3087
3135
 
3088
3136
  // log:notIncludes
@@ -3972,7 +4020,7 @@ function main() {
3972
4020
  }
3973
4021
 
3974
4022
  if (showAst) {
3975
- function astReplacer(_key, value) {
4023
+ function astReplacer(unusedJsonKey, value) {
3976
4024
  if (value instanceof Set) return Array.from(value);
3977
4025
  if (value && typeof value === 'object' && value.constructor) {
3978
4026
  const t = value.constructor.name;
@@ -4112,7 +4160,7 @@ function main() {
4112
4160
  engine.setTracePrefixes(outPrefixes);
4113
4161
 
4114
4162
  const entries = Object.entries(outPrefixes.map)
4115
- .filter(([_p, base]) => !!base)
4163
+ .filter(([, base]) => !!base)
4116
4164
  .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
4117
4165
 
4118
4166
  for (const [pfx, base] of entries) {
@@ -4546,7 +4594,7 @@ function parseSemanticsToFormula(text, baseIri) {
4546
4594
  const parser = new Parser(toks);
4547
4595
  if (typeof baseIri === 'string' && baseIri) parser.prefixes.setBase(baseIri);
4548
4596
 
4549
- const [_prefixes, triples, frules, brules] = parser.parseDocument();
4597
+ const [, triples, frules, brules] = parser.parseDocument();
4550
4598
 
4551
4599
  const all = triples.slice();
4552
4600
 
@@ -7926,7 +7974,7 @@ function makeExplain(deps) {
7926
7974
  // log:outputString support
7927
7975
  // ===========================================================================
7928
7976
 
7929
- function __compareOutputStringKeys(a, b, _prefixes) {
7977
+ function compareOutputStringKeys(a, b) {
7930
7978
  // Deterministic ordering of keys. The spec only requires "order of the subject keys"
7931
7979
  // and leaves concrete term ordering reasoner-dependent. We implement:
7932
7980
  // 1) numeric literals (numeric value)
@@ -8004,7 +8052,7 @@ function makeExplain(deps) {
8004
8052
  }
8005
8053
 
8006
8054
  pairs.sort((a, b) => {
8007
- const c = __compareOutputStringKeys(a.key, b.key, prefixes);
8055
+ const c = compareOutputStringKeys(a.key, b.key, prefixes);
8008
8056
  if (c !== 0) return c;
8009
8057
  return a.idx - b.idx; // stable tie-breaker
8010
8058
  });
@@ -10005,7 +10053,7 @@ function collectIrisInTerm(t) {
10005
10053
  if (t instanceof Iri) {
10006
10054
  out.push(t.value);
10007
10055
  } else if (t instanceof Literal) {
10008
- const [_lex, dt] = literalParts(t.value);
10056
+ const [, dt] = literalParts(t.value);
10009
10057
  if (dt) out.push(dt); // so rdf/xsd prefixes are emitted when only used in ^^...
10010
10058
  } else if (t instanceof ListTerm) {
10011
10059
  for (const x of t.elems) out.push(...collectIrisInTerm(x));
@@ -11576,8 +11624,8 @@ module.exports = {
11576
11624
  const __entry = __loadEntry();
11577
11625
  const __api = { reasonStream: __entry.reasonStream, reasonRdfJs: __entry.reasonRdfJs };
11578
11626
 
11579
- try { if (__outerModule && __outerModule.exports) __outerModule.exports = __api; } catch (_e) {}
11580
- try { if (__outerSelf) __outerSelf.eyeling = __api; } catch (_e) {}
11627
+ try { if (__outerModule && __outerModule.exports) __outerModule.exports = __api; } catch (ignoredError) {}
11628
+ try { if (__outerSelf) __outerSelf.eyeling = __api; } catch (ignoredError) {}
11581
11629
 
11582
11630
  // ---- demo.html compatibility ----
11583
11631
  // The original monolithic eyeling.js exposed internal functions/flags as globals.
@@ -11605,18 +11653,18 @@ module.exports = {
11605
11653
  // Fallback (no live linkage)
11606
11654
  if (typeof getFn === "function") __outerSelf[name] = getFn();
11607
11655
  }
11608
- } catch (_e) {}
11656
+ } catch (ignoredError) {}
11609
11657
  };
11610
11658
 
11611
11659
  def("enforceHttpsEnabled", __entry.getEnforceHttpsEnabled, __entry.setEnforceHttpsEnabled);
11612
11660
  def("proofCommentsEnabled", __entry.getProofCommentsEnabled, __entry.setProofCommentsEnabled);
11613
11661
  def("__tracePrefixes", __entry.getTracePrefixes, __entry.setTracePrefixes);
11614
11662
  }
11615
- } catch (_e) {}
11663
+ } catch (ignoredError) {}
11616
11664
 
11617
11665
  try {
11618
11666
  if (__outerModule && __outerRequire && __outerRequire.main === __outerModule && typeof __entry.main === "function") {
11619
11667
  __entry.main();
11620
11668
  }
11621
- } catch (_e) {}
11669
+ } catch (ignoredError) {}
11622
11670
  })();
package/lib/builtins.js CHANGED
@@ -123,6 +123,33 @@ function __builtinCollectVarsInTriple(tr, out) {
123
123
  __builtinCollectVarsInTerm(tr.o, out);
124
124
  }
125
125
 
126
+ function __isRuleFormulaLikeTerm(t) {
127
+ return t instanceof GraphTerm || (t instanceof Literal && (t.value === 'true' || t.value === 'false'));
128
+ }
129
+
130
+ function __expandScopedVarPredicateGoals(goals) {
131
+ if (!Array.isArray(goals) || goals.length === 0) return [{ goals, bind: null }];
132
+
133
+ let variants = [{ goals: goals.slice(), bind: null }];
134
+ const impliesIri = internIri(LOG_NS + 'implies');
135
+
136
+ for (let i = 0; i < goals.length; i++) {
137
+ const tr = goals[i];
138
+ if (!(tr.p instanceof Var)) continue;
139
+ if (!__isRuleFormulaLikeTerm(tr.s) && !__isRuleFormulaLikeTerm(tr.o)) continue;
140
+
141
+ const next = variants.slice();
142
+ for (const v of variants) {
143
+ const altGoals = v.goals.slice();
144
+ altGoals[i] = new Triple(altGoals[i].s, impliesIri, altGoals[i].o);
145
+ const altBind = { ...(v.bind || {}), [tr.p.name]: impliesIri };
146
+ next.push({ goals: altGoals, bind: altBind });
147
+ }
148
+ variants = next;
149
+ }
150
+ return variants;
151
+ }
152
+
126
153
  function __builtinCollectVarsInTriples(triples, out) {
127
154
  for (const tr of triples) __builtinCollectVarsInTriple(tr, out);
128
155
  }
@@ -255,7 +282,7 @@ function termToJsString(t) {
255
282
  if (t instanceof Iri) return t.value;
256
283
  if (!(t instanceof Literal)) return null;
257
284
 
258
- const [lex, _dt] = literalParts(t.value);
285
+ const [lex] = literalParts(t.value);
259
286
 
260
287
  if (isQuotedLexical(lex)) {
261
288
  // Interpret N3/Turtle string escapes (\" \n \uXXXX \UXXXXXXXX …)
@@ -277,7 +304,7 @@ function termToJsStringDecoded(t) {
277
304
  // Like termToJsString, but for short literals it *also* interprets escapes
278
305
  // (\" \n \uXXXX …) by attempting JSON.parse on the quoted lexical form.
279
306
  if (!(t instanceof Literal)) return null;
280
- const [lex, _dt] = literalParts(t.value);
307
+ const [lex] = literalParts(t.value);
281
308
 
282
309
  // Long strings: """ ... """ are taken verbatim.
283
310
  if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
@@ -288,7 +315,7 @@ function termToJsStringDecoded(t) {
288
315
  if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
289
316
  try {
290
317
  return JSON.parse(lex);
291
- } catch (_e) {
318
+ } catch {
292
319
  /* fall through */
293
320
  }
294
321
  return stripQuotes(lex);
@@ -353,13 +380,13 @@ function compileSwapRegex(pattern, extraFlags) {
353
380
  const flags = (extraFlags || '') + (needU ? 'u' : '');
354
381
  try {
355
382
  return new RegExp(pattern, flags);
356
- } catch (_e) {
383
+ } catch {
357
384
  if (needU) {
358
385
  const p2 = sanitizeForUnicodeMode(pattern);
359
386
  if (p2 !== pattern) {
360
387
  try {
361
388
  return new RegExp(p2, flags);
362
- } catch (_e2) {}
389
+ } catch {}
363
390
  }
364
391
  }
365
392
  return null;
@@ -1381,7 +1408,7 @@ function hashLiteralTerm(t, algo) {
1381
1408
  try {
1382
1409
  const digest = nodeCrypto.createHash(algo).update(input, 'utf8').digest('hex');
1383
1410
  return internLiteral(JSON.stringify(digest));
1384
- } catch (_e) {
1411
+ } catch {
1385
1412
  return null;
1386
1413
  }
1387
1414
  }
@@ -2578,7 +2605,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2578
2605
 
2579
2606
  const results = [];
2580
2607
  for (const el of inputList) {
2581
- const yvar = new Var('_mapY');
2608
+ const yvar = new Var('mapY');
2582
2609
  const goal2 = new Triple(el, pred, yvar);
2583
2610
  const sols = proveGoals([goal2], subst, facts, backRules, depth + 1, [], varGen);
2584
2611
 
@@ -3059,18 +3086,39 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3059
3086
  const visited2 = [];
3060
3087
  const keepVars = new Set();
3061
3088
  if (g.s instanceof GraphTerm) __builtinCollectVarsInTriples(g.s.triples, keepVars);
3062
- // Start from the incoming substitution so bindings flow outward.
3063
- return proveGoals(
3064
- Array.from(g.o.triples),
3065
- { ...subst },
3066
- scopeFacts,
3067
- scopeBackRules,
3068
- depth + 1,
3069
- visited2,
3070
- varGen,
3071
- maxResults,
3072
- keepVars.size ? { keepVars } : undefined,
3073
- );
3089
+
3090
+ const goalVariants = __expandScopedVarPredicateGoals(Array.from(g.o.triples));
3091
+ const out = [];
3092
+ for (const variant of goalVariants) {
3093
+ const sols = proveGoals(
3094
+ variant.goals,
3095
+ { ...subst },
3096
+ scopeFacts,
3097
+ scopeBackRules,
3098
+ depth + 1,
3099
+ visited2,
3100
+ varGen,
3101
+ maxResults,
3102
+ keepVars.size ? { keepVars } : undefined,
3103
+ );
3104
+ for (const s2 of sols) {
3105
+ const merged = { ...s2 };
3106
+ let ok = true;
3107
+ if (variant.bind) {
3108
+ for (const [k, v] of Object.entries(variant.bind)) {
3109
+ if (Object.prototype.hasOwnProperty.call(merged, k) && !termsEqual(merged[k], v)) {
3110
+ ok = false;
3111
+ break;
3112
+ }
3113
+ merged[k] = v;
3114
+ }
3115
+ }
3116
+ if (!ok) continue;
3117
+ out.push(merged);
3118
+ if (typeof maxResults === 'number' && maxResults > 0 && out.length >= maxResults) return out;
3119
+ }
3120
+ }
3121
+ return out;
3074
3122
  }
3075
3123
 
3076
3124
  // log:notIncludes
package/lib/cli.js CHANGED
@@ -153,7 +153,7 @@ function main() {
153
153
  }
154
154
 
155
155
  if (showAst) {
156
- function astReplacer(_key, value) {
156
+ function astReplacer(unusedJsonKey, value) {
157
157
  if (value instanceof Set) return Array.from(value);
158
158
  if (value && typeof value === 'object' && value.constructor) {
159
159
  const t = value.constructor.name;
@@ -293,7 +293,7 @@ function main() {
293
293
  engine.setTracePrefixes(outPrefixes);
294
294
 
295
295
  const entries = Object.entries(outPrefixes.map)
296
- .filter(([_p, base]) => !!base)
296
+ .filter(([, base]) => !!base)
297
297
  .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
298
298
 
299
299
  for (const [pfx, base] of entries) {
package/lib/deref.js CHANGED
@@ -359,7 +359,7 @@ function parseSemanticsToFormula(text, baseIri) {
359
359
  const parser = new Parser(toks);
360
360
  if (typeof baseIri === 'string' && baseIri) parser.prefixes.setBase(baseIri);
361
361
 
362
- const [_prefixes, triples, frules, brules] = parser.parseDocument();
362
+ const [, triples, frules, brules] = parser.parseDocument();
363
363
 
364
364
  const all = triples.slice();
365
365
 
package/lib/explain.js CHANGED
@@ -118,7 +118,7 @@ function makeExplain(deps) {
118
118
  // log:outputString support
119
119
  // ===========================================================================
120
120
 
121
- function __compareOutputStringKeys(a, b, _prefixes) {
121
+ function compareOutputStringKeys(a, b) {
122
122
  // Deterministic ordering of keys. The spec only requires "order of the subject keys"
123
123
  // and leaves concrete term ordering reasoner-dependent. We implement:
124
124
  // 1) numeric literals (numeric value)
@@ -196,7 +196,7 @@ function makeExplain(deps) {
196
196
  }
197
197
 
198
198
  pairs.sort((a, b) => {
199
- const c = __compareOutputStringKeys(a.key, b.key, prefixes);
199
+ const c = compareOutputStringKeys(a.key, b.key, prefixes);
200
200
  if (c !== 0) return c;
201
201
  return a.idx - b.idx; // stable tie-breaker
202
202
  });
package/lib/prelude.js CHANGED
@@ -426,7 +426,7 @@ function collectIrisInTerm(t) {
426
426
  if (t instanceof Iri) {
427
427
  out.push(t.value);
428
428
  } else if (t instanceof Literal) {
429
- const [_lex, dt] = literalParts(t.value);
429
+ const [, dt] = literalParts(t.value);
430
430
  if (dt) out.push(dt); // so rdf/xsd prefixes are emitted when only used in ^^...
431
431
  } else if (t instanceof ListTerm) {
432
432
  for (const x of t.elems) out.push(...collectIrisInTerm(x));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.16.0",
3
+ "version": "1.16.2",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -1305,15 +1305,15 @@ ex:a p:trig ex:b.
1305
1305
  });
1306
1306
 
1307
1307
  // stash for check()
1308
- this._seen = seen;
1309
- this._result = r;
1308
+ this.seen = seen;
1309
+ this.result = r;
1310
1310
  return r.closureN3;
1311
1311
  },
1312
1312
  expect: [/http:\/\/example\.org\/q/m],
1313
1313
  notExpect: [/http:\/\/example\.org\/p/m],
1314
1314
  check(out, tc) {
1315
- assert.equal(tc._seen.length, 1, 'Expected onDerived to be called once');
1316
- assert.match(tc._seen[0], /http:\/\/example\.org\/q/, 'Expected streamed triple to be the derived one');
1315
+ assert.equal(tc.seen.length, 1, 'Expected onDerived to be called once');
1316
+ assert.match(tc.seen[0], /http:\/\/example\.org\/q/, 'Expected streamed triple to be the derived one');
1317
1317
  // closureN3 should be exactly the derived triple (no input facts).
1318
1318
  assert.ok(String(out).trim().includes('http://example.org/q'));
1319
1319
  assert.ok(!String(out).includes('http://example.org/p'));
@@ -1584,19 +1584,19 @@ _:x :hates { _:foo :making :mess }.
1584
1584
  onDerived: ({ quad }) => seen.push(quad),
1585
1585
  },
1586
1586
  );
1587
- this._seen = seen;
1588
- this._result = result;
1587
+ this.seen = seen;
1588
+ this.result = result;
1589
1589
  return result.closureN3;
1590
1590
  },
1591
1591
  expect: [/http:\/\/example\.org\/q/m],
1592
1592
  notExpect: [/http:\/\/example\.org\/p/m],
1593
- check(_out, tc) {
1594
- assert.equal(tc._seen.length, 1, 'Expected one streamed RDF/JS quad');
1595
- assert.equal(tc._seen[0].termType, 'Quad');
1596
- assert.equal(tc._seen[0].predicate.value, 'http://example.org/q');
1597
- assert.ok(Array.isArray(tc._result.closureQuads), 'Expected closureQuads array');
1598
- assert.equal(tc._result.closureQuads.length, 1);
1599
- assert.equal(tc._result.closureQuads[0].object.value, 'http://example.org/o');
1593
+ check(outputIgnored, tc) {
1594
+ assert.equal(tc.seen.length, 1, 'Expected one streamed RDF/JS quad');
1595
+ assert.equal(tc.seen[0].termType, 'Quad');
1596
+ assert.equal(tc.seen[0].predicate.value, 'http://example.org/q');
1597
+ assert.ok(Array.isArray(tc.result.closureQuads), 'Expected closureQuads array');
1598
+ assert.equal(tc.result.closureQuads.length, 1);
1599
+ assert.equal(tc.result.closureQuads[0].object.value, 'http://example.org/o');
1600
1600
  },
1601
1601
  },
1602
1602
  {
@@ -1633,14 +1633,14 @@ _:x :hates { _:foo :making :mess }.
1633
1633
  })) {
1634
1634
  quads.push(quad);
1635
1635
  }
1636
- this._quads = quads;
1636
+ this.quads = quads;
1637
1637
  return quads.map((q) => `${q.subject.value} ${q.predicate.value} ${q.object.value}`).join('\n');
1638
1638
  },
1639
1639
  expect: [/http:\/\/example\.org\/q/],
1640
- check(_out, tc) {
1641
- assert.equal(tc._quads.length, 1, 'Expected one yielded quad');
1642
- assert.equal(tc._quads[0].predicate.value, 'http://example.org/q');
1643
- assert.equal(tc._quads[0].graph.termType, 'DefaultGraph');
1640
+ check(outputIgnored, tc) {
1641
+ assert.equal(tc.quads.length, 1, 'Expected one yielded quad');
1642
+ assert.equal(tc.quads[0].predicate.value, 'http://example.org/q');
1643
+ assert.equal(tc.quads[0].graph.termType, 'DefaultGraph');
1644
1644
  },
1645
1645
  },
1646
1646
  {
@@ -74,7 +74,7 @@ function startStaticServer(rootDir) {
74
74
 
75
75
  res.writeHead(200, { 'Content-Type': guessContentType(fsPath), 'Cache-Control': 'no-store' });
76
76
  fs.createReadStream(fsPath).pipe(res);
77
- } catch (_e) {
77
+ } catch {
78
78
  res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
79
79
  res.end('Not found');
80
80
  }
package/tools/bundle.js CHANGED
@@ -140,8 +140,10 @@ out.push(' }');
140
140
  out.push(' const __entry = __loadEntry();');
141
141
  out.push(' const __api = { reasonStream: __entry.reasonStream, reasonRdfJs: __entry.reasonRdfJs };');
142
142
  out.push('');
143
- out.push(' try { if (__outerModule && __outerModule.exports) __outerModule.exports = __api; } catch (_e) {}');
144
- out.push(' try { if (__outerSelf) __outerSelf.eyeling = __api; } catch (_e) {}');
143
+ out.push(
144
+ ' try { if (__outerModule && __outerModule.exports) __outerModule.exports = __api; } catch (ignoredError) {}',
145
+ );
146
+ out.push(' try { if (__outerSelf) __outerSelf.eyeling = __api; } catch (ignoredError) {}');
145
147
  out.push('');
146
148
  out.push(' // ---- demo.html compatibility ----');
147
149
  out.push(' // The original monolithic eyeling.js exposed internal functions/flags as globals.');
@@ -175,14 +177,14 @@ out.push(' } else {');
175
177
  out.push(' // Fallback (no live linkage)');
176
178
  out.push(' if (typeof getFn === "function") __outerSelf[name] = getFn();');
177
179
  out.push(' }');
178
- out.push(' } catch (_e) {}');
180
+ out.push(' } catch (ignoredError) {}');
179
181
  out.push(' };');
180
182
  out.push('');
181
183
  out.push(' def("enforceHttpsEnabled", __entry.getEnforceHttpsEnabled, __entry.setEnforceHttpsEnabled);');
182
184
  out.push(' def("proofCommentsEnabled", __entry.getProofCommentsEnabled, __entry.setProofCommentsEnabled);');
183
185
  out.push(' def("__tracePrefixes", __entry.getTracePrefixes, __entry.setTracePrefixes);');
184
186
  out.push(' }');
185
- out.push(' } catch (_e) {}');
187
+ out.push(' } catch (ignoredError) {}');
186
188
  out.push('');
187
189
  out.push(' try {');
188
190
  out.push(
@@ -190,7 +192,7 @@ out.push(
190
192
  );
191
193
  out.push(' __entry.main();');
192
194
  out.push(' }');
193
- out.push(' } catch (_e) {}');
195
+ out.push(' } catch (ignoredError) {}');
194
196
  out.push('})();');
195
197
 
196
198
  fs.writeFileSync(OUT, out.join('\n') + '\n', { encoding: 'utf8' });
package/tools/n3gen.js CHANGED
@@ -32,7 +32,7 @@ const process = require('node:process');
32
32
 
33
33
  const crypto = require('node:crypto');
34
34
 
35
- function _stripIriRef(s) {
35
+ function stripIriRef(s) {
36
36
  // Allow passing an IRIREF like <...>
37
37
  if (typeof s !== 'string') return '';
38
38
  s = s.trim();
@@ -41,7 +41,7 @@ function _stripIriRef(s) {
41
41
  }
42
42
 
43
43
  function normalizeSkolemRoot(root) {
44
- root = _stripIriRef(root);
44
+ root = stripIriRef(root);
45
45
  if (!root) return '';
46
46
  // Ensure it ends with '/.well-known/genid/' OR at least with '/'
47
47
  if (!root.endsWith('/')) root += '/';
@@ -64,7 +64,7 @@ const SKOLEM_ROOT = normalizeSkolemRoot(process.env.SKOLEM_ROOT) || DEFAULT_SKOL
64
64
  let SKOLEM_UUID = null; // e.g., '3f2504e0-4f89-5d3a-9a0c-0305e82c3301'
65
65
  let SKOLEM_PREFIX_IRI = null; // e.g., 'https://.../.well-known/genid/<UUID>#'
66
66
 
67
- function _deterministicUuidFromText(inputText) {
67
+ function deterministicUuidFromText(inputText) {
68
68
  const h = crypto.createHash('sha256').update(inputText, 'utf8').digest();
69
69
  const b = Buffer.from(h.subarray(0, 16));
70
70
 
@@ -77,11 +77,11 @@ function _deterministicUuidFromText(inputText) {
77
77
  }
78
78
 
79
79
  function initSkolemForInput(inputText) {
80
- SKOLEM_UUID = _deterministicUuidFromText(inputText);
80
+ SKOLEM_UUID = deterministicUuidFromText(inputText);
81
81
  SKOLEM_PREFIX_IRI = `${SKOLEM_ROOT}${SKOLEM_UUID}#`;
82
82
  }
83
83
 
84
- function _pnLocalSafe(s) {
84
+ function pnLocalSafe(s) {
85
85
  // Turtle PN_LOCAL allows percent escapes (PLX). We make sure all "special"
86
86
  // encodeURIComponent survivors are percent-escaped too.
87
87
  return encodeURIComponent(s).replace(/[!'()*]/g, (c) => '%' + c.charCodeAt(0).toString(16).toUpperCase());
@@ -786,7 +786,7 @@ class TurtleParser {
786
786
  this.blankCounter = 0;
787
787
  this.pendingTriples = [];
788
788
  this.reifierCounter = 0;
789
- this._reifiesEmitted = new Set();
789
+ this.reifiesEmitted = new Set();
790
790
  }
791
791
 
792
792
  peek() {
@@ -811,16 +811,16 @@ class TurtleParser {
811
811
  return new Blank(`_:n3r${this.reifierCounter}`);
812
812
  }
813
813
 
814
- _termKey(t) {
814
+ termKey(t) {
815
815
  if (t == null) return '[]';
816
816
  if (t instanceof Iri) return `I:${t.value}`;
817
817
  if (t instanceof Blank) return `B:${t.label}`;
818
818
  if (t instanceof Literal) return `L:${t.value}`;
819
819
  if (t instanceof Var) return `V:${t.name}`;
820
- if (t instanceof ListTerm) return `T:(` + t.elems.map((x) => this._termKey(x)).join(' ') + `)`;
820
+ if (t instanceof ListTerm) return `T:(` + t.elems.map((x) => this.termKey(x)).join(' ') + `)`;
821
821
  if (t instanceof GraphTerm) {
822
822
  const inner = t.triples
823
- .map((tr) => `${this._termKey(tr.s)} ${this._termKey(tr.p)} ${this._termKey(tr.o)}`)
823
+ .map((tr) => `${this.termKey(tr.s)} ${this.termKey(tr.p)} ${this.termKey(tr.o)}`)
824
824
  .join(' | ');
825
825
  return `G:{${inner}}`;
826
826
  }
@@ -831,9 +831,9 @@ class TurtleParser {
831
831
  // reifier log:nameOf tripleTerm .
832
832
  // We represent tripleTerm in N3 as a quoted graph term: { s p o . }
833
833
  emitReifies(reifier, tripleGraph) {
834
- const key = `${this._termKey(reifier)}|${this._termKey(tripleGraph)}`;
835
- if (this._reifiesEmitted.has(key)) return;
836
- this._reifiesEmitted.add(key);
834
+ const key = `${this.termKey(reifier)}|${this.termKey(tripleGraph)}`;
835
+ if (this.reifiesEmitted.has(key)) return;
836
+ this.reifiesEmitted.add(key);
837
837
  this.pendingTriples.push(new Triple(reifier, internIri(LOG_NS + 'nameOf'), tripleGraph));
838
838
  }
839
839
 
@@ -1519,7 +1519,7 @@ function buildSkolemMapForBnodesThatCrossScopes(triples) {
1519
1519
  if (scopes.size <= 1) continue;
1520
1520
 
1521
1521
  const id = lbl.startsWith('_:') ? lbl.slice(2) : lbl;
1522
- const local = _pnLocalSafe(id);
1522
+ const local = pnLocalSafe(id);
1523
1523
  skolemMap.set(lbl, `${SKOLEM_PREFIX}:${local}`);
1524
1524
  }
1525
1525
  return skolemMap;
@@ -1538,16 +1538,16 @@ function buildSkolemMapForBnodesThatCrossScopes(triples) {
1538
1538
  // semantics-preserving.
1539
1539
  // ---------------------------------------------------------------------------
1540
1540
 
1541
- function _termKey(t) {
1541
+ function termKey(t) {
1542
1542
  if (t == null) return 'N:null';
1543
1543
  if (t instanceof Iri) return `I:${t.value}`;
1544
1544
  if (t instanceof Blank) return `B:${t.label}`;
1545
1545
  if (t instanceof Literal) return `L:${t.value}`;
1546
1546
  if (t instanceof Var) return `V:${t.name}`;
1547
- if (t instanceof ListTerm) return `T:(` + t.elems.map(_termKey).join(' ') + `)`;
1548
- if (t instanceof OpenListTerm) return `T:(` + t.prefix.map(_termKey).join(' ') + ` ... ?${t.tailVar})`;
1547
+ if (t instanceof ListTerm) return `T:(` + t.elems.map(termKey).join(' ') + `)`;
1548
+ if (t instanceof OpenListTerm) return `T:(` + t.prefix.map(termKey).join(' ') + ` ... ?${t.tailVar})`;
1549
1549
  if (t instanceof GraphTerm)
1550
- return `G:{` + t.triples.map((tr) => `${_termKey(tr.s)} ${_termKey(tr.p)} ${_termKey(tr.o)}`).join(' ; ') + `}`;
1550
+ return `G:{` + t.triples.map((tr) => `${termKey(tr.s)} ${termKey(tr.p)} ${termKey(tr.o)}`).join(' ; ') + `}`;
1551
1551
  return `X:${String(t)}`;
1552
1552
  }
1553
1553
 
@@ -1567,11 +1567,11 @@ function foldRdfLists(triples) {
1567
1567
 
1568
1568
  for (let i = 0; i < triples.length; i++) {
1569
1569
  const tr = triples[i];
1570
- const sKey = _termKey(tr.s);
1570
+ const sKey = termKey(tr.s);
1571
1571
  if (!outBySubj.has(sKey)) outBySubj.set(sKey, { term: tr.s, idxs: [] });
1572
1572
  outBySubj.get(sKey).idxs.push(i);
1573
1573
 
1574
- const oKey = _termKey(tr.o);
1574
+ const oKey = termKey(tr.o);
1575
1575
  const viaRest = isIri(tr.p, rdfRest);
1576
1576
  addIncoming(oKey, viaRest);
1577
1577
  }
@@ -1655,7 +1655,7 @@ function foldRdfLists(triples) {
1655
1655
  break;
1656
1656
  }
1657
1657
 
1658
- const nextKey = _termKey(next);
1658
+ const nextKey = termKey(next);
1659
1659
 
1660
1660
  // Intermediate node safety: only referenced via rdf:rest and exactly once.
1661
1661
  const inc = incoming.get(nextKey) || 0;
@@ -1694,7 +1694,7 @@ function foldRdfLists(triples) {
1694
1694
  if (t == null) return t;
1695
1695
 
1696
1696
  if (t instanceof Blank) {
1697
- const m = listMap.get(_termKey(t));
1697
+ const m = listMap.get(termKey(t));
1698
1698
  if (m) return replaceTerm(m.listTerm);
1699
1699
  return t;
1700
1700
  }
@@ -1813,7 +1813,7 @@ function ensureSkolemPrefix(prefixes, skolemMap) {
1813
1813
  const base = prefixes ? prefixes.baseIri || '' : '';
1814
1814
  const labels = [...skolemMap.keys()].sort().join('\n');
1815
1815
  const seed = ['n3gen-skolem', SKOLEM_ROOT, base, labels, ''].join('\n');
1816
- const uuid = _deterministicUuidFromText(seed);
1816
+ const uuid = deterministicUuidFromText(seed);
1817
1817
  SKOLEM_PREFIX_IRI = `${SKOLEM_ROOT}${uuid}#`;
1818
1818
  } else if (!SKOLEM_PREFIX_IRI) {
1819
1819
  SKOLEM_PREFIX_IRI = `${SKOLEM_ROOT}${SKOLEM_UUID}#`;