eyeling 1.6.13 → 1.6.15

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 (77) hide show
  1. package/README.md +8 -19
  2. package/examples/output/age.n3 +0 -17
  3. package/examples/output/alignment-demo.n3 +0 -572
  4. package/examples/output/backward.n3 +0 -15
  5. package/examples/output/basic-monadic.n3 +0 -105
  6. package/examples/output/brussels-brew-club.n3 +0 -476
  7. package/examples/output/cat-koko.n3 +0 -108
  8. package/examples/output/cobalt-kepler-kitchen.n3 +0 -7064
  9. package/examples/output/complex.n3 +0 -46
  10. package/examples/output/control-system.n3 +0 -75
  11. package/examples/output/cranberry-calculus.n3 +0 -1313
  12. package/examples/output/crypto-builtins-tests.n3 +0 -60
  13. package/examples/output/deep-taxonomy-10.n3 +0 -602
  14. package/examples/output/deep-taxonomy-100.n3 +1 -5733
  15. package/examples/output/deep-taxonomy-1000.n3 +1 -57033
  16. package/examples/output/deep-taxonomy-10000.n3 +1 -570033
  17. package/examples/output/derived-backward-rule-2.n3 +0 -58
  18. package/examples/output/derived-backward-rule.n3 +0 -44
  19. package/examples/output/derived-rule.n3 +0 -42
  20. package/examples/output/dijkstra.n3 +0 -297
  21. package/examples/output/dog.n3 +0 -30
  22. package/examples/output/drone-corridor-planner.n3 +0 -799
  23. package/examples/output/easter.n3 +0 -3570
  24. package/examples/output/equals.n3 +0 -15
  25. package/examples/output/ev-roundtrip-planner.n3 +0 -392
  26. package/examples/output/existential-rule.n3 +0 -34
  27. package/examples/output/expression-eval.n3 +0 -20
  28. package/examples/output/family-cousins.n3 +0 -636
  29. package/examples/output/fibonacci.n3 +0 -36
  30. package/examples/output/french-cities.n3 +0 -484
  31. package/examples/output/good-cobbler.n3 +0 -22
  32. package/examples/output/gps.n3 +0 -62
  33. package/examples/output/gray-code-counter.n3 +0 -17
  34. package/examples/output/hanoi.n3 +0 -17
  35. package/examples/output/jade-eigen-loom.n3 +0 -4690
  36. package/examples/output/json-pointer.n3 +0 -529
  37. package/examples/output/json-reconcile-vat.n3 +0 -12882
  38. package/examples/output/light-eaters.n3 +0 -311
  39. package/examples/output/list-builtins-tests.n3 +0 -167
  40. package/examples/output/list-iterate.n3 +0 -124
  41. package/examples/output/lldm.n3 +0 -960
  42. package/examples/output/log-collect-all-in.n3 +0 -117
  43. package/examples/output/log-for-all-in.n3 +0 -27
  44. package/examples/output/log-not-includes.n3 +0 -59
  45. package/examples/output/log-skolem.n3 +0 -17
  46. package/examples/output/log-uri.n3 +0 -42
  47. package/examples/output/math-builtins-tests.n3 +0 -4434
  48. package/examples/output/minimal-skos-alignment.n3 +0 -39
  49. package/examples/output/monkey.n3 +0 -36
  50. package/examples/output/odrl-trust.n3 +0 -46
  51. package/examples/output/oslo-steps-library-scholarly.n3 +0 -1260
  52. package/examples/output/oslo-steps-workflow-composition.n3 +0 -180
  53. package/examples/output/peano.n3 +0 -23
  54. package/examples/output/pi.n3 +0 -17
  55. package/examples/output/pillar.n3 +0 -32
  56. package/examples/output/polygon.n3 +0 -17
  57. package/examples/output/rdf-list.n3 +0 -28
  58. package/examples/output/reordering.n3 +0 -26
  59. package/examples/output/ruby-runge-workshop.n3 +0 -613
  60. package/examples/output/rule-matching.n3 +0 -26
  61. package/examples/output/saffron-slopeworks.n3 +0 -1447
  62. package/examples/output/self-referential.n3 +0 -81
  63. package/examples/output/similar.n3 +0 -15
  64. package/examples/output/snaf.n3 +0 -23
  65. package/examples/output/socrates.n3 +0 -21
  66. package/examples/output/spectral-week.n3 +0 -350
  67. package/examples/output/string-builtins-tests.n3 +0 -240
  68. package/examples/output/topaz-markov-mill.n3 +0 -4178
  69. package/examples/output/traffic-skos-aggregate.n3 +0 -3151
  70. package/examples/output/turing.n3 +0 -36
  71. package/examples/output/ultramarine-simpson-forge.n3 +0 -3873
  72. package/examples/output/witch.n3 +0 -107
  73. package/examples/output/zebra.n3 +0 -111
  74. package/eyeling.js +129 -25
  75. package/index.js +13 -6
  76. package/package.json +1 -1
  77. package/test/examples.test.js +1 -1
