eyeling 1.28.3 → 1.28.5

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.
@@ -142,6 +142,10 @@ function __assertBuiltinHandlerResult(iri, out) {
142
142
  }
143
143
  }
144
144
 
145
+ function apiTermToN3(term, prefixes = PrefixEnv.newDefault()) {
146
+ return termToN3(term, prefixes || PrefixEnv.newDefault());
147
+ }
148
+
145
149
  function __buildBuiltinRegistrationApi() {
146
150
  if (__builtinApiSingleton) return __builtinApiSingleton;
147
151
 
@@ -154,7 +158,7 @@ function __buildBuiltinRegistrationApi() {
154
158
  literalParts,
155
159
  termToJsString,
156
160
  termToJsStringDecoded,
157
- termToN3,
161
+ termToN3: apiTermToN3,
158
162
  iriValue,
159
163
  unifyTerm,
160
164
  applySubstTerm,
@@ -16389,11 +16393,18 @@ function liftBlankRuleVars(premise, conclusion) {
16389
16393
  const mapping = Object.create(null);
16390
16394
  let counter = 0;
16391
16395
 
16396
+ // These variables are implementation details used to correlate one blank
16397
+ // node across the lifted rule body. Their names must not be spellable by
16398
+ // user input; otherwise a user variable such as ?_b1 can capture the
16399
+ // lifted blank node and leak it into the rule head. U+E000 is a private-use
16400
+ // code point and is not accepted by the lexer as part of a variable name.
16401
+ const INTERNAL_BLANK_VAR_PREFIX = '\uE000eyeling_b';
16402
+
16392
16403
  function blankToVar(label) {
16393
16404
  let name = mapping[label];
16394
16405
  if (name === undefined) {
16395
16406
  counter += 1;
16396
- name = `_b${counter}`;
16407
+ name = `${INTERNAL_BLANK_VAR_PREFIX}${counter}`;
16397
16408
  mapping[label] = name;
16398
16409
  }
16399
16410
  return new Var(name);
@@ -16445,7 +16456,7 @@ function liftBlankRuleVars(premise, conclusion) {
16445
16456
  // consumed by the builtin rather than ordinary triple patterns. Keep their
16446
16457
  // local blank nodes as Blank terms so the builtin can treat them as local
16447
16458
  // existentials, and bindings returned from an explicit scope are blank nodes
16448
- // instead of synthetic rule variables such as ?_b1.
16459
+ // instead of synthetic rule variables.
16449
16460
  const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
16450
16461
  return new Triple(
16451
16462
  keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
@@ -18,31 +18,31 @@
18
18
  {
19
19
  (?param {
20
20
  :Let :param ?param .
21
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
21
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
22
22
  },
23
23
  {
24
24
  ((?param) {
25
25
  :Let :param ?param .
26
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
26
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
27
27
  },
28
28
  {
29
29
  (?param {
30
30
  :Let :param ?param .
31
31
  ?param string:lessThan "Louie" .
32
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
32
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
33
33
  }.
34
34
 
35
35
  {
36
36
  (?param {
37
37
  :Let :param ?param .
38
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
38
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
39
39
  }
40
40
  pe:by [ pe:builtin log:collectAllIn ].
41
41
 
42
42
  {
43
43
  ((?param) {
44
44
  :Let :param ?param .
45
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
45
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
46
46
  }
47
47
  pe:by [ pe:builtin log:collectAllIn ].
48
48
 
@@ -50,7 +50,7 @@
50
50
  (?param {
51
51
  :Let :param ?param .
52
52
  ?param string:lessThan "Louie" .
53
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
53
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
54
54
  }
55
55
  pe:by [ pe:builtin log:collectAllIn ].
56
56
  }.
@@ -66,31 +66,31 @@
66
66
  {
67
67
  (?param {
68
68
  :Let :param ?param .
69
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
69
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
70
70
  },
71
71
  {
72
72
  ((?param) {
73
73
  :Let :param ?param .
74
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
74
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
75
75
  },
76
76
  {
77
77
  (?param {
78
78
  :Let :param ?param .
79
79
  ?param string:lessThan "Louie" .
80
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
80
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
81
81
  }.
82
82
 
83
83
  {
84
84
  (?param {
85
85
  :Let :param ?param .
86
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
86
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
87
87
  }
88
88
  pe:by [ pe:builtin log:collectAllIn ].
89
89
 
90
90
  {
91
91
  ((?param) {
92
92
  :Let :param ?param .
93
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
93
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
94
94
  }
95
95
  pe:by [ pe:builtin log:collectAllIn ].
96
96
 
@@ -98,7 +98,7 @@
98
98
  (?param {
99
99
  :Let :param ?param .
100
100
  ?param string:lessThan "Louie" .
101
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
101
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
102
102
  }
103
103
  pe:by [ pe:builtin log:collectAllIn ].
104
104
  }.
@@ -114,31 +114,31 @@
114
114
  {
115
115
  (?param {
116
116
  :Let :param ?param .
117
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
117
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
118
118
  },
119
119
  {
120
120
  ((?param) {
121
121
  :Let :param ?param .
122
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
122
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
123
123
  },
124
124
  {
125
125
  (?param {
126
126
  :Let :param ?param .
127
127
  ?param string:lessThan "Louie" .
128
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
128
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
129
129
  }.
130
130
 
131
131
  {
132
132
  (?param {
133
133
  :Let :param ?param .
134
- } ("Huey" "Dewey" "Louie")) log:collectAllIn ?_b1 .
134
+ } ("Huey" "Dewey" "Louie")) log:collectAllIn ?eyeling_b1 .
135
135
  }
136
136
  pe:by [ pe:builtin log:collectAllIn ].
137
137
 
138
138
  {
139
139
  ((?param) {
140
140
  :Let :param ?param .
141
- } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?_b1 .
141
+ } (("Huey") ("Dewey") ("Louie"))) log:collectAllIn ?eyeling_b1 .
142
142
  }
143
143
  pe:by [ pe:builtin log:collectAllIn ].
144
144
 
@@ -146,7 +146,7 @@
146
146
  (?param {
147
147
  :Let :param ?param .
148
148
  ?param string:lessThan "Louie" .
149
- } ("Huey" "Dewey")) log:collectAllIn ?_b1 .
149
+ } ("Huey" "Dewey")) log:collectAllIn ?eyeling_b1 .
150
150
  }
151
151
  pe:by [ pe:builtin log:collectAllIn ].
152
152
  }.
@@ -16,7 +16,7 @@
16
16
  :c :subTask ?s .
17
17
  } {
18
18
  ?s :state :Completed .
19
- }) log:forAllIn ?_b1 .
19
+ }) log:forAllIn ?eyeling_b1 .
20
20
  }.
21
21
 
22
22
  { :c a :CompositeTask . }
@@ -27,7 +27,7 @@
27
27
  :c :subTask ?s .
28
28
  } {
29
29
  ?s :state :Completed .
30
- }) log:forAllIn ?_b1 .
30
+ }) log:forAllIn ?eyeling_b1 .
31
31
  }
32
32
  pe:by [ pe:builtin log:forAllIn ].
33
33
  }.
package/eyeling.js CHANGED
@@ -142,6 +142,10 @@ function __assertBuiltinHandlerResult(iri, out) {
142
142
  }
143
143
  }
144
144
 
145
+ function apiTermToN3(term, prefixes = PrefixEnv.newDefault()) {
146
+ return termToN3(term, prefixes || PrefixEnv.newDefault());
147
+ }
148
+
145
149
  function __buildBuiltinRegistrationApi() {
146
150
  if (__builtinApiSingleton) return __builtinApiSingleton;
147
151
 
@@ -154,7 +158,7 @@ function __buildBuiltinRegistrationApi() {
154
158
  literalParts,
155
159
  termToJsString,
156
160
  termToJsStringDecoded,
157
- termToN3,
161
+ termToN3: apiTermToN3,
158
162
  iriValue,
159
163
  unifyTerm,
160
164
  applySubstTerm,
@@ -16389,11 +16393,18 @@ function liftBlankRuleVars(premise, conclusion) {
16389
16393
  const mapping = Object.create(null);
16390
16394
  let counter = 0;
16391
16395
 
16396
+ // These variables are implementation details used to correlate one blank
16397
+ // node across the lifted rule body. Their names must not be spellable by
16398
+ // user input; otherwise a user variable such as ?_b1 can capture the
16399
+ // lifted blank node and leak it into the rule head. U+E000 is a private-use
16400
+ // code point and is not accepted by the lexer as part of a variable name.
16401
+ const INTERNAL_BLANK_VAR_PREFIX = '\uE000eyeling_b';
16402
+
16392
16403
  function blankToVar(label) {
16393
16404
  let name = mapping[label];
16394
16405
  if (name === undefined) {
16395
16406
  counter += 1;
16396
- name = `_b${counter}`;
16407
+ name = `${INTERNAL_BLANK_VAR_PREFIX}${counter}`;
16397
16408
  mapping[label] = name;
16398
16409
  }
16399
16410
  return new Var(name);
@@ -16445,7 +16456,7 @@ function liftBlankRuleVars(premise, conclusion) {
16445
16456
  // consumed by the builtin rather than ordinary triple patterns. Keep their
16446
16457
  // local blank nodes as Blank terms so the builtin can treat them as local
16447
16458
  // existentials, and bindings returned from an explicit scope are blank nodes
16448
- // instead of synthetic rule variables such as ?_b1.
16459
+ // instead of synthetic rule variables.
16449
16460
  const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
16450
16461
  return new Triple(
16451
16462
  keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
package/lib/builtins.js CHANGED
@@ -131,6 +131,10 @@ function __assertBuiltinHandlerResult(iri, out) {
131
131
  }
132
132
  }
133
133
 
134
+ function apiTermToN3(term, prefixes = PrefixEnv.newDefault()) {
135
+ return termToN3(term, prefixes || PrefixEnv.newDefault());
136
+ }
137
+
134
138
  function __buildBuiltinRegistrationApi() {
135
139
  if (__builtinApiSingleton) return __builtinApiSingleton;
136
140
 
@@ -143,7 +147,7 @@ function __buildBuiltinRegistrationApi() {
143
147
  literalParts,
144
148
  termToJsString,
145
149
  termToJsStringDecoded,
146
- termToN3,
150
+ termToN3: apiTermToN3,
147
151
  iriValue,
148
152
  unifyTerm,
149
153
  applySubstTerm,
package/lib/rules.js CHANGED
@@ -29,11 +29,18 @@ function liftBlankRuleVars(premise, conclusion) {
29
29
  const mapping = Object.create(null);
30
30
  let counter = 0;
31
31
 
32
+ // These variables are implementation details used to correlate one blank
33
+ // node across the lifted rule body. Their names must not be spellable by
34
+ // user input; otherwise a user variable such as ?_b1 can capture the
35
+ // lifted blank node and leak it into the rule head. U+E000 is a private-use
36
+ // code point and is not accepted by the lexer as part of a variable name.
37
+ const INTERNAL_BLANK_VAR_PREFIX = '\uE000eyeling_b';
38
+
32
39
  function blankToVar(label) {
33
40
  let name = mapping[label];
34
41
  if (name === undefined) {
35
42
  counter += 1;
36
- name = `_b${counter}`;
43
+ name = `${INTERNAL_BLANK_VAR_PREFIX}${counter}`;
37
44
  mapping[label] = name;
38
45
  }
39
46
  return new Var(name);
@@ -85,7 +92,7 @@ function liftBlankRuleVars(premise, conclusion) {
85
92
  // consumed by the builtin rather than ordinary triple patterns. Keep their
86
93
  // local blank nodes as Blank terms so the builtin can treat them as local
87
94
  // existentials, and bindings returned from an explicit scope are blank nodes
88
- // instead of synthetic rule variables such as ?_b1.
95
+ // instead of synthetic rule variables.
89
96
  const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
90
97
  return new Triple(
91
98
  keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.28.3",
3
+ "version": "1.28.5",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -3123,6 +3123,36 @@ MESSAGE
3123
3123
  ],
3124
3124
  },
3125
3125
 
3126
+
3127
+ {
3128
+ name: 'regression: user variable ?_b1 cannot capture lifted blank-node internals',
3129
+ opt: { proofComments: false },
3130
+ input: `@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3131
+ @prefix : <http://example.org/> .
3132
+
3133
+ :test :value (6).
3134
+
3135
+ {
3136
+ :test :value [
3137
+ rdf:first 6;
3138
+ rdf:rest rdf:nil].
3139
+ }
3140
+ =>
3141
+ {
3142
+ ?_b1 a :test
3143
+ }.
3144
+
3145
+ {
3146
+ ?What a :test .
3147
+ } => { :test :is false }.
3148
+ `,
3149
+ // API output contains newly derived triples only; the input fact is not echoed.
3150
+ check(out) {
3151
+ assert.equal(out, '');
3152
+ },
3153
+ notExpect: [/\(6\)\s+a\s+:test\s*\./m, /:test\s+:is\s+false\s*\./m],
3154
+ },
3155
+
3126
3156
  {
3127
3157
  name: 'API empty input returns empty output',
3128
3158
  opt: { proofComments: false },
@@ -110,6 +110,14 @@ const cases = [
110
110
  assert.deepEqual(Object.keys(api.ns).sort(), expectedNsKeys);
111
111
  },
112
112
  },
113
+ {
114
+ name: 'custom builtin helper termToN3 uses default prefixes when omitted',
115
+ run() {
116
+ const api = builtins.__testBuildBuiltinApi();
117
+ assert.equal(api.termToN3(api.internIri('http://www.w3.org/2000/10/swap/log#implies')), 'log:implies');
118
+ assert.equal(api.termToN3(api.internLiteral('"abc"')), '"abc"');
119
+ },
120
+ },
113
121
  {
114
122
  name: 'registerBuiltinModule accepts supported module export forms',
115
123
  run() {