eyeling 1.26.0 → 1.26.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.
@@ -4826,8 +4826,8 @@ function main() {
4826
4826
  baseIri: __sourceLabelToBaseIri(sourceLabel),
4827
4827
  label: sourceLabel,
4828
4828
  collectUsedPrefixes: streamMode,
4829
- collectSourceLocations: engine.getProofCommentsEnabled(),
4830
4829
  keepSourceArtifacts: false,
4830
+ sourceLocations: engine.getProofCommentsEnabled(),
4831
4831
  rdf: rdfMode,
4832
4832
  }),
4833
4833
  );
@@ -4983,7 +4983,7 @@ function main() {
4983
4983
  }
4984
4984
 
4985
4985
  if (engine.getProofCommentsEnabled()) {
4986
- process.stdout.write(engine.renderProofDocument(outDerived, derived, triples, prefixes, brules));
4986
+ process.stdout.write(engine.renderProofDocument(outDerived, derived.concat(outDerived || []), triples, prefixes, brules));
4987
4987
  return;
4988
4988
  }
4989
4989
 
@@ -5520,6 +5520,7 @@ const {
5520
5520
  Triple,
5521
5521
  Rule,
5522
5522
  DerivedFact,
5523
+ varsInRule,
5523
5524
  internIri,
5524
5525
  collectBlankLabelsInTriples,
5525
5526
  copyQuotedGraphMetadata,
@@ -5537,7 +5538,7 @@ const EMPTY_LIST_TERM = new ListTerm([]);
5537
5538
  const { lex, N3SyntaxError } = require('./lexer');
5538
5539
  const { Parser } = require('./parser');
5539
5540
  const { liftBlankRuleVars } = require('./rules');
5540
- const { parseN3SourceList } = require('./multisource');
5541
+ const { parseN3SourceList, parseN3Text } = require('./multisource');
5541
5542
 
5542
5543
  const {
5543
5544
  makeBuiltins,
@@ -7930,217 +7931,6 @@ function unifyTriple(pat, fact, subst) {
7930
7931
  return s3;
7931
7932
  }
7932
7933
 
7933
-
7934
- function __copyProofSourceMetadata(from, to) {
7935
- if (!from || !to) return to;
7936
- for (const key of ['__sourceOffset', '__source']) {
7937
- if (hasOwn.call(from, key)) {
7938
- Object.defineProperty(to, key, {
7939
- value: from[key],
7940
- enumerable: false,
7941
- writable: false,
7942
- configurable: true,
7943
- });
7944
- }
7945
- }
7946
- return to;
7947
- }
7948
-
7949
- function __standardizeRuleForProof(rule, gen) {
7950
- const proofVarNames = Object.create(null);
7951
-
7952
- function renameTerm(t, vmapName, vmapVar, genArr) {
7953
- if (t instanceof Var) {
7954
- if (!hasOwn.call(vmapVar, t.name)) {
7955
- const name = `${t.name}__proof_${genArr[0]}`;
7956
- genArr[0] += 1;
7957
- vmapName[t.name] = name;
7958
- vmapVar[t.name] = new Var(name);
7959
- proofVarNames[name] = t.name;
7960
- }
7961
- return vmapVar[t.name];
7962
- }
7963
- if (t instanceof ListTerm) {
7964
- let changed = false;
7965
- const elems2 = t.elems.map((e) => {
7966
- const e2 = renameTerm(e, vmapName, vmapVar, genArr);
7967
- if (e2 !== e) changed = true;
7968
- return e2;
7969
- });
7970
- return changed ? new ListTerm(elems2) : t;
7971
- }
7972
- if (t instanceof OpenListTerm) {
7973
- let changed = false;
7974
- const newXs = t.prefix.map((e) => {
7975
- const e2 = renameTerm(e, vmapName, vmapVar, genArr);
7976
- if (e2 !== e) changed = true;
7977
- return e2;
7978
- });
7979
- if (!hasOwn.call(vmapName, t.tailVar)) {
7980
- const name = `${t.tailVar}__proof_${genArr[0]}`;
7981
- genArr[0] += 1;
7982
- vmapName[t.tailVar] = name;
7983
- vmapVar[t.tailVar] = new Var(name);
7984
- proofVarNames[name] = t.tailVar;
7985
- }
7986
- const newTail = vmapName[t.tailVar];
7987
- if (newTail !== t.tailVar) changed = true;
7988
- return changed ? new OpenListTerm(newXs, newTail) : t;
7989
- }
7990
- if (t instanceof GraphTerm) {
7991
- let changed = false;
7992
- const triples2 = t.triples.map((tr) => {
7993
- const s2 = renameTerm(tr.s, vmapName, vmapVar, genArr);
7994
- const p2 = renameTerm(tr.p, vmapName, vmapVar, genArr);
7995
- const o2 = renameTerm(tr.o, vmapName, vmapVar, genArr);
7996
- if (s2 !== tr.s || p2 !== tr.p || o2 !== tr.o) changed = true;
7997
- return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
7998
- });
7999
- return changed ? copyQuotedGraphMetadata(t, new GraphTerm(triples2)) : t;
8000
- }
8001
- return t;
8002
- }
8003
-
8004
- const vmapName = Object.create(null);
8005
- const vmapVar = Object.create(null);
8006
- const premise = rule.premise.map((tr) => {
8007
- const s2 = renameTerm(tr.s, vmapName, vmapVar, gen);
8008
- const p2 = renameTerm(tr.p, vmapName, vmapVar, gen);
8009
- const o2 = renameTerm(tr.o, vmapName, vmapVar, gen);
8010
- return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
8011
- });
8012
- const conclusion = rule.conclusion.map((tr) => {
8013
- const s2 = renameTerm(tr.s, vmapName, vmapVar, gen);
8014
- const p2 = renameTerm(tr.p, vmapName, vmapVar, gen);
8015
- const o2 = renameTerm(tr.o, vmapName, vmapVar, gen);
8016
- return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
8017
- });
8018
- const out = new Rule(premise, conclusion, rule.isForward, rule.isFuse, rule.headBlankLabels);
8019
- Object.defineProperty(out, '__proofVarSourceNames', {
8020
- value: proofVarNames,
8021
- enumerable: false,
8022
- writable: false,
8023
- configurable: true,
8024
- });
8025
- return __copyProofSourceMetadata(rule, out);
8026
- }
8027
-
8028
- function __mergeProofSubst(base, delta) {
8029
- const out = __cloneSubst(base);
8030
- for (const k in delta || {}) {
8031
- if (!hasOwn.call(delta, k)) continue;
8032
- const v = applySubstTerm(delta[k], out);
8033
- if (hasOwn.call(out, k)) {
8034
- if (!termsEqual(applySubstTerm(out[k], out), v)) return null;
8035
- } else {
8036
- out[k] = v;
8037
- }
8038
- }
8039
- return out;
8040
- }
8041
-
8042
- function __sourceSortKey(obj) {
8043
- const src = obj && obj.__source;
8044
- const label = src && typeof src.label === 'string' ? src.label : '';
8045
- const line = src && Number.isInteger(src.line) ? src.line : 0;
8046
- return `${label}\t${line}`;
8047
- }
8048
-
8049
- function __candidateFactsForProof(facts, goal) {
8050
- if (!Array.isArray(facts)) return [];
8051
- ensureFactIndexes(facts);
8052
- const candidates = candidateFacts(facts, goal);
8053
- if (!candidates) return facts;
8054
- const out = [];
8055
- for (let i = 0; i < candidates.exactLen; i++) out.push(facts[candidates.exact[i]]);
8056
- for (let i = 0; i < candidates.wildLen; i++) out.push(facts[candidates.wild[i]]);
8057
- return out;
8058
- }
8059
-
8060
- function findBackwardProofForGoal(goal, facts, backRules, opts = {}) {
8061
- const maxDepth = Number.isInteger(opts.maxDepth) && opts.maxDepth > 0 ? opts.maxDepth : 64;
8062
- const varGen = [0];
8063
-
8064
- function proofKey(tr) {
8065
- return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
8066
- }
8067
-
8068
- function proveGoal(goal0, subst, depth, visited) {
8069
- if (depth > maxDepth) return [];
8070
- const g = applySubstTriple(goal0, subst);
8071
- const key = proofKey(g);
8072
- if (visited.has(key)) return [];
8073
-
8074
- if (isBuiltinPred(g.p)) {
8075
- const builtinGoalForEval = g.p instanceof Iri && g.p.value === LOG_NS + 'rawType' ? goal0 : g;
8076
- const builtinSubstForEval = g.p instanceof Iri && g.p.value === LOG_NS + 'rawType' ? subst : __emptySubst();
8077
- const deltas = evalBuiltin(builtinGoalForEval, builtinSubstForEval, facts, backRules, depth, varGen, 1) || [];
8078
- const out = [];
8079
- for (const delta of deltas) {
8080
- const subst2 = __mergeProofSubst(subst, delta);
8081
- if (subst2 === null) continue;
8082
- const fact = applySubstTriple(g, subst2);
8083
- out.push({ subst: subst2, proof: { kind: 'builtin', fact, builtin: fact.p } });
8084
- break;
8085
- }
8086
- return out;
8087
- }
8088
-
8089
- const factResults = [];
8090
- for (const f of __candidateFactsForProof(facts, g)) {
8091
- const subst2 = unifyTriple(g, f, subst);
8092
- if (subst2 === null) continue;
8093
- factResults.push({ subst: subst2, proof: { kind: 'fact', fact: applySubstTriple(f, subst2), source: f.__source } });
8094
- break;
8095
- }
8096
- if (factResults.length) return factResults;
8097
-
8098
- if (!(g.p instanceof Iri)) return [];
8099
- ensureBackRuleIndexes(backRules);
8100
- const rules = (backRules.__byHeadPred.get(g.p.__tid) || []).concat(backRules.__wildHeadPred || []);
8101
- rules.sort((a, b) => (__sourceSortKey(a) < __sourceSortKey(b) ? -1 : __sourceSortKey(a) > __sourceSortKey(b) ? 1 : 0));
8102
-
8103
- const visited2 = new Set(visited);
8104
- visited2.add(key);
8105
-
8106
- for (const r of rules) {
8107
- if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
8108
- const rStd = __standardizeRuleForProof(r, varGen);
8109
- const head = rStd.conclusion[0];
8110
- if (head.p instanceof Iri && head.p.__tid !== g.p.__tid) continue;
8111
- const subst1 = unifyTriple(head, g, subst);
8112
- if (subst1 === null) continue;
8113
- const bodyProof = proveGoalList(rStd.premise || [], subst1, depth + 1, visited2);
8114
- if (!bodyProof) continue;
8115
- const fact = applySubstTriple(g, bodyProof.subst);
8116
- const premises = (rStd.premise || []).map((prem) => applySubstTriple(prem, bodyProof.subst));
8117
- const df = new DerivedFact(fact, rStd, premises, bodyProof.subst);
8118
- return [{ subst: bodyProof.subst, proof: { kind: 'rule', df, children: bodyProof.proofs } }];
8119
- }
8120
-
8121
- return [];
8122
- }
8123
-
8124
- function proveGoalList(goals, subst, depth, visited) {
8125
- let states = [{ subst, proofs: [] }];
8126
- for (const goal1 of goals || []) {
8127
- const next = [];
8128
- for (const state of states) {
8129
- const proofs = proveGoal(goal1, state.subst, depth, visited);
8130
- for (const pr of proofs) next.push({ subst: pr.subst, proofs: state.proofs.concat([pr.proof]) });
8131
- }
8132
- if (!next.length) return null;
8133
- // Keep proof reconstruction deterministic and cheap: one proof is enough
8134
- // for an explanation of the already-derived enclosing fact.
8135
- states = [next[0]];
8136
- }
8137
- return states[0] || { subst, proofs: [] };
8138
- }
8139
-
8140
- const found = proveGoal(goal, __emptySubst(), 0, new Set());
8141
- return found.length ? found[0].proof : null;
8142
- }
8143
-
8144
7934
  // Strategy: when the substitution is "large" or search depth is high,
8145
7935
  // keep only bindings that are still relevant to:
8146
7936
  // - variables appearing in the remaining goals
@@ -8862,6 +8652,120 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
8862
8652
  return results;
8863
8653
  }
8864
8654
 
8655
+
8656
+ // Reconstruct one backward proof for N3 proof output. This is intentionally
8657
+ // called only by renderProofDocument(), so normal reasoning does not pay for it.
8658
+ function __proofTripleKey(tr) {
8659
+ if (!tr) return '';
8660
+ return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
8661
+ }
8662
+
8663
+ function __copyProofSource(from, to) {
8664
+ if (from && to && Object.prototype.hasOwnProperty.call(from, '__source')) {
8665
+ Object.defineProperty(to, '__source', {
8666
+ value: from.__source,
8667
+ enumerable: false,
8668
+ writable: false,
8669
+ configurable: true,
8670
+ });
8671
+ }
8672
+ return to;
8673
+ }
8674
+
8675
+ function __annotateProofVarSourceNames(rule) {
8676
+ if (!rule) return rule;
8677
+ const sourceNames = Object.create(null);
8678
+ for (const name of varsInRule(rule)) {
8679
+ const m = /^(.*)__\d+$/.exec(name);
8680
+ sourceNames[name] = m ? m[1] : name;
8681
+ }
8682
+ Object.defineProperty(rule, '__proofVarSourceNames', {
8683
+ value: sourceNames,
8684
+ enumerable: false,
8685
+ writable: false,
8686
+ configurable: true,
8687
+ });
8688
+ return rule;
8689
+ }
8690
+
8691
+ function findBackwardProofForGoal(goal, facts, backRules, opts = {}) {
8692
+ const maxDepth = Number.isInteger(opts.maxDepth) && opts.maxDepth >= 0 ? opts.maxDepth : 64;
8693
+ const varGen = Array.isArray(opts.varGen) ? opts.varGen : [1];
8694
+ const visited = opts.visited instanceof Set ? opts.visited : new Set();
8695
+ const factList = Array.isArray(facts) ? facts : [];
8696
+ const ruleList = Array.isArray(backRules) ? backRules : [];
8697
+
8698
+ function matchingBaseFact(g) {
8699
+ const candidates = g && g.p instanceof Iri ? candidateFacts(factList, g) : null;
8700
+ const total = candidates ? candidates.totalLen : factList.length;
8701
+ for (let i = 0; i < total; i++) {
8702
+ let f;
8703
+ if (candidates) {
8704
+ if (i < candidates.exactLen) f = factList[candidates.exact[i]];
8705
+ else f = factList[candidates.wild[i - candidates.exactLen]];
8706
+ } else {
8707
+ f = factList[i];
8708
+ }
8709
+ if (unifyTriple(g, f, __emptySubst()) !== null) return f;
8710
+ }
8711
+ return null;
8712
+ }
8713
+
8714
+ function builtinProof(g) {
8715
+ if (!(g && isBuiltinPred(g.p))) return null;
8716
+ return { kind: 'builtin', fact: g, builtin: g.p };
8717
+ }
8718
+
8719
+ function solve(g, depth) {
8720
+ if (!g || depth > maxDepth) return null;
8721
+
8722
+ const base = matchingBaseFact(g);
8723
+ if (base) return { kind: 'fact', fact: base, source: base.__source };
8724
+
8725
+ const builtin = builtinProof(g);
8726
+ if (builtin) return builtin;
8727
+
8728
+ if (!(g.p instanceof Iri)) return null;
8729
+ const gKey = __proofTripleKey(g);
8730
+ if (visited.has(gKey)) return null;
8731
+ visited.add(gKey);
8732
+
8733
+ try {
8734
+ ensureBackRuleIndexes(ruleList);
8735
+ const candRules = (ruleList.__byHeadPred.get(g.p.__tid) || []).concat(ruleList.__wildHeadPred);
8736
+ for (const r of candRules) {
8737
+ if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
8738
+ const rawHead = r.conclusion[0];
8739
+ if (rawHead.p instanceof Iri && rawHead.p.__tid !== g.p.__tid) continue;
8740
+
8741
+ const rStd = __annotateProofVarSourceNames(__copyProofSource(r, standardizeRule(r, varGen)));
8742
+ const head = rStd.conclusion[0];
8743
+ const s0 = unifyTriple(head, g, __emptySubst());
8744
+ if (s0 === null) continue;
8745
+
8746
+ const solutions = proveGoals(rStd.premise, s0, factList, ruleList, depth + 1, [], varGen, 1, {
8747
+ keepVars: varsInRule(rStd),
8748
+ deferBuiltins: true,
8749
+ });
8750
+ if (!solutions.length) continue;
8751
+
8752
+ const subst = solutions[0];
8753
+ const fact = applySubstTriple(head, subst);
8754
+ const premises = rStd.premise.map((prem) => applySubstTriple(prem, subst));
8755
+ const df = new DerivedFact(fact, rStd, premises, __cloneSubst(subst));
8756
+ const children = premises.map((prem) => builtinProof(prem) || solve(prem, depth + 1));
8757
+ return { kind: 'rule', df, children };
8758
+ }
8759
+ } finally {
8760
+ visited.delete(gKey);
8761
+ }
8762
+
8763
+ return null;
8764
+ }
8765
+
8766
+ return solve(goal, 0);
8767
+ }
8768
+
8865
8769
  // ===========================================================================
8866
8770
  // Forward chaining to fixpoint
8867
8771
  // ===========================================================================
@@ -9543,12 +9447,22 @@ function reasonStream(input, opts = {}) {
9543
9447
  skipUnsupportedRdfJs = false,
9544
9448
  builtinModules = null,
9545
9449
  rdf = false,
9450
+ sourceLabel = '<input>',
9546
9451
  } = opts;
9547
9452
 
9548
9453
  const useRdfCompatibility = !!rdf;
9549
9454
 
9550
- const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility });
9551
- const parsedInput = parsedSourceList || normalizeParsedReasonerInputSync(input);
9455
+ const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility, sourceLocations: proof });
9456
+ const parsedTextInput = (!parsedSourceList && proof && typeof input === 'string')
9457
+ ? parseN3Text(input, {
9458
+ baseIri: baseIri || '',
9459
+ label: sourceLabel || '<input>',
9460
+ keepSourceArtifacts: false,
9461
+ sourceLocations: true,
9462
+ rdf: useRdfCompatibility,
9463
+ })
9464
+ : null;
9465
+ const parsedInput = parsedSourceList || parsedTextInput || normalizeParsedReasonerInputSync(input);
9552
9466
  const rdfFactory = rdfjs ? getDataFactory(dataFactory) : null;