@@ -1,115 +1,8 @@
1
1
  @prefix : <https://eyereasoner.github.io/eye/reasoning/witch#> .
2
2
 
3
- # ----------------------------------------------------------------------
4
- # Proof for derived triple:
5
- # :DUCK a :ISMADEOFWOOD .
6
- # It holds because the following instance of the rule body is provable:
7
- # :DUCK a :FLOATS .
8
- # via the schematic forward rule:
9
- # {
10
- # ?x a :FLOATS .
11
- # } => {
12
- # ?x a :ISMADEOFWOOD .
13
- # } .
14
- # with substitution (on rule variables):
15
- # ?x = :DUCK
16
- # Therefore the derived triple above is entailed by the rules and facts.
17
- # ----------------------------------------------------------------------
18
-
19
3
  :DUCK a :ISMADEOFWOOD .
20
-
21
- # ----------------------------------------------------------------------
22
- # Proof for derived triple:
23
- # :GIRL a :FLOATS .
24
- # It holds because the following instance of the rule body is provable:
25
- # :DUCK a :FLOATS .
26
- # :DUCK :SAMEWEIGHT :GIRL .
27
- # via the schematic forward rule:
28
- # {
29
- # ?x a :FLOATS .
30
- # ?x :SAMEWEIGHT ?y .
31
- # } => {
32
- # ?y a :FLOATS .
33
- # } .
34
- # with substitution (on rule variables):
35
- # ?x = :DUCK
36
- # ?y = :GIRL
37
- # Therefore the derived triple above is entailed by the rules and facts.
38
- # ----------------------------------------------------------------------
39
-
40
4
  :GIRL a :FLOATS .
41
-
42
- # ----------------------------------------------------------------------
43
- # Proof for derived triple:
44
- # :DUCK a :BURNS .
45
- # It holds because the following instance of the rule body is provable:
46
- # :DUCK a :ISMADEOFWOOD .
47
- # via the schematic forward rule:
48
- # {
49
- # ?x a :ISMADEOFWOOD .
50
- # } => {
51
- # ?x a :BURNS .
52
- # } .
53
- # with substitution (on rule variables):
54
- # ?x = :DUCK
55
- # Therefore the derived triple above is entailed by the rules and facts.
56
- # ----------------------------------------------------------------------
57
-
58
5
  :DUCK a :BURNS .
59
-
60
- # ----------------------------------------------------------------------
61
- # Proof for derived triple:
62
- # :GIRL a :ISMADEOFWOOD .
63
- # It holds because the following instance of the rule body is provable:
64
- # :GIRL a :FLOATS .
65
- # via the schematic forward rule:
66
- # {
67
- # ?x a :FLOATS .
68
- # } => {
69
- # ?x a :ISMADEOFWOOD .
70
- # } .
71
- # with substitution (on rule variables):
72
- # ?x = :GIRL
73
- # Therefore the derived triple above is entailed by the rules and facts.
74
- # ----------------------------------------------------------------------
75
-
76
6
  :GIRL a :ISMADEOFWOOD .
