eyeling 1.7.10 → 1.7.12

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/examples/bind.n3 CHANGED
@@ -4,4 +4,4 @@
4
4
 
5
5
  :phayes a :Person ; :givenName "Pat"; :familyName "Hayes" .
6
6
 
7
- { ?x a :Person . ?SCOPE log:notIncludes { ?x :name ?someName . } . ?x :givenName ?name1 . ?x :familyName ?name2 . (?name1 " " ?name2) string:concatenation ?FN . } => { ?x :name ?FN } .
7
+ { ?x a :Person . (1 { ?x :name ?someName . } ()) log:collectAllIn ?SCOPE . ?x :givenName ?name1 . ?x :familyName ?name2 . (?name1 " " ?name2) string:concatenation ?FN . } => { ?x :name ?FN } .
package/examples/snaf.n3 CHANGED
@@ -9,7 +9,7 @@
9
9
  :Bob a :Person.
10
10
 
11
11
  {
12
- ?SCOPE log:notIncludes { :Alice :hates ?X }.
12
+ (1 { :Alice :hates ?X } ()) log:collectAllIn ?SCOPE .
13
13
  ?X a :Person.
14
14
  }
15
15
  =>
package/eyeling.js CHANGED
@@ -16,8 +16,20 @@
16
16
  * 5) Print only newly derived forward facts with explanations.
17
17
  */
18
18
 
19
- const { version } = require('./package.json');
20
- const nodeCrypto = require('crypto');
19
+ // -----------------------------------------------------------------------------
20
+ // Browser/Worker-safe version + crypto wiring
21
+ // -----------------------------------------------------------------------------
22
+ let version = 'dev';
23
+ try {
24
+ // Node: keep package.json version if available
25
+ if (typeof require === 'function') version = require('./package.json').version || version;
26
+ } catch (_) {}
27
+
28
+ let nodeCrypto = null;
29
+ try {
30
+ // Node: crypto available
31
+ if (typeof require === 'function') nodeCrypto = require('crypto');
32
+ } catch (_) {}
21
33
 
22
34
  // ===========================================================================
23
35
  // Namespace constants
@@ -5533,62 +5545,40 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5533
5545
  return results;
5534
5546
  }
5535
5547
 
5536
- // log:includes (provable in scope)
5548
+ // log:includes
5537
5549
  // Schema: $s+ log:includes $o+
5538
- // When the subject is a formula, the scope is that concrete formula (syntactic containment).
5539
- // Otherwise, the scope is the current document scope (facts + backward rules).
5550
+ // Object may be a concrete formula or the literal `true` (empty formula).
5540
5551
  if (pv === LOG_NS + 'includes') {
5552
+ if (!(g.s instanceof GraphTerm)) return [];
5553
+
5541
5554
  // Empty formula is always included.
5542
5555
  if (g.o instanceof Literal && g.o.value === 'true') return [{ ...subst }];
5543
5556
  if (!(g.o instanceof GraphTerm)) return [];
5544
5557
 
5545
- /** @type {Triple[] | null} */
5546
- let scopeFacts = null;
5547
- /** @type {Rule[]} */
5548
- let scopeBackRules = backRules;
5549
-
5550
- // If the subject is a formula, treat it as a concrete scope graph.
5551
- // Also support `true` as the empty formula.
5552
- if (g.s instanceof GraphTerm) {
5553
- scopeFacts = g.s.triples.slice();
5554
- ensureFactIndexes(scopeFacts);
5555
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5556
- scopeBackRules = []; // concrete scope = syntactic containment (no extra rules)
5557
- } else if (g.s instanceof Literal && g.s.value === 'true') {
5558
- scopeFacts = [];
5559
- ensureFactIndexes(scopeFacts);
5560
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5561
- scopeBackRules = [];
5562
- } else {
5563
- scopeFacts = facts; // dynamic scope
5564
- }
5558
+ const scopeFacts = g.s.triples.slice();
5559
+ ensureFactIndexes(scopeFacts);
5560
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5565
5561
 
5566
5562
  const visited2 = [];
5567
5563
  // Start from the incoming substitution so bindings flow outward.
5568
- return proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
5564
+ return proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen);
5569
5565
  }
5570
5566
 