9553
9467
 
9554
9468
  const __oldEnforceHttps = deref.getEnforceHttpsEnabled();
@@ -9658,7 +9572,7 @@ function reasonStream(input, opts = {}) {
9658
9572
  const closureN3 = proof
9659
9573
  ? renderProofDocument(
9660
9574
  Array.isArray(logQueryRules) && logQueryRules.length ? queryDerived : derived,
9661
- derived,
9575
+ derived.concat(queryDerived || []),
9662
9576
  triples,
9663
9577
  prefixes,
9664
9578
  brules,
@@ -9711,7 +9625,7 @@ function reasonRdfJs(input, opts = {}) {
9711
9625
 
9712
9626
  Promise.resolve().then(async () => {
9713
9627
  try {
9714
- const normalizedInput = parseN3SourceList(input, restOpts) || (await normalizeReasonerInputAsync(input));
9628
+ const normalizedInput = parseN3SourceList(input, { ...restOpts, sourceLocations: !!(restOpts.proof || restOpts.proofComments) }) || (await normalizeReasonerInputAsync(input));
9715
9629
  reasonStream(normalizedInput, {
9716
9630
  ...restOpts,
9717
9631
  rdfjs: false,
@@ -10020,7 +9934,6 @@ ${lineIndent(body, ' ')}
10020
9934
  }`;
10021
9935
  }
10022
9936
 
10023
-
10024
9937
  function clonePrefixEnvWithProofVocabulary(prefixes) {
10025
9938
  const map = { ...(prefixes && prefixes.map ? prefixes.map : {}) };
10026
9939
  if (!map.pe) map.pe = PE_NS;
@@ -10038,6 +9951,11 @@ ${lineIndent(body, ' ')}
10038
9951
  return source.label.replace(/\\/g, '/').split('/').pop() || source.label;
10039
9952
  }
10040
9953
 
9954
+ function sourceKeyForProof(source) {
9955
+ if (!source) return '<unknown>';
9956
+ return `${sourceLabelForProof(source)}:${Number.isInteger(source.line) ? source.line : ''}`;
9957
+ }
9958
+
10041
9959
  function byBlankNode(kind, source) {
10042
9960
  const src = source || {};
10043
9961
  const props = [`pe:${kind} ${n3String(sourceLabelForProof(src))}`];
@@ -10045,121 +9963,129 @@ ${lineIndent(body, ' ')}
10045
9963
  return `[ ${props.join('; ')} ]`;
10046
9964
  }
10047
9965
 
10048
- function renderBindingList(df, prefixes) {
10049
- if (!df || !df.rule || !df.subst) return '';
9966
+ function renderBindingItems(df, prefixes) {
9967
+ if (!df || !df.rule || !df.subst) return [];
10050
9968
  const ruleVars = varsInRule(df.rule);
10051
9969
  const visibleNames = Object.keys(df.subst)
10052
9970
  .filter((name) => ruleVars.has(name))
10053
9971
  .sort();
10054
- if (!visibleNames.length) return '';
9972
+ if (!visibleNames.length) return [];
10055
9973
  const sourceNames = (df.rule && df.rule.__proofVarSourceNames) || null;
10056
- return visibleNames
10057
- .map((name) => {
10058
- const value = applySubstTerm(new Var(name), df.subst);
10059
- const displayName = sourceNames && sourceNames[name] ? sourceNames[name] : name;
10060
- return `[ pe:var ${n3String(displayName)}; pe:value ${termToN3(value, prefixes)} ]`;
10061
- })
10062
- .join(', ');
9974
+ return visibleNames.map((name) => {
9975
+ const value = applySubstTerm(new Var(name), df.subst);
9976
+ const displayName = sourceNames && sourceNames[name] ? sourceNames[name] : name;
9977
+ return `[ pe:var ${n3String(displayName)}; pe:value ${termToN3(value, prefixes)} ]`;
9978
+ });
10063
9979
  }
10064
9980
 
10065
- function proofSourceKey(source) {
10066
- if (!source) return '';
10067
- const label = typeof source.label === 'string' ? source.label : '';
10068
- const line = Number.isInteger(source.line) ? source.line : 0;
10069
- return `${label}\t${line}`;
9981
+ function withLastLineSuffix(text, suffix) {
9982
+ const lines = String(text).split(/\r?\n/);
9983
+ lines[lines.length - 1] += suffix;
9984
+ return lines.join('\n');
10070
9985
  }
10071
9986
 
10072
- function proofEntryKey(kind, fact, source, extra) {
10073
- return `${kind}\t${proofTripleKey(fact)}\t${proofSourceKey(source)}\t${extra || ''}`;
9987
+ function renderPredicateObjects(predicate, objects, isLast) {
9988
+ const values = (objects || []).filter((value) => value);
9989
+ if (!values.length) return [];
9990
+ const end = isLast ? '.' : ';';
9991
+ if (values.length === 1 && !values[0].includes('\n')) {
9992
+ return [` ${predicate} ${values[0]}${end}`];
9993
+ }
9994
+ const out = [` ${predicate}`];
9995
+ for (let i = 0; i < values.length; i++) {
9996
+ const suffix = i === values.length - 1 ? end : ',';
9997
+ out.push(lineIndent(withLastLineSuffix(values[i], suffix), ' '));
9998
+ }
9999
+ return out;
10074
10000
  }
10075
10001
 
10076
- function ruleEntryKey(df) {
10077
- const rule = df && df.rule;
10078
- const premises = (df && df.premises ? df.premises : []).map((prem) => proofTripleKey(prem)).join('\t');
10079
- return proofEntryKey('rule', df && df.fact, rule && rule.__source, premises);
10002
+ function proofEntryKey(entry) {
10003
+ if (!entry) return '';
10004
+ if (entry.kind === 'rule') {
10005
+ const df = entry.df;
10006
+ const source = df && df.rule && df.rule.__source;
10007
+ const premiseKey = (df && df.premises ? df.premises : []).map(proofTripleKey).join('|');
10008
+ return `rule:${proofTripleKey(df && df.fact)}:${sourceKeyForProof(source)}:${premiseKey}`;
10009
+ }
10010
+ if (entry.kind === 'builtin') return `builtin:${proofTripleKey(entry.fact)}`;
10011
+ return `fact:${proofTripleKey(entry.fact)}:${sourceKeyForProof(entry.source)}`;
10080
10012
  }
10081
10013
 
10082
10014
  function collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof) {
10083
10015
  const entries = [];
10084
10016
  const seen = new Set();
10085
10017
 
10086
- function entryKeyForProof(proof, fallbackTriple) {
10087
- if (!proof) return proofEntryKey('fact', fallbackTriple, null);
10088
- if (proof.kind === 'rule') return ruleEntryKey(proof.df);
10089
- if (proof.kind === 'builtin') return proofEntryKey('builtin', proof.fact || fallbackTriple, null);
10090
- return proofEntryKey('fact', proof.fact || fallbackTriple, proof.source);
10018
+ function remember(entry) {
10019
+ const key = proofEntryKey(entry);
10020
+ if (!key || seen.has(key)) return false;
10021
+ seen.add(key);
10022
+ entries.push(entry);
10023
+ return true;
10024
+ }
10025
+
10026
+ function derivedCandidatesForKey(key) {
10027
+ const found = derivedByKey.get(key);
10028
+ if (!found) return [];
10029
+ return Array.isArray(found) ? found : [found];
10091
10030
  }
10092
10031
 
10093
- function visitProofNode(proof, fallbackTriple) {
10032
+ function visitProofNode(proof, fallbackTriple, parentDf) {
10094
10033
  if (!proof) {
10095
- visitFactTriple(fallbackTriple);
10034
+ visitFactTriple(fallbackTriple, parentDf);
10096
10035
  return;
10097
10036
  }
10098
- const key = entryKeyForProof(proof, fallbackTriple);
10099
- if (!key || seen.has(key)) return;
10100
10037
  if (proof.kind === 'rule' && proof.df) {
10101
10038
  visitDerivedFact(proof.df, proof.children || null);
10102
10039
  return;
10103
10040
  }
10104
- seen.add(key);
10105
10041
  if (proof.kind === 'builtin') {
10106
- entries.push({
10107
- kind: 'builtin',
10108
- fact: proof.fact || fallbackTriple,
10109
- builtin: proof.builtin || (proof.fact && proof.fact.p),
10110
- });
10111
- } else {
10112
- entries.push({ kind: 'fact', fact: proof.fact || fallbackTriple, source: proof.source });
10042
+ remember({ kind: 'builtin', fact: proof.fact || fallbackTriple, builtin: proof.builtin || (proof.fact && proof.fact.p) });
10043
+ return;
10113
10044
  }
10045
+ remember({ kind: 'fact', fact: proof.fact || fallbackTriple, source: proof.source });
10114
10046
  }
10115
10047
 
10116
- function visitFactTriple(tr) {
10117
- const tripleKey = proofTripleKey(tr);
10118
- if (!tripleKey) return;
10119
- const df = derivedByKey.get(tripleKey);
10120
- if (df) {
10121
- visitDerivedFact(df);
10048
+ function visitFactTriple(tr, parentDf) {
10049
+ const key = proofTripleKey(tr);
10050
+ const base = baseFactByKey.get(key) || null;
10051
+ if (base) {
10052
+ remember({ kind: 'fact', fact: base, source: base.__source });
10122
10053
  return;
10123
10054
  }
10124
- const base = baseFactByKey.get(tripleKey) || null;
10125
- if (base) {
10126
- const key = proofEntryKey('fact', base, base.__source);
10127
- if (seen.has(key)) return;
10128
- seen.add(key);
10129
- entries.push({ kind: 'fact', fact: base, source: base.__source });
10055
+
10056
+ const candidates = derivedCandidatesForKey(key);
10057
+ const df = candidates.find((candidate) => candidate !== parentDf) || null;
10058
+ if (df) {
10059
+ visitDerivedFact(df);
10130
10060
  return;
10131
10061
  }
10062
+
10132
10063
  if (tr && isBuiltinPred(tr.p)) {
10133
- const key = proofEntryKey('builtin', tr, null);
10134
- if (seen.has(key)) return;
10135
- seen.add(key);
10136
- entries.push({ kind: 'builtin', fact: tr, builtin: tr.p });
10064
+ remember({ kind: 'builtin', fact: tr, builtin: tr.p });
10137
10065
  return;
10138
10066
  }
10067
+
10139
10068
  if (resolveBackwardProof) {
10140
10069
  const proof = resolveBackwardProof(tr);
10141
10070
  if (proof) {
10142
- visitProofNode(proof, tr);
10071
+ visitProofNode(proof, tr, parentDf);
10143
10072
  return;
10144
10073
  }
10145
10074
  }
10146
- const key = proofEntryKey('fact', tr, null);
10147
- if (seen.has(key)) return;
10148
- seen.add(key);
10149
- entries.push({ kind: 'fact', fact: tr, source: null });
10075
+
10076
+ remember({ kind: 'fact', fact: tr, source: null });
10150
10077
  }
10151
10078
 
10152
10079
  function visitDerivedFact(df, children) {
10153
- const key = ruleEntryKey(df);
10154
- if (!key || seen.has(key)) return;
10155
- seen.add(key);
10156
- entries.push({ kind: 'rule', df });
10080
+ if (!df || !df.fact) return;
10081
+ const entry = { kind: 'rule', df };
10082
+ if (!remember(entry)) return;
10157
10083
 
10158
10084
  if (Array.isArray(children) && children.length) {
10159
- for (const child of children) visitProofNode(child);
10085
+ for (const child of children) visitProofNode(child, null, df);
10160
10086
  return;
10161
10087
  }
10162
- for (const prem of df.premises || []) visitFactTriple(prem);
10088
+ for (const prem of df.premises || []) visitFactTriple(prem, df);
10163
10089
  }
10164
10090
 
10165
10091
  visitDerivedFact(rootDf);
@@ -10189,16 +10115,18 @@ ${lineIndent(body, ' ')}
10189
10115
  }
10190
10116
 
10191
10117
  const df = entry.df;
10192
- const props = [`pe:by ${byBlankNode('rule', df.rule && df.rule.__source)}`];
10193
- const bindings = renderBindingList(df, prefixes);
10194
- if (bindings) props.push(`pe:binding ${bindings}`);
10195
- if (df.premises && df.premises.length) {
10196
- props.push(`pe:uses ${df.premises.map((prem) => graphForTriple(prem, prefixes)).join(', ')}`);
10197
- }
10118
+ const bindingItems = renderBindingItems(df, prefixes);
10119
+ const useItems = (df.premises || []).map((prem) => graphForTriple(prem, prefixes));
10120
+ const propertyGroups = [
10121
+ { predicate: 'pe:by', objects: [byBlankNode('rule', df.rule && df.rule.__source)] },
10122
+ { predicate: 'pe:binding', objects: bindingItems },
10123
+ { predicate: 'pe:uses', objects: useItems },
10124
+ ].filter((group) => group.objects.length);
10198
10125
 
10199
10126
  let out = ` ${graphForTriple(df.fact, prefixes)}\n`;
10200
- for (let i = 0; i < props.length; i++) {
10201
- out += ` ${props[i]}${i === props.length - 1 ? '.' : ';'}\n`;
10127
+ for (let i = 0; i < propertyGroups.length; i++) {
10128
+ const group = propertyGroups[i];
10129
+ out += renderPredicateObjects(group.predicate, group.objects, i === propertyGroups.length - 1).join('\n') + '\n';
10202
10130
  }
10203
10131
  return out.trimEnd();
10204
10132
  }
@@ -10219,13 +10147,18 @@ ${proofBody}
10219
10147
 
10220
10148
  const proofPrefixes = clonePrefixEnvWithProofVocabulary(prefixes);
10221
10149
  const derivedByKey = new Map();
10222
- for (const df of allDerived || []) {
10223
- if (!df || !df.fact) continue;
10150
+ function addDerived(df) {
10151
+ if (!df || !df.fact) return;
10224
10152
  const key = proofTripleKey(df.fact);
10225
- if (!derivedByKey.has(key)) derivedByKey.set(key, df);
10153
+ let bucket = derivedByKey.get(key);
10154
+ if (!bucket) {
10155
+ bucket = [];
10156
+ derivedByKey.set(key, bucket);
10157
+ }
10158
+ if (!bucket.includes(df)) bucket.push(df);
10226
10159
  }
10227
- // Do not insert query-wrapper output facts here: those wrappers often derive
10228
- // the same triple they use, and would hide the underlying fact/rule proof.
10160
+ for (const df of allDerived || []) addDerived(df);
10161
+ for (const df of selectedDerived) addDerived(df);
10229
10162
 
10230
10163
  const baseFactByKey = new Map();
10231
10164
  for (const tr of baseFacts || []) {
@@ -12173,20 +12106,20 @@ function emptyParsedDocument() {
12173
12106
  }
12174
12107
 
12175
12108
  function lineStartsForText(text) {
12176
- const s = String(text);
12177
12109
  const starts = [0];
12178
- for (let i = 0; i < s.length; i++) {
12179
- const c = s.charCodeAt(i);
12180
- if (c === 10) starts.push(i + 1); // LF
12181
- else if (c === 13) { // CR or CRLF
12182
- if (i + 1 < s.length && s.charCodeAt(i + 1) === 10) i++;
12183
- starts.push(i + 1);
12110
+ const str = String(text);
12111
+ for (let i = 0; i < str.length; i++) {
12112
+ const c = str[i];
12113
+ if (c === '\n') starts.push(i + 1);
12114
+ else if (c === '\r') {
12115
+ starts.push(i + 1 < str.length && str[i + 1] === '\n' ? i + 2 : i + 1);
12116
+ if (i + 1 < str.length && str[i + 1] === '\n') i++;
12184
12117
  }
12185
12118
  }
12186
12119
  return starts;
12187
12120
  }
12188
12121
 
12189
- function offsetToLineFromStarts(offset, lineStarts) {
12122
+ function offsetToLine(lineStarts, offset) {
12190
12123
  if (typeof offset !== 'number') return null;
12191
12124
  let lo = 0;
12192
12125
  let hi = lineStarts.length;
@@ -12198,9 +12131,9 @@ function offsetToLineFromStarts(offset, lineStarts) {
12198
12131
  return lo + 1;
12199
12132
  }
12200
12133
 
12201
- function annotateSourceLocation(obj, label, lineStarts) {
12134
+ function annotateSourceLocation(obj, lineStarts, label) {
12202
12135
  if (!obj || typeof obj.__sourceOffset !== 'number') return obj;
12203
- const line = offsetToLineFromStarts(obj.__sourceOffset, lineStarts);
12136
+ const line = offsetToLine(lineStarts, obj.__sourceOffset);
12204
12137
  Object.defineProperty(obj, '__source', {
12205
12138
  value: { label, line },
12206
12139
  enumerable: false,
@@ -12212,10 +12145,10 @@ function annotateSourceLocation(obj, label, lineStarts) {
12212
12145
 
12213
12146
  function annotateParsedSourceLocations(doc, text, label) {
12214
12147
  const lineStarts = lineStartsForText(text);
12215
- for (const tr of doc.triples || []) annotateSourceLocation(tr, label, lineStarts);
12216
- for (const r of doc.frules || []) annotateSourceLocation(r, label, lineStarts);
12217
- for (const r of doc.brules || []) annotateSourceLocation(r, label, lineStarts);
12218
- for (const r of doc.logQueryRules || []) annotateSourceLocation(r, label, lineStarts);
12148
+ for (const tr of doc.triples || []) annotateSourceLocation(tr, lineStarts, label);
12149
+ for (const r of doc.frules || []) annotateSourceLocation(r, lineStarts, label);
12150
+ for (const r of doc.brules || []) annotateSourceLocation(r, lineStarts, label);
12151
+ for (const r of doc.logQueryRules || []) annotateSourceLocation(r, lineStarts, label);
12219
12152
  }
12220
12153
 
12221
12154
  function copySourceMetadata(from, to) {
@@ -12310,7 +12243,7 @@ function parseN3Text(text, opts = {}) {
12310
12243
  label = '<input>',
12311
12244
  keepSourceArtifacts = true,
12312
12245
  collectUsedPrefixes = false,
12313
- collectSourceLocations = true,
12246
+ sourceLocations = false,
12314
12247
  rdf = false,
12315
12248
  } = opts || {};
12316
12249
  const tokens = lex(text, { rdf });
@@ -12319,7 +12252,7 @@ function parseN3Text(text, opts = {}) {
12319
12252
  const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
12320
12253
 
12321
12254
  const doc = { prefixes, triples, frules, brules, logQueryRules, label };
12322
- if (collectSourceLocations) annotateParsedSourceLocations(doc, text, label);
12255
+ if (sourceLocations) annotateParsedSourceLocations(doc, text, label);
12323
12256
 
12324
12257
  if (collectUsedPrefixes) {
12325
12258
  Object.defineProperty(doc, 'usedPrefixes', {
@@ -12510,8 +12443,8 @@ function parseN3SourceList(input, opts = {}) {
12510
12443
  label: source.label,
12511
12444
  baseIri: source.baseIri || (sources.length === 1 ? defaultBaseIri : ''),
12512
12445
  collectUsedPrefixes: true,
12513
- collectSourceLocations: !!opts.collectSourceLocations,
12514
12446
  keepSourceArtifacts: !!opts.keepSourceArtifacts,
12447
+ sourceLocations: !!opts.sourceLocations,
12515
12448
  rdf: !!opts.rdf,
12516
12449
  }),
12517
12450
  );