77
-
78
- # ----------------------------------------------------------------------
79
- # Proof for derived triple:
80
- # :GIRL a :BURNS .
81
- # It holds because the following instance of the rule body is provable:
82
- # :GIRL a :ISMADEOFWOOD .
83
- # via the schematic forward rule:
84
- # {
85
- # ?x a :ISMADEOFWOOD .
86
- # } => {
87
- # ?x a :BURNS .
88
- # } .
89
- # with substitution (on rule variables):
90
- # ?x = :GIRL
91
- # Therefore the derived triple above is entailed by the rules and facts.
92
- # ----------------------------------------------------------------------
93
-
94
7
  :GIRL a :BURNS .
95
-
96
- # ----------------------------------------------------------------------
97
- # Proof for derived triple:
98
- # :GIRL a :WITCH .
99
- # It holds because the following instance of the rule body is provable:
100
- # :GIRL a :BURNS .
101
- # :GIRL a :WOMAN .
102
- # via the schematic forward rule:
103
- # {
104
- # ?x a :BURNS .
105
- # ?x a :WOMAN .
106
- # } => {
107
- # ?x a :WITCH .
108
- # } .
109
- # with substitution (on rule variables):
110
- # ?x = :GIRL
111
- # Therefore the derived triple above is entailed by the rules and facts.
112
- # ----------------------------------------------------------------------
113
-
114
8
  :GIRL a :WITCH .
115
-
@@ -1,114 +1,3 @@
1
1
  @prefix : <http://eulersharp.sourceforge.net/2005/11swap/zebra#> .
2
2
 
