eyeling 1.5.15 → 1.5.16

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.
Files changed (2) hide show
  1. package/README.md +84 -63
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -4,12 +4,13 @@ A minimal [Notation3 (N3)](https://notation3.org/) reasoner in **JavaScript**.
4
4
 
5
5
  `eyeling` is:
6
6
 
7
- - a single self-contained file (`eyeling.js`, no external deps),
8
- - intentionally tiny and close in spirit to EYE,
9
- - a practical N3/Turtle superset (enough for lots of real rulesets),
10
- - supports forward (`=>`) + backward (`<=`) chaining over Horn-style rules,
11
- - prints only newly derived forward facts, optionally preceded by compact proof comments,
12
- - we never want to leak raw data, hence pass-only-new and backward rules for functions that work with raw data, and of course we also keep all reasoning in the browser.
7
+ - a single self-contained file (`eyeling.js`, no external deps)
8
+ - intentionally tiny and close in spirit to EYE
9
+ - a practical N3/Turtle superset (enough for lots of real rulesets)
10
+ - supports forward (`=>`) + backward (`<=`) chaining over Horn-style rules
11
+ - prints only newly derived forward facts, optionally preceded by compact proof comments
12
+ - we never want to leak raw data, hence pass-only-new and backward rules for functions that work with raw data
13
+ - and of course we also keep all reasoning in the browser
13
14
 
14
15
  ## Playground (in your browser)
15
16
 
@@ -18,21 +19,22 @@ Try it here:
18
19
  - [Eyeling playground](https://eyereasoner.github.io/eyeling/demo)
19
20
 
20
21
  The playground runs `eyeling` client-side. You can:
21
- - edit an N3 program directly,
22
- - load an N3 program from a URL,
23
- - share a link with the program encoded in the URL fragment (`#...`).
22
+
23
+ - edit an N3 program directly
24
+ - load an N3 program from a URL
25
+ - share a link with the program encoded in the URL fragment (`#...`)
24
26
 
25
27
  ### Example (Socrates)
26
28
 
27
29
  This link preloads a small “Socrates is Mortal” ruleset:
28
30
 
29
- [Socrates example](https://eyereasoner.github.io/eyeling/demo#%23%20------------------%0A%23%20Socrates%20inference%0A%23%20------------------%0A%0A%40prefix%20rdfs%3A%20%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E.%0A%40prefix%20%3A%20%3Chttp%3A%2F%2Fexample.org%2Fsocrates%23%3E.%0A%0A%23%20facts%0A%3ASocrates%20a%20%3AHuman.%0A%3AHuman%20rdfs%3AsubClassOf%20%3AMortal.%0A%0A%23%20subclass%20rule%0A%7B%0A%20%20%20%20%3FS%20a%20%3FA.%0A%20%20%20%20%3FA%20rdfs%3AsubClassOf%20%3FB.%0A%7D%20%3D%3E%20%7B%0A%20%20%20%20%3FS%20a%20%3FB.%0A%7D%2E%0A)
31
+ - [Socrates example](https://eyereasoner.github.io/eyeling/demo#%23%20------------------%0A%23%20Socrates%20inference%0A%23%20------------------%0A%0A%40prefix%20rdfs%3A%20%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E.%0A%40prefix%20%3A%20%3Chttp%3A%2F%2Fexample.org%2Fsocrates%23%3E.%0A%0A%23%20facts%0A%3ASocrates%20a%20%3AHuman.%0A%3AHuman%20rdfs%3AsubClassOf%20%3AMortal.%0A%0A%23%20subclass%20rule%0A%7B%0A%20%20%20%20%3FS%20a%20%3FA.%0A%20%20%20%20%3FA%20rdfs%3AsubClassOf%20%3FB.%0A%7D%20%3D%3E%20%7B%0A%20%20%20%20%3FS%20a%20%3FB.%0A%7D%2E%0A)
30
32
 
31
33
  ## Quick start (Node.js)
32
34
 
33
35
  ### Requirements
34
36
 
35
- - A reasonably recent Node.js (anything modern with `BigInt` support is fine).
37
+ - Node.js >= 18 (anything modern with `BigInt` support is fine)
36
38
 
37
39
  ### Install (npm)
38
40
 
@@ -53,7 +55,7 @@ npx eyeling examples/socrates.n3
53
55
  ### JavaScript API (Node)
54
56
 
55
57
  ```js
56
- const { reason } = require('eyeling');
58
+ const { reason } = require("eyeling");
57
59
 
58
60
  const input = `
59
61
  @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@@ -72,7 +74,7 @@ console.log(output);
72
74
  ESM:
73
75
 
74
76
  ```js
75
- import eyeling from 'eyeling';
77
+ import eyeling from "eyeling";
76
78
 
77
79
  const output = eyeling.reason({ proofComments: false }, input);
78
80
  console.log(output);
@@ -80,6 +82,28 @@ console.log(output);
80
82
 
81
83
  Note: the API currently shells out to the bundled `eyeling.js` CLI under the hood (simple + robust).
82
84
 
85
+ ### Testing
86
+
87
+ From a repo checkout:
88
+
89
+ ```bash
90
+ npm test
91
+ ```
92
+
93
+ Or run individual suites:
94
+
95
+ ```bash
96
+ npm run test:api
97
+ npm run test:examples
98
+ npm run test:package
99
+ npm run test:packlist
100
+ ```
101
+
102
+ - `test:api` runs an independent JS API test suite (does not rely on `examples/`).
103
+ - `test:examples` runs the `examples/test` runner and compares against the golden outputs in `examples/output`.
104
+ - `test:package` does a “real consumer” smoke test: `npm pack` → install tarball into a temp project → run API + CLI + examples.
105
+ - `test:packlist` sanity-checks what will be published in the npm tarball (and the CLI shebang/bin wiring).
106
+
83
107
  ### Run a single file
84
108
 
85
109
  From the repo root:
@@ -94,10 +118,10 @@ node eyeling.js examples/socrates.n3
94
118
 
95
119
  By default, `eyeling`:
96
120
 
97
- 1. parses the input (facts + rules),
98
- 2. runs **forward chaining to a fixpoint**,
99
- 3. prints only **newly derived forward facts** (not the original input facts),
100
- 4. prints a compact per-triple explanation as `#` comments (can be disabled).
121
+ 1. parses the input (facts + rules)
122
+ 2. runs **forward chaining to a fixpoint**
123
+ 3. prints only **newly derived forward facts** (not the original input facts)
124
+ 4. prints a compact per-triple explanation as `#` comments (can be disabled)
101
125
 
102
126
  ### Options
103
127
 
@@ -116,7 +140,8 @@ node eyeling.js -n examples/socrates.n3
116
140
  npm run test:examples
117
141
  ```
118
142
 
119
- This runs `eyeling.js` over each example and compares against the golden outputs in `examples/output`.
143
+ This runs `eyeling.js` over each example and compares against the golden outputs in `examples/output`
144
+ (works both in a git checkout and in an npm-installed package).
120
145
 
121
146
  ## What output do I get?
122
147
 
@@ -131,14 +156,14 @@ The proof comments are compact “local justifications” per derived triple (no
131
156
 
132
157
  ### Forward + backward chaining
133
158
 
134
- * **Forward chaining to fixpoint** for forward rules written as `{ P } => { C } .`
135
- * **Backward chaining (SLD-style)** for backward rules written as `{ H } <= { B } .` and for built-ins.
159
+ - **Forward chaining to fixpoint** for forward rules written as `{ P } => { C } .`
160
+ - **Backward chaining (SLD-style)** for backward rules written as `{ H } <= { B } .` and for built-ins.
136
161
 
137
162
  Forward rule premises are proved using:
138
163
 
139
- * ground facts (input + derived),
140
- * backward rules,
141
- * built-ins.
164
+ - ground facts (input + derived)
165
+ - backward rules
166
+ - built-ins
142
167
 
143
168
  The CLI prints only newly derived forward facts.
144
169
 
@@ -146,63 +171,59 @@ The CLI prints only newly derived forward facts.
146
171
 
147
172
  `eyeling` stays tiny, but includes a few key performance mechanisms:
148
173
 
149
- * facts are indexed for matching:
150
-
151
- * by predicate, and (when possible) by **(predicate, object)** (important for type-heavy workloads),
152
- * duplicate detection uses a fast key path when a triple is fully IRI/Literal-shaped,
153
- * backward rules are indexed by head predicate,
154
- * the backward prover is **iterative** (explicit stack), so deep chains won’t blow the JS call stack,
155
- * for very deep backward chains, substitutions may be compactified (semantics-preserving) to avoid quadratic “copy a growing substitution object” behavior.
174
+ - facts are indexed for matching:
175
+ - by predicate, and (when possible) by **(predicate, object)** (important for type-heavy workloads)
176
+ - duplicate detection uses a fast key path when a triple is fully IRI/Literal-shaped
177
+ - backward rules are indexed by head predicate
178
+ - the backward prover is **iterative** (explicit stack), so deep chains won’t blow the JS call stack
179
+ - for very deep backward chains, substitutions may be compactified (semantics-preserving) to avoid quadratic “copy a growing substitution object” behavior
156
180
 
157
181
  ## Parsing: practical N3 subset
158
182
 
159
183
  Supported:
160
184
 
161
- * `@prefix` / `@base`
162
- * triples with `;` and `,`
163
- * variables `?x`
164
- * blank nodes:
165
-
166
- * anonymous `[]`
167
- * property lists `[ :p :o; :q :r ]`
168
- * collections `( ... )`
169
- * quoted formulas `{ ... }`
170
- * implications:
171
-
172
- * forward rules `{ P } => { C } .`
173
- * backward rules `{ H } <= { B } .`
174
- * datatyped literals with `^^`
175
- * `#` line comments
185
+ - `@prefix` / `@base`
186
+ - triples with `;` and `,`
187
+ - variables `?x`
188
+ - blank nodes:
189
+ - anonymous `[]`
190
+ - property lists `[ :p :o; :q :r ]`
191
+ - collections `( ... )`
192
+ - quoted formulas `{ ... }`
193
+ - implications:
194
+ - forward rules `{ P } => { C } .`
195
+ - backward rules `{ H } <= { B } .`
196
+ - datatyped literals with `^^`
197
+ - `#` line comments
176
198
 
177
199
  Non-goals / current limits:
178
200
 
179
- * not a full W3C N3 grammar (some edge cases for identifiers, quantifiers, advanced syntax),
180
- * quoted formulas are matched as whole formulas (no pattern matching inside formulas yet),
181
- * proof output is local per derived triple (not a global exported proof tree).
201
+ - not a full W3C N3 grammar (some edge cases for identifiers, quantifiers, advanced syntax)
202
+ - quoted formulas are matched as whole formulas (no pattern matching inside formulas yet)
203
+ - proof output is local per derived triple (not a global exported proof tree)
182
204
 
183
205
  ## Blank nodes and quantification (pragmatic N3/EYE-style)
184
206
 
185
207
  `eyeling` follows the usual N3 intuition:
186
208
 
187
- 1. blank nodes in facts are normal RDF blanks (`_:b1`, `_:b2`, … within a run),
188
- 2. blank nodes in rule premises behave like rule-scoped universals (similar to variables),
189
- 3. blank nodes only in rule conclusions behave like existentials:
190
- each rule firing generates fresh Skolem blanks (`_:sk_0`, `_:sk_1`, …).
209
+ 1. blank nodes in facts are normal RDF blanks (`_:b1`, `_:b2`, … within a run)
210
+ 2. blank nodes in rule premises behave like rule-scoped universals (similar to variables)
211
+ 3. blank nodes only in rule conclusions behave like existentials: each rule firing generates fresh Skolem blanks (`_:sk_0`, `_:sk_1`, …)
191
212
 
192
213
  Equal facts up to renaming of Skolem IDs are treated as duplicates and are not re-added.
193
214
 
194
215
  ## Rule-producing rules (meta-rules)
195
216
 
196
- `eyeling` understands the `log:implies` / `log:impliedBy` idiom:
217
+ `eyeling` understands the `log:implies` / `log:impliedBy` idiom.
197
218
 
198
219
  Top level:
199
220
 
200
- * `{ P } log:implies { C } .` becomes a forward rule `{ P } => { C } .`
201
- * `{ H } log:impliedBy { B } .` becomes a backward rule `{ H } <= { B } .`
221
+ - `{ P } log:implies { C } .` becomes a forward rule `{ P } => { C } .`
222
+ - `{ H } log:impliedBy { B } .` becomes a backward rule `{ H } <= { B } .`
202
223
 
203
224
  During reasoning:
204
225
 
205
- * any **derived** `log:implies` / `log:impliedBy` triple with formula subject/object is turned into a new live forward/backward rule.
226
+ - any **derived** `log:implies` / `log:impliedBy` triple with formula subject/object is turned into a new live forward/backward rule.
206
227
 
207
228
  ## Inference fuse — `{ ... } => false.`
208
229
 
@@ -211,6 +232,7 @@ Rules whose conclusion is `false` are treated as hard failures:
211
232
  ```n3
212
233
  :stone :color :black .
213
234
  :stone :color :white .
235
+
214
236
  { ?X :color :black . ?X :color :white . } => false.
215
237
  ```
216
238
 
@@ -220,13 +242,12 @@ As soon as the premise is provable, `eyeling` exits with status code `2`.
220
242
 
221
243
  `eyeling` implements a pragmatic subset of common N3 builtin families and evaluates them during backward goal proving:
222
244
 
223
- * **crypto**: `crypto:md5` `crypto:sha` `crypto:sha256` `crypto:sha512`
224
- * **list**: `list:append` `list:first` `list:firstRest` `list:in` `list:iterate` `list:last` `list:length` `list:map` `list:member` `list:memberAt` `list:notMember` `list:remove` `list:reverse` `list:sort`
225
- * **log**: `log:collectAllIn` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:skolem` `log:uri`
226
- * **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
227
- * **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
228
- * **time**: `time:localTime`
229
-
245
+ - **crypto**: `crypto:md5` `crypto:sha` `crypto:sha256` `crypto:sha512`
246
+ - **list**: `list:append` `list:first` `list:firstRest` `list:in` `list:iterate` `list:last` `list:length` `list:map` `list:member` `list:memberAt` `list:notMember` `list:remove` `list:reverse` `list:sort`
247
+ - **log**: `log:collectAllIn` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:skolem` `log:uri`
248
+ - **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
249
+ - **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
250
+ - **time**: `time:localTime`
230
251
 
231
252
  ## License
232
253
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.5.15",
3
+ "version": "1.5.16",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [