eyeling 1.7.17 → 1.7.19
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/LICENSE.md +1 -1
- package/README.md +12 -14
- package/examples/output/json-reconcile-vat.n3 +151 -0
- package/eyeling.js +68 -17
- package/package.json +1 -1
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MIT License
|
|
2
2
|
|
|
3
|
-
### Copyright
|
|
3
|
+
### Copyright 2025-2026 Jos De Roo, KNoWS office of IDLab, Ghent University - imec
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -17,13 +17,14 @@ A [Notation3 (N3)](https://notation3.org/) reasoner in **JavaScript**.
|
|
|
17
17
|
Try it here:
|
|
18
18
|
|
|
19
19
|
- [Eyeling playground](https://eyereasoner.github.io/eyeling/demo)
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
- Edit an N3 program directly.
|
|
21
|
+
- Load an N3 program from a URL (in the "Load N3 from URL" box or as ?url=...).
|
|
22
|
+
- Share a link with the program encoded in the URL fragment (`#...`).
|
|
23
23
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
24
|
+
- [Eyeling streaming playground](https://eyereasoner.github.io/eyeling/stream)
|
|
25
|
+
- Browse a Wikidata entity, load its facts, and see Eyeling’s **deductive closure appear incrementally** as triples are derived.
|
|
26
|
+
- Edit **N3 rules live** and re-run to watch how different inference rules change what gets derived.
|
|
27
|
+
- Demo **CORS-safe dynamic fetching**: derived “fetch requests” can trigger extra facts (e.g., Wikiquote extracts) that are injected and re-reasoned.
|
|
27
28
|
|
|
28
29
|
## Quick start
|
|
29
30
|
|
|
@@ -120,6 +121,7 @@ Options:
|
|
|
120
121
|
-s, --super-restricted Disable all builtins except => and <=.
|
|
121
122
|
-a, --ast Print parsed AST as JSON and exit.
|
|
122
123
|
--strings Print log:outputString strings (ordered by key) instead of N3 output.
|
|
124
|
+
--enforce-https Rewrite http:// IRIs to https:// for log dereferencing builtins.
|
|
123
125
|
```
|
|
124
126
|
|
|
125
127
|
By default, `eyeling`:
|
|
@@ -165,6 +167,7 @@ The CLI prints only newly derived forward facts.
|
|
|
165
167
|
- backward rules are indexed by head predicate
|
|
166
168
|
- the backward prover is **iterative** (explicit stack), so deep chains won’t blow the JS call stack
|
|
167
169
|
- for very deep backward chains, substitutions may be compactified (semantics-preserving) to avoid quadratic “copy a growing substitution object” behavior
|
|
170
|
+
- if the head is **structurally ground** and has no head blanks, one body proof suffices—and if the head triples are already known, we can skip the body proof.
|
|
168
171
|
|
|
169
172
|
## Blank nodes and quantification
|
|
170
173
|
|
|
@@ -202,7 +205,7 @@ Rules whose conclusion is `false` are treated as hard failures:
|
|
|
202
205
|
|
|
203
206
|
As soon as the premise is provable, `eyeling` exits with status code `2`.
|
|
204
207
|
|
|
205
|
-
## Syntax
|
|
208
|
+
## Syntax
|
|
206
209
|
|
|
207
210
|
`eyeling`’s parser targets (nearly) the full *Notation3 Language* grammar from the [W3C N3 Community Group spec](https://w3c.github.io/N3/spec/).
|
|
208
211
|
|
|
@@ -223,14 +226,9 @@ Commonly used N3/Turtle features:
|
|
|
223
226
|
- Resource paths (`!` and `^`)
|
|
224
227
|
- `#` line comments
|
|
225
228
|
|
|
226
|
-
|
|
229
|
+
## Builtins
|
|
227
230
|
|
|
228
|
-
|
|
229
|
-
- **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:rest` `list:reverse` `list:sort`
|
|
230
|
-
- **log**: `log:collectAllIn` `log:content` `log:dtlit` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:includes` `log:langlit` `log:notEqualTo` `log:notIncludes` `log:outputString` `log:parsedAsN3` `log:rawType` `log:semantics` `log:semanticsOrError` `log:skolem` `log:trace` `log:uri`
|
|
231
|
-
- **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:integerQuotient` `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`
|
|
232
|
-
- **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:jsonPointer` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
|
|
233
|
-
- **time**: `time:day` `time:hour` `time:localTime` `time:minute` `time:month` `time:second` `time:timeZone` `time:year`
|
|
231
|
+
`eyeling` implements the builtins described in [eyeling-builtins](https://github.com/eyereasoner/eyeling/blob/main/eyeling-builtins.ttl).
|
|
234
232
|
|
|
235
233
|
## License
|
|
236
234
|
|
|
@@ -73,3 +73,154 @@ genid:8e2eaee7-90fd-39b8-cf83-6d8c8e5816c8 ex:email "ada@other.example" .
|
|
|
73
73
|
<urn:example:customer:vat:NL999999999B01> a ex:CustomerEmailConflict .
|
|
74
74
|
<urn:example:customer:vat:NL999999999B01> ex:conflictingEmail "acct@company.nl" .
|
|
75
75
|
<urn:example:customer:vat:NL999999999B01> ex:conflictingEmail "billing@company.nl" .
|
|
76
|
+
<urn:example:order:A100> ex:line <urn:example:order:A100#line:0> .
|
|
77
|
+
<urn:example:order:A100#line:0> a ex:OrderLine .
|
|
78
|
+
<urn:example:order:A100#line:0> ex:lineIndex 0 .
|
|
79
|
+
<urn:example:order:A100#line:0> ex:product ex:Widget .
|
|
80
|
+
<urn:example:order:A100#line:0> ex:sku "WID-001" .
|
|
81
|
+
<urn:example:order:A100#line:0> ex:qty 2 .
|
|
82
|
+
<urn:example:order:A100#line:0> ex:unitCents 999 .
|
|
83
|
+
<urn:example:order:A100#line:0> ex:netCents 1998 .
|
|
84
|
+
<urn:example:order:A100> ex:line <urn:example:order:A100#line:1> .
|
|
85
|
+
<urn:example:order:A100#line:1> a ex:OrderLine .
|
|
86
|
+
<urn:example:order:A100#line:1> ex:lineIndex 1 .
|
|
87
|
+
<urn:example:order:A100#line:1> ex:product ex:Gadget .
|
|
88
|
+
<urn:example:order:A100#line:1> ex:sku "GAD-002" .
|
|
89
|
+
<urn:example:order:A100#line:1> ex:qty 1 .
|
|
90
|
+
<urn:example:order:A100#line:1> ex:unitCents 1500 .
|
|
91
|
+
<urn:example:order:A100#line:1> ex:netCents 1500 .
|
|
92
|
+
<urn:example:order:A200> ex:line <urn:example:order:A200#line:0> .
|
|
93
|
+
<urn:example:order:A200#line:0> a ex:OrderLine .
|
|
94
|
+
<urn:example:order:A200#line:0> ex:lineIndex 0 .
|
|
95
|
+
<urn:example:order:A200#line:0> ex:product ex:Widget .
|
|
96
|
+
<urn:example:order:A200#line:0> ex:sku "WID-001" .
|
|
97
|
+
<urn:example:order:A200#line:0> ex:qty 2 .
|
|
98
|
+
<urn:example:order:A200#line:0> ex:unitCents 999 .
|
|
99
|
+
<urn:example:order:A200#line:0> ex:netCents 1998 .
|
|
100
|
+
<urn:example:order:A200> ex:line <urn:example:order:A200#line:1> .
|
|
101
|
+
<urn:example:order:A200#line:1> a ex:OrderLine .
|
|
102
|
+
<urn:example:order:A200#line:1> ex:lineIndex 1 .
|
|
103
|
+
<urn:example:order:A200#line:1> ex:product ex:Gadget .
|
|
104
|
+
<urn:example:order:A200#line:1> ex:sku "GAD-002" .
|
|
105
|
+
<urn:example:order:A200#line:1> ex:qty 1 .
|
|
106
|
+
<urn:example:order:A200#line:1> ex:unitCents 1500 .
|
|
107
|
+
<urn:example:order:A200#line:1> ex:netCents 1500 .
|
|
108
|
+
<urn:example:order:A300> ex:line <urn:example:order:A300#line:0> .
|
|
109
|
+
<urn:example:order:A300#line:0> a ex:OrderLine .
|
|
110
|
+
<urn:example:order:A300#line:0> ex:lineIndex 0 .
|
|
111
|
+
<urn:example:order:A300#line:0> ex:product ex:Widget .
|
|
112
|
+
<urn:example:order:A300#line:0> ex:sku "WID-001" .
|
|
113
|
+
<urn:example:order:A300#line:0> ex:qty 2 .
|
|
114
|
+
<urn:example:order:A300#line:0> ex:unitCents 999 .
|
|
115
|
+
<urn:example:order:A300#line:0> ex:netCents 1998 .
|
|
116
|
+
<urn:example:order:A300> ex:line <urn:example:order:A300#line:1> .
|
|
117
|
+
<urn:example:order:A300#line:1> a ex:OrderLine .
|
|
118
|
+
<urn:example:order:A300#line:1> ex:lineIndex 1 .
|
|
119
|
+
<urn:example:order:A300#line:1> ex:product ex:Gadget .
|
|
120
|
+
<urn:example:order:A300#line:1> ex:sku "GAD-002" .
|
|
121
|
+
<urn:example:order:A300#line:1> ex:qty 1 .
|
|
122
|
+
<urn:example:order:A300#line:1> ex:unitCents 1500 .
|
|
123
|
+
<urn:example:order:A300#line:1> ex:netCents 1500 .
|
|
124
|
+
<urn:example:order:A301> ex:line <urn:example:order:A301#line:0> .
|
|
125
|
+
<urn:example:order:A301#line:0> a ex:OrderLine .
|
|
126
|
+
<urn:example:order:A301#line:0> ex:lineIndex 0 .
|
|
127
|
+
<urn:example:order:A301#line:0> ex:product ex:Widget .
|
|
128
|
+
<urn:example:order:A301#line:0> ex:sku "WID-001" .
|
|
129
|
+
<urn:example:order:A301#line:0> ex:qty 2 .
|
|
130
|
+
<urn:example:order:A301#line:0> ex:unitCents 999 .
|
|
131
|
+
<urn:example:order:A301#line:0> ex:netCents 1998 .
|
|
132
|
+
<urn:example:order:A301> ex:line <urn:example:order:A301#line:1> .
|
|
133
|
+
<urn:example:order:A301#line:1> a ex:OrderLine .
|
|
134
|
+
<urn:example:order:A301#line:1> ex:lineIndex 1 .
|
|
135
|
+
<urn:example:order:A301#line:1> ex:product ex:Gadget .
|
|
136
|
+
<urn:example:order:A301#line:1> ex:sku "GAD-002" .
|
|
137
|
+
<urn:example:order:A301#line:1> ex:qty 1 .
|
|
138
|
+
<urn:example:order:A301#line:1> ex:unitCents 1500 .
|
|
139
|
+
<urn:example:order:A301#line:1> ex:netCents 1500 .
|
|
140
|
+
<urn:example:order:A400> ex:line <urn:example:order:A400#line:0> .
|
|
141
|
+
<urn:example:order:A400#line:0> a ex:OrderLine .
|
|
142
|
+
<urn:example:order:A400#line:0> ex:lineIndex 0 .
|
|
143
|
+
<urn:example:order:A400#line:0> ex:product ex:Widget .
|
|
144
|
+
<urn:example:order:A400#line:0> ex:sku "WID-001" .
|
|
145
|
+
<urn:example:order:A400#line:0> ex:qty 2 .
|
|
146
|
+
<urn:example:order:A400#line:0> ex:unitCents 999 .
|
|
147
|
+
<urn:example:order:A400#line:0> ex:netCents 1998 .
|
|
148
|
+
<urn:example:order:A400> ex:line <urn:example:order:A400#line:1> .
|
|
149
|
+
<urn:example:order:A400#line:1> a ex:OrderLine .
|
|
150
|
+
<urn:example:order:A400#line:1> ex:lineIndex 1 .
|
|
151
|
+
<urn:example:order:A400#line:1> ex:product ex:Gadget .
|
|
152
|
+
<urn:example:order:A400#line:1> ex:sku "GAD-002" .
|
|
153
|
+
<urn:example:order:A400#line:1> ex:qty 1 .
|
|
154
|
+
<urn:example:order:A400#line:1> ex:unitCents 1500 .
|
|
155
|
+
<urn:example:order:A400#line:1> ex:netCents 1500 .
|
|
156
|
+
<urn:example:order:A200#line:0> ex:vatBps 0 .
|
|
157
|
+
<urn:example:order:A200#line:0> ex:vatCents 0 .
|
|
158
|
+
<urn:example:order:A200#line:0> ex:grossCents 1998 .
|
|
159
|
+
<urn:example:order:A200#line:0> ex:vatReason ex:Export .
|
|
160
|
+
<urn:example:order:A200#line:1> ex:vatBps 0 .
|
|
161
|
+
<urn:example:order:A200#line:1> ex:vatCents 0 .
|
|
162
|
+
<urn:example:order:A200#line:1> ex:grossCents 1500 .
|
|
163
|
+
<urn:example:order:A200#line:1> ex:vatReason ex:Export .
|
|
164
|
+
<urn:example:order:A300#line:0> ex:vatBps 0 .
|
|
165
|
+
<urn:example:order:A300#line:0> ex:vatCents 0 .
|
|
166
|
+
<urn:example:order:A300#line:0> ex:grossCents 1998 .
|
|
167
|
+
<urn:example:order:A300#line:0> ex:vatReason ex:ReverseCharge .
|
|
168
|
+
<urn:example:order:A300#line:1> ex:vatBps 0 .
|
|
169
|
+
<urn:example:order:A300#line:1> ex:vatCents 0 .
|
|
170
|
+
<urn:example:order:A300#line:1> ex:grossCents 1500 .
|
|
171
|
+
<urn:example:order:A300#line:1> ex:vatReason ex:ReverseCharge .
|
|
172
|
+
<urn:example:order:A301#line:0> ex:vatBps 0 .
|
|
173
|
+
<urn:example:order:A301#line:0> ex:vatCents 0 .
|
|
174
|
+
<urn:example:order:A301#line:0> ex:grossCents 1998 .
|
|
175
|
+
<urn:example:order:A301#line:0> ex:vatReason ex:ReverseCharge .
|
|
176
|
+
<urn:example:order:A301#line:1> ex:vatBps 0 .
|
|
177
|
+
<urn:example:order:A301#line:1> ex:vatCents 0 .
|
|
178
|
+
<urn:example:order:A301#line:1> ex:grossCents 1500 .
|
|
179
|
+
<urn:example:order:A301#line:1> ex:vatReason ex:ReverseCharge .
|
|
180
|
+
<urn:example:order:A100#line:0> ex:vatBps 2100 .
|
|
181
|
+
<urn:example:order:A100#line:0> ex:vatCents 419 .
|
|
182
|
+
<urn:example:order:A100#line:0> ex:grossCents 2417 .
|
|
183
|
+
<urn:example:order:A100#line:0> ex:vatReason ex:Domestic .
|
|
184
|
+
<urn:example:order:A100#line:1> ex:vatBps 600 .
|
|
185
|
+
<urn:example:order:A100#line:1> ex:vatCents 90 .
|
|
186
|
+
<urn:example:order:A100#line:1> ex:grossCents 1590 .
|
|
187
|
+
<urn:example:order:A100#line:1> ex:vatReason ex:Domestic .
|
|
188
|
+
<urn:example:order:A400#line:0> ex:vatBps 2100 .
|
|
189
|
+
<urn:example:order:A400#line:0> ex:vatCents 419 .
|
|
190
|
+
<urn:example:order:A400#line:0> ex:grossCents 2417 .
|
|
191
|
+
<urn:example:order:A400#line:0> ex:vatReason ex:Domestic .
|
|
192
|
+
<urn:example:order:A400#line:1> ex:vatBps 600 .
|
|
193
|
+
<urn:example:order:A400#line:1> ex:vatCents 90 .
|
|
194
|
+
<urn:example:order:A400#line:1> ex:grossCents 1590 .
|
|
195
|
+
<urn:example:order:A400#line:1> ex:vatReason ex:Domestic .
|
|
196
|
+
<urn:example:order:A100> ex:computedNetCents 3498 .
|
|
197
|
+
<urn:example:order:A100> ex:computedVatCents 509 .
|
|
198
|
+
<urn:example:order:A100> ex:computedGrossCents 4007 .
|
|
199
|
+
<urn:example:order:A200> ex:computedNetCents 3498 .
|
|
200
|
+
<urn:example:order:A200> ex:computedVatCents 0 .
|
|
201
|
+
<urn:example:order:A200> ex:computedGrossCents 3498 .
|
|
202
|
+
<urn:example:order:A300> ex:computedNetCents 3498 .
|
|
203
|
+
<urn:example:order:A300> ex:computedVatCents 0 .
|
|
204
|
+
<urn:example:order:A300> ex:computedGrossCents 3498 .
|
|
205
|
+
<urn:example:order:A301> ex:computedNetCents 3498 .
|
|
206
|
+
<urn:example:order:A301> ex:computedVatCents 0 .
|
|
207
|
+
<urn:example:order:A301> ex:computedGrossCents 3498 .
|
|
208
|
+
<urn:example:order:A400> ex:computedNetCents 3498 .
|
|
209
|
+
<urn:example:order:A400> ex:computedVatCents 509 .
|
|
210
|
+
<urn:example:order:A400> ex:computedGrossCents 4007 .
|
|
211
|
+
<urn:example:order:A100> a ex:OrderOk .
|
|
212
|
+
<urn:example:order:A200> a ex:OrderOk .
|
|
213
|
+
<urn:example:order:A300> a ex:OrderOk .
|
|
214
|
+
<urn:example:order:A301> a ex:OrderOk .
|
|
215
|
+
<urn:example:issue:A400:vat> a ex:Issue .
|
|
216
|
+
<urn:example:issue:A400:vat> ex:onOrder <urn:example:order:A400> .
|
|
217
|
+
<urn:example:issue:A400:vat> ex:field "vatCents" .
|
|
218
|
+
<urn:example:issue:A400:vat> ex:declared 508 .
|
|
219
|
+
<urn:example:issue:A400:vat> ex:computed 509 .
|
|
220
|
+
<urn:example:order:A400> ex:hasIssue <urn:example:issue:A400:vat> .
|
|
221
|
+
<urn:example:issue:A400:gross> a ex:Issue .
|
|
222
|
+
<urn:example:issue:A400:gross> ex:onOrder <urn:example:order:A400> .
|
|
223
|
+
<urn:example:issue:A400:gross> ex:field "grossCents" .
|
|
224
|
+
<urn:example:issue:A400:gross> ex:declared 4006 .
|
|
225
|
+
<urn:example:issue:A400:gross> ex:computed 4007 .
|
|
226
|
+
<urn:example:order:A400> ex:hasIssue <urn:example:issue:A400:gross> .
|
package/eyeling.js
CHANGED
|
@@ -104,6 +104,17 @@ const __logSemanticsCache = new Map(); // iri -> GraphTerm | null (null means pa
|
|
|
104
104
|
const __logSemanticsOrErrorCache = new Map(); // iri -> Term (GraphTerm | Literal) for log:semanticsOrError
|
|
105
105
|
const __logConclusionCache = new WeakMap(); // GraphTerm -> GraphTerm (deductive closure)
|
|
106
106
|
|
|
107
|
+
// When enabled, force http:// IRIs to be dereferenced as https://
|
|
108
|
+
// (CLI: --enforce-https, API: reasonStream({ enforceHttps: true })).
|
|
109
|
+
let enforceHttpsEnabled = false;
|
|
110
|
+
|
|
111
|
+
function __maybeEnforceHttps(iri) {
|
|
112
|
+
if (!enforceHttpsEnabled) return iri;
|
|
113
|
+
return typeof iri === 'string' && iri.startsWith('http://')
|
|
114
|
+
? 'https://' + iri.slice('http://'.length)
|
|
115
|
+
: iri;
|
|
116
|
+
}
|
|
117
|
+
|
|
107
118
|
// Environment detection (Node vs Browser/Worker).
|
|
108
119
|
// Eyeling is primarily synchronous, so we use sync XHR in browsers for log:content/log:semantics.
|
|
109
120
|
// Note: Browser fetches are subject to CORS; use CORS-enabled resources or a proxy.
|
|
@@ -150,9 +161,9 @@ function __fetchHttpTextSyncBrowser(url) {
|
|
|
150
161
|
|
|
151
162
|
function __normalizeDerefIri(iriNoFrag) {
|
|
152
163
|
// In Node, treat non-http as local path; leave as-is.
|
|
153
|
-
if (__IS_NODE) return iriNoFrag;
|
|
164
|
+
if (__IS_NODE) return __maybeEnforceHttps(iriNoFrag);
|
|
154
165
|
// In browsers/workers, resolve relative references against the page URL.
|
|
155
|
-
return __resolveBrowserUrl(iriNoFrag);
|
|
166
|
+
return __maybeEnforceHttps(__resolveBrowserUrl(iriNoFrag));
|
|
156
167
|
}
|
|
157
168
|
|
|
158
169
|
function __stripFragment(iri) {
|
|
@@ -195,9 +206,17 @@ function __fetchHttpTextViaSubprocess(url) {
|
|
|
195
206
|
const cp = require('child_process');
|
|
196
207
|
// Use a subprocess so this code remains synchronous without rewriting the whole reasoner to async.
|
|
197
208
|
const script = `
|
|
209
|
+
const enforceHttps = ${enforceHttpsEnabled ? 'true' : 'false'};
|
|
198
210
|
const url = process.argv[1];
|
|
199
211
|
const maxRedirects = 10;
|
|
212
|
+
function norm(u) {
|
|
213
|
+
if (enforceHttps && typeof u === 'string' && u.startsWith('http://')) {
|
|
214
|
+
return 'https://' + u.slice('http://'.length);
|
|
215
|
+
}
|
|
216
|
+
return u;
|
|
217
|
+
}
|
|
200
218
|
function get(u, n) {
|
|
219
|
+
u = norm(u);
|
|
201
220
|
if (n > maxRedirects) { console.error('Too many redirects'); process.exit(3); }
|
|
202
221
|
let mod;
|
|
203
222
|
if (u.startsWith('https://')) mod = require('https');
|
|
@@ -219,7 +238,8 @@ function __fetchHttpTextViaSubprocess(url) {
|
|
|
219
238
|
const req = mod.request(opts, (res) => {
|
|
220
239
|
const sc = res.statusCode || 0;
|
|
221
240
|
if (sc >= 300 && sc < 400 && res.headers && res.headers.location) {
|
|
222
|
-
|
|
241
|
+
let next = new URL(res.headers.location, u).toString();
|
|
242
|
+
next = norm(next);
|
|
223
243
|
res.resume();
|
|
224
244
|
return get(next, n + 1);
|
|
225
245
|
}
|
|
@@ -3061,19 +3081,34 @@ function termToJsXsdStringNoLang(t) {
|
|
|
3061
3081
|
}
|
|
3062
3082
|
|
|
3063
3083
|
function termToJsString(t) {
|
|
3064
|
-
//
|
|
3065
|
-
//
|
|
3066
|
-
//
|
|
3067
|
-
//
|
|
3084
|
+
// Domain is xsd:string for SWAP/N3 string builtins (string:*).
|
|
3085
|
+
//
|
|
3086
|
+
// Per the N3 Builtins spec, when the domain is xsd:string we must be able to
|
|
3087
|
+
// cast *any* IRI or literal value (incl. numeric, boolean, dateTime, anyURI,
|
|
3088
|
+
// rdf:langString, and plain literals) to a string.
|
|
3089
|
+
//
|
|
3090
|
+
// We implement this as:
|
|
3091
|
+
// - IRI -> its IRI string
|
|
3092
|
+
// - Literal:
|
|
3093
|
+
// * quoted lexical form: decode N3/Turtle escapes and strip quotes
|
|
3094
|
+
// * unquoted lexical form: use as-is (e.g., 1234, true, 1971-..., 1.23E4)
|
|
3095
|
+
// - Everything else (blank nodes, lists, formulas, vars) -> fail
|
|
3096
|
+
if (t instanceof Iri) return t.value;
|
|
3068
3097
|
if (!(t instanceof Literal)) return null;
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3098
|
+
|
|
3099
|
+
const [lex, _dt] = literalParts(t.value);
|
|
3100
|
+
|
|
3101
|
+
if (isQuotedLexical(lex)) {
|
|
3102
|
+
// Interpret N3/Turtle string escapes (\" \n \uXXXX \UXXXXXXXX …)
|
|
3103
|
+
// to obtain the actual string value.
|
|
3104
|
+
return decodeN3StringEscapes(stripQuotes(lex));
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
// Unquoted lexical (numbers/booleans/dateTimes, etc.)
|
|
3108
|
+
return typeof lex === 'string' ? lex : String(lex);
|
|
3075
3109
|
}
|
|
3076
3110
|
|
|
3111
|
+
|
|
3077
3112
|
function makeStringLiteral(str) {
|
|
3078
3113
|
// JSON.stringify gives us a valid N3/Turtle-style quoted string
|
|
3079
3114
|
// (with proper escaping for quotes, backslashes, newlines, …).
|
|
@@ -6991,8 +7026,16 @@ function __collectOutputStringsFromFacts(facts, prefixes) {
|
|
|
6991
7026
|
}
|
|
6992
7027
|
|
|
6993
7028
|
function reasonStream(n3Text, opts = {}) {
|
|
6994
|
-
const {
|
|
6995
|
-
|
|
7029
|
+
const {
|
|
7030
|
+
baseIri = null,
|
|
7031
|
+
proof = false,
|
|
7032
|
+
onDerived = null,
|
|
7033
|
+
includeInputFactsInClosure = true,
|
|
7034
|
+
enforceHttps = false,
|
|
7035
|
+
} = opts;
|
|
7036
|
+
|
|
7037
|
+
const __oldEnforceHttps = enforceHttpsEnabled;
|
|
7038
|
+
enforceHttpsEnabled = !!enforceHttps;
|
|
6996
7039
|
proofCommentsEnabled = !!proof;
|
|
6997
7040
|
|
|
6998
7041
|
const toks = lex(n3Text);
|
|
@@ -7020,12 +7063,14 @@ function reasonStream(n3Text, opts = {}) {
|
|
|
7020
7063
|
|
|
7021
7064
|
const closureTriples = includeInputFactsInClosure ? facts : derived.map((d) => d.fact);
|
|
7022
7065
|
|
|
7023
|
-
|
|
7066
|
+
const __out = {
|
|
7024
7067
|
prefixes,
|
|
7025
7068
|
facts, // saturated closure (Triple[])
|
|
7026
7069
|
derived, // DerivedFact[]
|
|
7027
7070
|
closureN3: closureTriples.map((t) => tripleToN3(t, prefixes)).join('\n'),
|
|
7028
7071
|
};
|
|
7072
|
+
enforceHttpsEnabled = __oldEnforceHttps;
|
|
7073
|
+
return __out;
|
|
7029
7074
|
}
|
|
7030
7075
|
|
|
7031
7076
|
// Minimal export surface for Node + browser/worker
|
|
@@ -7056,7 +7101,8 @@ function main() {
|
|
|
7056
7101
|
` -n, --no-proof-comments Disable proof explanations (default).\n` +
|
|
7057
7102
|
` -s, --super-restricted Disable all builtins except => and <=.\n` +
|
|
7058
7103
|
` -a, --ast Print parsed AST as JSON and exit.\n` +
|
|
7059
|
-
` --strings Print log:outputString strings (ordered by key) instead of N3 output.\n
|
|
7104
|
+
` --strings Print log:outputString strings (ordered by key) instead of N3 output.\n` +
|
|
7105
|
+
` --enforce-https Rewrite http:// IRIs to https:// for log dereferencing builtins.\n`;
|
|
7060
7106
|
(toStderr ? console.error : console.log)(msg);
|
|
7061
7107
|
}
|
|
7062
7108
|
|
|
@@ -7079,6 +7125,11 @@ function main() {
|
|
|
7079
7125
|
|
|
7080
7126
|
const outputStringsMode = argv.includes('--strings');
|
|
7081
7127
|
|
|
7128
|
+
// --enforce-https: rewrite http:// -> https:// for log dereferencing builtins
|
|
7129
|
+
if (argv.includes('--enforce-https')) {
|
|
7130
|
+
enforceHttpsEnabled = true;
|
|
7131
|
+
}
|
|
7132
|
+
|
|
7082
7133
|
// --proof-comments / -p: enable proof explanations
|
|
7083
7134
|
if (argv.includes('--proof-comments') || argv.includes('-p')) {
|
|
7084
7135
|
proofCommentsEnabled = true;
|