3
- # ----------------------------------------------------------------------
4
- # Proof for derived triple:
5
- # :german :eats :fish .
6
- # It holds because the following instance of the rule body is provable:
7
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) log:equalTo ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) .
8
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) :pair ((:blue :dane :horse :tea :blends) (:yellow :norwegian :cats :water :dunhill)) .
9
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) :pair ((:blue :dane :horse :tea :blends) (:yellow :norwegian :cats :water :dunhill)) .
10
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) :sublist ((:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) .
11
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) :pair ((:blue :dane :horse :tea :blends) (:yellow :norwegian :cats :water :dunhill)) .
12
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:red :brit :birds :milk :pallmall) .
13
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:white :swede :dogs :beer :bluemasters) .
14
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:blue :dane :horse :tea :blends) .
15
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:red :brit :birds :milk :pallmall) .
16
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:yellow :norwegian :cats :water :dunhill) .
17
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:white :swede :dogs :beer :bluemasters) .
18
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:green :german :fish :coffee :prince) .
19
- # ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters)) list:member (:green :german :fish :coffee :prince) .
20
- # via the schematic forward rule:
21
- # {
22
- # ?L log:equalTo ((?A1 :norwegian ?A2 ?A3 ?A4) (:blue ?A5 ?A6 ?A7 ?A8) (?A9 ?A10 ?A11 :milk ?A12) ?A13 ?A14) .
23
- # ?L :pair ((?A15 ?A16 ?A17 ?A18 :blends) (?A19 ?A20 :cats ?A21 ?A22)) .
24
- # ?L :pair ((?A23 ?A24 :horse ?A25 ?A26) (?A27 ?A28 ?A29 ?A30 :dunhill)) .
25
- # ?L :sublist ((:green ?A31 ?A32 :coffee ?A33) (:white ?A34 ?A35 ?A36 ?A37)) .
26
- # ?L :pair ((?A38 ?A39 ?A40 ?A41 :blends) (?A42 ?A43 ?A44 :water ?A45)) .
27
- # ?L list:member (:red :brit ?A46 ?A47 ?A48) .
28
- # ?L list:member (?A49 :swede :dogs ?A50 ?A51) .
29
- # ?L list:member (?A52 :dane ?A53 :tea ?A54) .
30
- # ?L list:member (?A55 ?A56 :birds ?A57 :pallmall) .
31
- # ?L list:member (:yellow ?A58 ?A59 ?A60 :dunhill) .
32
- # ?L list:member (?A61 ?A62 ?A63 :beer :bluemasters) .
33
- # ?L list:member (?A64 :german ?A65 ?A66 :prince) .
34
- # ?L list:member (?A67 ?B :fish ?A69 ?A70) .
35
- # } => {
36
- # ?B :eats :fish .
37
- # } .
38
- # with substitution (on rule variables):
39
- # ?A1 = :yellow
40
- # ?A10 = :brit
41
- # ?A11 = :birds
42
- # ?A12 = :pallmall
43
- # ?A13 = (:green :german :fish :coffee :prince)
44
- # ?A14 = (:white :swede :dogs :beer :bluemasters)
45
- # ?A15 = :blue
46
- # ?A16 = :dane
47
- # ?A17 = :horse
48
- # ?A18 = :tea
49
- # ?A19 = :yellow
50
- # ?A2 = :cats
51
- # ?A20 = :norwegian
52
- # ?A21 = :water
53
- # ?A22 = :dunhill
54
- # ?A23 = :blue
55
- # ?A24 = :dane
56
- # ?A25 = :tea
57
- # ?A26 = :blends
58
- # ?A27 = :yellow
59
- # ?A28 = :norwegian
60
- # ?A29 = :cats
61
- # ?A3 = :water
62
- # ?A30 = :water
63
- # ?A31 = :german
64
- # ?A32 = :fish
65
- # ?A33 = :prince
66
- # ?A34 = :swede
67
- # ?A35 = :dogs
68
- # ?A36 = :beer
69
- # ?A37 = :bluemasters
70
- # ?A38 = :blue
71
- # ?A39 = :dane
72
- # ?A4 = :dunhill
73
- # ?A40 = :horse
74
- # ?A41 = :tea
75
- # ?A42 = :yellow
76
- # ?A43 = :norwegian
77
- # ?A44 = :cats
78
- # ?A45 = :dunhill
79
- # ?A46 = :birds
80
- # ?A47 = :milk
81
- # ?A48 = :pallmall
82
- # ?A49 = :white
83
- # ?A5 = :dane
84
- # ?A50 = :beer
85
- # ?A51 = :bluemasters
86
- # ?A52 = :blue
87
- # ?A53 = :horse
88
- # ?A54 = :blends
89
- # ?A55 = :red
90
- # ?A56 = :brit
91
- # ?A57 = :milk
92
- # ?A58 = :norwegian
93
- # ?A59 = :cats
94
- # ?A6 = :horse
95
- # ?A60 = :water
96
- # ?A61 = :white
97
- # ?A62 = :swede
98
- # ?A63 = :dogs
99
- # ?A64 = :green
100
- # ?A65 = :fish
101
- # ?A66 = :coffee
102
- # ?A67 = :green
103
- # ?A69 = :coffee
104
- # ?A7 = :tea
105
- # ?A70 = :prince
106
- # ?A8 = :blends
107
- # ?A9 = :red
108
- # ?B = :german
109
- # ?L = ((:yellow :norwegian :cats :water :dunhill) (:blue :dane :horse :tea :blends) (:red :brit :birds :milk :pallmall) (:green :german :fish :coffee :prince) (:white :swede :dogs :beer :bluemasters))
110
- # Therefore the derived triple above is entailed by the rules and facts.
111
- # ----------------------------------------------------------------------
112
-
113
3
  :german :eats :fish .
114
-
package/eyeling.js CHANGED
@@ -39,7 +39,11 @@ const RDF_JSON_DT = RDF_NS + 'JSON';
39
39
  function resolveIriRef(ref, base) {
40
40
  if (!base) return ref;
41
41
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return ref; // already absolute
42
- try { return new URL(ref, base).toString(); } catch { return ref; }
42
+ try {
43
+ return new URL(ref, base).toString();
44
+ } catch {
45
+ return ref;
46
+ }
43
47
  }
44
48
 
45
49
  function isRdfJsonDatatype(dt) {
@@ -71,7 +75,7 @@ const skolemCache = new Map();
71
75
  const jsonPointerCache = new Map();
72
76
 
73
77
  // Controls whether human-readable proof comments are printed.
74
- let proofCommentsEnabled = true;
78
+ let proofCommentsEnabled = false;
75
79
 
76
80
  // ----------------------------------------------------------------------------
77
81
  // Deterministic time support
@@ -271,14 +275,30 @@ function decodeN3StringEscapes(s) {
271
275
  }
272
276
  const e = s[++i];
273
277
  switch (e) {
274
- case 't': out += '\t'; break;
275
- case 'n': out += '\n'; break;
276
- case 'r': out += '\r'; break;
277
- case 'b': out += '\b'; break;
278
- case 'f': out += '\f'; break;
279
- case '"': out += '"'; break;
280
- case "'": out += "'"; break;
281
- case '\\': out += '\\'; break;
278
+ case 't':
279
+ out += '\t';
280
+ break;
281
+ case 'n':
282
+ out += '\n';
283
+ break;
284
+ case 'r':
285
+ out += '\r';
286
+ break;
287
+ case 'b':
288
+ out += '\b';
289
+ break;
290
+ case 'f':
291
+ out += '\f';
292
+ break;
293
+ case '"':
294
+ out += '"';
295
+ break;
296
+ case "'":
297
+ out += "'";
298
+ break;
299
+ case '\\':
300
+ out += '\\';
301
+ break;
282
302
 
283
303
  case 'u': {
284
304
  const hex = s.slice(i + 1, i + 5);
@@ -295,7 +315,7 @@ function decodeN3StringEscapes(s) {
295
315
  const hex = s.slice(i + 1, i + 9);
296
316
  if (/^[0-9A-Fa-f]{8}$/.test(hex)) {
297
317
  const cp = parseInt(hex, 16);
298
- if (cp >= 0 && cp <= 0x10FFFF) out += String.fromCodePoint(cp);
318
+ if (cp >= 0 && cp <= 0x10ffff) out += String.fromCodePoint(cp);
299
319
  else out += '\\U' + hex;
300
320
  i += 8;
301
321
  } else {
@@ -2343,9 +2363,14 @@ function stripQuotes(lex) {
2343
2363
  }
2344
2364
 
2345
2365
  function termToJsString(t) {
2346
- // Accept any Literal and interpret its lexical form as a JS string.
2366
+ // Strict string extraction for SWAP/N3 string builtins:
2367
+ // - accept plain string literals ("...") and language-tagged ones ("..."@en)
2368
+ // - accept "..."^^xsd:string
2369
+ // - reject any other datatype (e.g., "x"^^xsd:integer, "x"^^xsd:foobar)
2347
2370
  if (!(t instanceof Literal)) return null;
2348
- const [lex, _dt] = literalParts(t.value);
2371
+ const [lex, dt] = literalParts(t.value);
2372
+ if (!isQuotedLexical(lex)) return null;
2373
+ if (dt !== null && dt !== XSD_NS + 'string' && dt !== 'xsd:string') return null;
2349
2374
  return stripQuotes(lex);
2350
2375
  }
2351
2376
 
@@ -4198,13 +4223,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4198
4223
  const [sLex, sDt0] = literalParts(a.value);
4199
4224
 
4200
4225
  // $s.1 must be xsd:string (plain or ^^xsd:string), not language-tagged.
4201
- const okString =
4202
- (sDt0 === null && isPlainStringLiteralValue(a.value)) || sDt0 === XSD_NS + 'string';
4226
+ const okString = (sDt0 === null && isPlainStringLiteralValue(a.value)) || sDt0 === XSD_NS + 'string';
4203
4227
  if (okString) {
4204
4228
  const dtIri = b.value;
4205
4229
  // For xsd:string, prefer the plain string literal form.
4206
- const outLit =
4207
- dtIri === XSD_NS + 'string' ? new Literal(sLex) : new Literal(`${sLex}^^<${dtIri}>`);
4230
+ const outLit = dtIri === XSD_NS + 'string' ? new Literal(sLex) : new Literal(`${sLex}^^<${dtIri}>`);
4208
4231
  const s2 = unifyTerm(goal.o, outLit, subst);
4209
4232
  if (s2 !== null) results.push(s2);
4210
4233
  }
@@ -4214,6 +4237,62 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4214
4237
  return results;
4215
4238
  }
4216
4239
 
4240
+ // log:langlit
4241
+ // Schema: ( $s.1? $s.2? )? log:langlit $o?
4242
+ // true iff $o is a language-tagged literal with string value $s.1 and language tag $s.2
4243
+ if (g.p instanceof Iri && g.p.value === LOG_NS + 'langlit') {
4244
+ // Fully unbound (both arguments '?'-mode): treat as satisfiable, succeed once.
4245
+ if (g.s instanceof Var && g.o instanceof Var) return [{ ...subst }];
4246
+ const results = [];
4247
+ const LANG_RE = /^[A-Za-z]+(?:-[A-Za-z0-9]+)*$/; // (same notion as literalParts/literalHasLangTag)
4248
+
4249
+ function extractLangTag(litVal) {
4250
+ if (typeof litVal !== 'string') return null;
4251
+ if (!literalHasLangTag(litVal)) return null;
4252
+ const lastQuote = litVal.lastIndexOf('"');
4253
+ if (lastQuote < 0) return null;
4254
+ const after = lastQuote + 1;
4255
+ if (after >= litVal.length || litVal[after] !== '@') return null;
4256
+ const tag = litVal.slice(after + 1);
4257
+ if (!LANG_RE.test(tag)) return null;
4258
+ return tag;
4259
+ }
4260
+
4261
+ // Direction 1: object language-tagged literal -> subject list (string, langtag)
4262
+ if (g.o instanceof Literal) {
4263
+ const tag = extractLangTag(g.o.value);
4264
+ if (tag !== null) {
4265
+ const [oLex] = literalParts(g.o.value); // strips @lang into lexical part
4266
+ const strLit = isQuotedLexical(oLex) ? new Literal(oLex) : makeStringLiteral(String(oLex));
4267
+ const langLit = makeStringLiteral(tag);
4268
+ const subjList = new ListTerm([strLit, langLit]);
4269
+ const s2 = unifyTerm(goal.s, subjList, subst);
4270
+ if (s2 !== null) results.push(s2);
4271
+ }
4272
+ }
4273
+
4274
+ // Direction 2: subject list -> object language-tagged literal
4275
+ if (g.s instanceof ListTerm && g.s.elems.length === 2) {
4276
+ const a = g.s.elems[0]; // string
4277
+ const b = g.s.elems[1]; // lang tag string
4278
+ if (a instanceof Literal && b instanceof Literal) {
4279
+ const [sLex, sDt0] = literalParts(a.value);
4280
+ const okString = (sDt0 === null && isPlainStringLiteralValue(a.value)) || sDt0 === XSD_NS + 'string';
4281
+ const [langLex, langDt0] = literalParts(b.value);
4282
+ const okLang = (langDt0 === null && isPlainStringLiteralValue(b.value)) || langDt0 === XSD_NS + 'string';
4283
+ if (okString && okLang) {
4284
+ const tag = stripQuotes(langLex);
4285
+ if (LANG_RE.test(tag)) {
4286
+ const outLit = new Literal(`${sLex}@${tag}`);
4287
+ const s2 = unifyTerm(goal.o, outLit, subst);
4288
+ if (s2 !== null) results.push(s2);
4289
+ }
4290
+ }
4291
+ }
4292
+ }
4293
+ return results;
4294
+ }
4295
+
4217
4296
  // log:implies — expose internal forward rules as data
4218
4297
  if (g.p instanceof Iri && g.p.value === LOG_NS + 'implies') {
4219
4298
  const allFw = backRules.__allForwardRules || [];
@@ -4390,8 +4469,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4390
4469
  return s2 !== null ? [s2] : [];
4391
4470
  }
4392
4471
 
4393
- const sOk = (g.s instanceof Var) || (g.s instanceof Blank) || (g.s instanceof Iri);
4394
- const oOk = (g.o instanceof Var) || (g.o instanceof Blank) || (g.o instanceof Literal);
4472
+ const sOk = g.s instanceof Var || g.s instanceof Blank || g.s instanceof Iri;
4473
+ const oOk = g.o instanceof Var || g.o instanceof Blank || g.o instanceof Literal;
4395
4474
  if (!sOk || !oOk) return [];
4396
4475
  return [{ ...subst }];
4397
4476
  }
@@ -5479,7 +5558,6 @@ function localIsoDateTimeString(d) {
5479
5558
  // ============================================================================
5480
5559
  // CLI entry point
5481
5560
  // ============================================================================
5482
-
5483
5561
  function main() {
5484
5562
  // Drop "node" and script name; keep only user-provided args
5485
5563
  const argv = process.argv.slice(2);
@@ -5487,6 +5565,19 @@ function main() {
5487
5565
  // --------------------------------------------------------------------------
5488
5566
  // Global options
5489
5567
  // --------------------------------------------------------------------------
5568
+ // --help / -h: print help and exit
5569
+ if (argv.includes('--help') || argv.includes('-h')) {
5570
+ console.log(
5571
+ 'Usage: eyeling.js [options] <file.n3>\n' +
5572
+ '\n' +
5573
+ 'Options:\n' +
5574
+ ' -h, --help Show this help and exit.\n' +
5575
+ ' -v, --version Print version and exit.\n' +
5576
+ ' -p, --proof-comments Enable proof explanations.\n' +
5577
+ ' -n, --no-proof-comments Disable proof explanations (default).\n',
5578
+ );
5579
+ process.exit(0);
5580
+ }
5490
5581
 
5491
5582
  // --version / -v: print version and exit
5492
5583
  if (argv.includes('--version') || argv.includes('-v')) {
@@ -5494,7 +5585,13 @@ function main() {
5494
5585
  process.exit(0);
5495
5586
  }
5496
5587
 
5497
- // --no-proof-comments / -n: disable proof explanations
5588
+ // --proof-comments / -p: enable proof explanations
5589
+ if (argv.includes('--proof-comments') || argv.includes('-p')) {
5590
+ proofCommentsEnabled = true;
5591
+ }
5592
+
5593
+ // --no-proof-comments / -n: disable proof explanations (default)
5594
+ // Keep this after --proof-comments so -n wins if both are present.
5498
5595
  if (argv.includes('--no-proof-comments') || argv.includes('-n')) {
5499
5596
  proofCommentsEnabled = false;
5500
5597
  }
@@ -5503,9 +5600,16 @@ function main() {
5503
5600
  // Positional args (the N3 file)
5504
5601
  // --------------------------------------------------------------------------
5505
5602
  const positional = argv.filter((a) => !a.startsWith('-'));
5506
-
5507
5603
  if (positional.length !== 1) {
5508
- console.error('Usage: eyeling.js [--version|-v] [--no-proof-comments|-n] <file.n3>');
5604
+ console.error(
5605
+ 'Usage: eyeling.js [options] <file.n3>\n' +
5606
+ '\n' +
5607
+ 'Options:\n' +
5608
+ ' -h, --help Show this help and exit.\n' +
5609
+ ' -v, --version Print version and exit.\n' +
5610
+ ' -p, --proof-comments Enable proof explanations.\n' +
5611
+ ' -n, --no-proof-comments Disable proof explanations (default).\n',
5612
+ );
5509
5613
  process.exit(1);
5510
5614
  }
5511
5615
 
@@ -5524,12 +5628,12 @@ function main() {
5524
5628
  const [prefixes, triples, frules, brules] = parser.parseDocument();
5525
5629
  // console.log(JSON.stringify([prefixes, triples, frules, brules], null, 2));
5526
5630
 
5527
- // Build internal ListTerm values from rdf:first/rdf:rest (+ rdf:nil) input triples
5631
+ // Build internal ListTerm values from rdf:first/rdf:rest (+ rdf:nil)
5632
+ // input triples
5528
5633
  materializeRdfLists(triples, frules, brules);
5529
5634
 
5530
5635
  const facts = triples.filter((tr) => isGroundTriple(tr));
5531
5636
  const derived = forwardChain(facts, frules, brules);
5532
-
5533
5637
  const derivedTriples = derived.map((df) => df.fact);
5534
5638
  const usedPrefixes = prefixes.prefixesUsedForOutput(derivedTriples);
5535
5639
 
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ +'use strict';
2
2
 
3
3
  const fs = require('node:fs');
4
4
  const os = require('node:os');
@@ -13,15 +13,23 @@ function reason(opt = {}, n3_input = '') {
13
13
 
14
14
  // allow passing an args array directly
15
15
  if (Array.isArray(opt)) opt = { args: opt };
16
+ if (opt == null || typeof opt !== 'object') opt = {};
16
17
 
17
18
  const args = [];
18
19
 
19
20
  // default: proof comments OFF for API output (machine-friendly)
20
21
  // set { proofComments: true } to keep them
22
+ const proofCommentsSpecified = typeof opt.proofComments === 'boolean' || typeof opt.noProofComments === 'boolean';
23
+
21
24
  const proofComments =
22
25
  typeof opt.proofComments === 'boolean' ? opt.proofComments : typeof opt.noProofComments === 'boolean' ? !opt.noProofComments : false;
23
26
 
24
- if (!proofComments) args.push('--no-proof-comments'); // CLI already supports this :contentReference[oaicite:1]{index=1}
27
+ // Only pass a flag when the caller explicitly asked.
28
+ // (CLI default is now: no proof comments.)
29
+ if (proofCommentsSpecified) {
30
+ if (proofComments) args.push('--proof-comments');
31
+ else args.push('--no-proof-comments');
32
+ }
25
33
 
26
34
  if (Array.isArray(opt.args)) args.push(...opt.args);
27
35
 
@@ -34,10 +42,7 @@ function reason(opt = {}, n3_input = '') {
34
42
  fs.writeFileSync(inputFile, n3_input, 'utf8');
35
43
 
36
44
  const eyelingPath = path.join(__dirname, 'eyeling.js');
37
- const res = cp.spawnSync(process.execPath, [eyelingPath, ...args, inputFile], {
38
- encoding: 'utf8',
39
- maxBuffer,
40
- });
45
+ const res = cp.spawnSync(process.execPath, [eyelingPath, ...args, inputFile], { encoding: 'utf8', maxBuffer });
41
46
 
42
47
  if (res.error) throw res.error;
43
48
  if (res.status !== 0) {
@@ -47,6 +52,7 @@ function reason(opt = {}, n3_input = '') {
47
52
  err.stderr = res.stderr;
48
53
  throw err;
49
54
  }
55
+
50
56
  return res.stdout;
51
57
  } finally {
52
58
  fs.rmSync(dir, { recursive: true, force: true });
@@ -54,5 +60,6 @@ function reason(opt = {}, n3_input = '') {
54
60
  }
55
61
 
56
62
  module.exports = { reason };
63
+
57
64
  // small interop nicety for ESM default import
58
65
  module.exports.default = module.exports;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.6.13",
3
+ "version": "1.6.15",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
@@ -172,7 +172,7 @@ function main() {
172
172
  // Run eyeling on this file (cwd examplesDir so relative behavior matches old script)
173
173
  const outFd = fs.openSync(generatedPath, 'w');
174
174
 
175
- const r = cp.spawnSync(nodePath, [eyelingJsPath, file], {
175
+ const r = cp.spawnSync(nodePath, [eyelingJsPath, '-n', file], {
176
176
  cwd: examplesDir,
177
177
  stdio: ['ignore', outFd, 'pipe'], // stdout -> file, stderr captured
178
178
  maxBuffer: 200 * 1024 * 1024,