5571
- // log:notIncludes (not provable in scope)
5572
- // Delay until we have a frozen scope snapshot to avoid early success.
5567
+ // log:notIncludes
5568
+ // Schema: $s+ log:notIncludes $o+
5573
5569
  if (pv === LOG_NS + 'notIncludes') {
5574
- if (!(g.o instanceof GraphTerm)) return [];
5570
+ if (!(g.s instanceof GraphTerm)) return [];
5575
5571
 
5576
- let scopeFacts = null;
5577
- let scopeBackRules = backRules;
5572
+ // Empty formula is always included, so it is never "not included".
5573
+ if (g.o instanceof Literal && g.o.value === 'true') return [];
5574
+ if (!(g.o instanceof GraphTerm)) return [];
5578
5575
 
5579
- // If the subject is a formula, treat it as the concrete scope graph
5580
- if (g.s instanceof GraphTerm) {
5581
- scopeFacts = g.s.triples.slice();
5582
- ensureFactIndexes(scopeFacts);
5583
- Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5584
- scopeBackRules = []; // concrete scope = syntactic containment (no extra rules)
5585
- } else {
5586
- scopeFacts = facts.__scopedSnapshot || null;
5587
- if (!scopeFacts) return []; // DELAY until saturation snapshot exists
5588
- }
5576
+ const scopeFacts = g.s.triples.slice();
5577
+ ensureFactIndexes(scopeFacts);
5578
+ Object.defineProperty(scopeFacts, '__scopedSnapshot', { value: scopeFacts, enumerable: false, writable: true });
5589
5579
 
5590
5580
  const visited2 = [];
5591
- const sols = proveGoals(Array.from(g.o.triples), {}, scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
5581
+ const sols = proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen);
5592
5582
  return sols.length ? [] : [{ ...subst }];
5593
5583
  }
5594
5584
 
@@ -6259,7 +6249,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
6259
6249
  // Forward chaining to fixpoint
6260
6250
  // ===========================================================================
6261
6251
 
6262
- function forwardChain(facts, forwardRules, backRules) {
6252
+ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */) {
6263
6253
  ensureFactIndexes(facts);
6264
6254
  ensureBackRuleIndexes(backRules);
6265
6255
 
@@ -6344,7 +6334,10 @@ function forwardChain(facts, forwardRules, backRules) {
6344
6334
  if (!hasFactIndexed(facts, instantiated)) {
6345
6335
  factList.push(instantiated);
6346
6336
  pushFactIndexed(facts, instantiated);
6347
- derivedForward.push(new DerivedFact(instantiated, r, instantiatedPremises.slice(), { ...s }));
6337
+ const df = new DerivedFact(instantiated, r, instantiatedPremises.slice(), { ...s });
6338
+ derivedForward.push(df);
6339
+ if (typeof onDerived === 'function') onDerived(df);
6340
+
6348
6341
  changed = true;
6349
6342
  }
6350
6343
 
@@ -6408,7 +6401,10 @@ function forwardChain(facts, forwardRules, backRules) {
6408
6401
 
6409
6402
  factList.push(inst);
6410
6403
  pushFactIndexed(facts, inst);
6411
- derivedForward.push(new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s }));
6404
+ const df = new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s });
6405
+ derivedForward.push(df);
6406
+ if (typeof onDerived === 'function') onDerived(df);
6407
+
6412
6408
  changed = true;
6413
6409
  }
6414
6410
  }
@@ -6744,6 +6740,53 @@ function __collectOutputStringsFromFacts(facts, prefixes) {
6744
6740
  return pairs.map((p) => p.text).join('');
6745
6741
  }
6746
6742
 
6743
+ function reasonStream(n3Text, opts = {}) {
6744
+ const { baseIri = null, proof = false, onDerived = null, includeInputFactsInClosure = true } = opts;
6745
+
6746
+ proofCommentsEnabled = !!proof;
6747
+
6748
+ const toks = lex(n3Text);
6749
+ const parser = new Parser(toks);
6750
+ if (baseIri) parser.prefixes.setBase(baseIri);
6751
+
6752
+ let prefixes, triples, frules, brules;
6753
+ [prefixes, triples, frules, brules] = parser.parseDocument();
6754
+
6755
+ materializeRdfLists(triples, frules, brules);
6756
+
6757
+ // facts becomes the saturated closure because pushFactIndexed(...) appends into it
6758
+ const facts = triples.filter((tr) => isGroundTriple(tr));
6759
+
6760
+ const derived = forwardChain(facts, frules, brules, (df) => {
6761
+ if (typeof onDerived === 'function') {
6762
+ onDerived({
6763
+ triple: tripleToN3(df.fact, prefixes),
6764
+ df,
6765
+ });
6766
+ }
6767
+ });
6768
+
6769
+ const closureTriples = includeInputFactsInClosure ? facts : derived.map((d) => d.fact);
6770
+
6771
+ return {
6772
+ prefixes,
6773
+ facts, // saturated closure (Triple[])
6774
+ derived, // DerivedFact[]
6775
+ closureN3: closureTriples.map((t) => tripleToN3(t, prefixes)).join('\n'),
6776
+ };
6777
+ }
6778
+
6779
+ // Minimal export surface for Node + browser/worker
6780
+ const EYELING_API = { reasonStream };
6781
+
6782
+ try {
6783
+ if (typeof module !== 'undefined' && module.exports) module.exports = EYELING_API;
6784
+ } catch (_) {}
6785
+
6786
+ try {
6787
+ if (typeof self !== 'undefined') self.eyeling = EYELING_API;
6788
+ } catch (_) {}
6789
+
6747
6790
  function main() {
6748
6791
  // Drop "node" and script name; keep only user-provided args
6749
6792
  const argv = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.7.10",
3
+ "version": "1.7.12",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [