eyeling 1.5.31 → 1.5.32
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/README.md +1 -1
- package/examples/json-pointer.n3 +69 -0
- package/examples/output/json-pointer.n3 +800 -0
- package/eyeling.js +207 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -239,7 +239,7 @@ As soon as the premise is provable, `eyeling` exits with status code `2`.
|
|
|
239
239
|
- **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`
|
|
240
240
|
- **log**: `log:collectAllIn` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:skolem` `log:uri`
|
|
241
241
|
- **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`
|
|
242
|
-
- **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`
|
|
242
|
+
- **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`
|
|
243
243
|
- **time**: `time:localTime`
|
|
244
244
|
|
|
245
245
|
## License
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@prefix string: <http://www.w3.org/2000/10/swap/string#> .
|
|
2
|
+
@prefix list: <http://www.w3.org/2000/10/swap/list#> .
|
|
3
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
4
|
+
@prefix ex: <http://example.org/> .
|
|
5
|
+
|
|
6
|
+
ex:doc ex:json """{
|
|
7
|
+
"users": [
|
|
8
|
+
{ "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
9
|
+
{ "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
10
|
+
],
|
|
11
|
+
"policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
12
|
+
}""" .
|
|
13
|
+
|
|
14
|
+
# Sanity check: key contains "/" so JSON Pointer must use "~1"
|
|
15
|
+
{
|
|
16
|
+
ex:doc ex:json ?J .
|
|
17
|
+
(?J "/users/0/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
18
|
+
} => {
|
|
19
|
+
ex:checks ex:firstUserNameOk true .
|
|
20
|
+
} .
|
|
21
|
+
|
|
22
|
+
# Allowed users: email domain is in policy.allowedDomains
|
|
23
|
+
{
|
|
24
|
+
ex:doc ex:json ?J .
|
|
25
|
+
(?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
26
|
+
(?J "/users") string:jsonPointer ?Users .
|
|
27
|
+
|
|
28
|
+
?Users list:iterate (?Idx ?UserJson) .
|
|
29
|
+
(?UserJson "/id") string:jsonPointer ?Id .
|
|
30
|
+
(?UserJson "/email") string:jsonPointer ?Email .
|
|
31
|
+
(?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
32
|
+
|
|
33
|
+
(?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
34
|
+
?Allowed list:member ?EmailDomain .
|
|
35
|
+
|
|
36
|
+
("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
37
|
+
?User log:uri ?UriStr .
|
|
38
|
+
} => {
|
|
39
|
+
?User a ex:AllowedUser ;
|
|
40
|
+
ex:name ?Name ;
|
|
41
|
+
ex:email ?Email ;
|
|
42
|
+
ex:emailDomain ?EmailDomain ;
|
|
43
|
+
ex:userIndex ?Idx .
|
|
44
|
+
} .
|
|
45
|
+
|
|
46
|
+
# Blocked users: email domain is NOT in the allowlist
|
|
47
|
+
{
|
|
48
|
+
ex:doc ex:json ?J .
|
|
49
|
+
(?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
50
|
+
(?J "/users") string:jsonPointer ?Users .
|
|
51
|
+
|
|
52
|
+
?Users list:iterate (?Idx ?UserJson) .
|
|
53
|
+
(?UserJson "/id") string:jsonPointer ?Id .
|
|
54
|
+
(?UserJson "/email") string:jsonPointer ?Email .
|
|
55
|
+
(?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
56
|
+
|
|
57
|
+
(?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
58
|
+
?Allowed list:notMember ?EmailDomain .
|
|
59
|
+
|
|
60
|
+
("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
61
|
+
?User log:uri ?UriStr .
|
|
62
|
+
} => {
|
|
63
|
+
?User a ex:BlockedUser ;
|
|
64
|
+
ex:name ?Name ;
|
|
65
|
+
ex:email ?Email ;
|
|
66
|
+
ex:emailDomain ?EmailDomain ;
|
|
67
|
+
ex:userIndex ?Idx .
|
|
68
|
+
} .
|
|
69
|
+
|
|
@@ -0,0 +1,800 @@
|
|
|
1
|
+
@prefix ex: <http://example.org/> .
|
|
2
|
+
|
|
3
|
+
# ----------------------------------------------------------------------
|
|
4
|
+
# Proof for derived triple:
|
|
5
|
+
# ex:checks ex:firstUserNameOk true .
|
|
6
|
+
# It holds because the following instance of the rule body is provable:
|
|
7
|
+
# ex:doc ex:json """{
|
|
8
|
+
# "users": [
|
|
9
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
10
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
11
|
+
# ],
|
|
12
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
13
|
+
# }""" .
|
|
14
|
+
# ("""{
|
|
15
|
+
# "users": [
|
|
16
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
17
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
18
|
+
# ],
|
|
19
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
20
|
+
# }""" "/users/0/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
21
|
+
# via the schematic forward rule:
|
|
22
|
+
# {
|
|
23
|
+
# ex:doc ex:json ?J .
|
|
24
|
+
# (?J "/users/0/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
25
|
+
# } => {
|
|
26
|
+
# ex:checks ex:firstUserNameOk true .
|
|
27
|
+
# } .
|
|
28
|
+
# with substitution (on rule variables):
|
|
29
|
+
# ?J = """{
|
|
30
|
+
# "users": [
|
|
31
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
32
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
33
|
+
# ],
|
|
34
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
35
|
+
# }"""
|
|
36
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
37
|
+
# ----------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
ex:checks ex:firstUserNameOk true .
|
|
40
|
+
|
|
41
|
+
# ----------------------------------------------------------------------
|
|
42
|
+
# Proof for derived triple:
|
|
43
|
+
# <urn:example:user:u1> a ex:AllowedUser .
|
|
44
|
+
# It holds because the following instance of the rule body is provable:
|
|
45
|
+
# ex:doc ex:json """{
|
|
46
|
+
# "users": [
|
|
47
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
48
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
49
|
+
# ],
|
|
50
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
51
|
+
# }""" .
|
|
52
|
+
# ("""{
|
|
53
|
+
# "users": [
|
|
54
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
55
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
56
|
+
# ],
|
|
57
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
58
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
59
|
+
# ("""{
|
|
60
|
+
# "users": [
|
|
61
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
62
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
63
|
+
# ],
|
|
64
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
65
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
66
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (0 """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""") .
|
|
67
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/id") string:jsonPointer "u1" .
|
|
68
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/email") string:jsonPointer "ada@example.org" .
|
|
69
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
70
|
+
# ("ada@example.org" "@([^@]+)$") string:scrape "example.org" .
|
|
71
|
+
# ("example.org" "example.com") list:member "example.org" .
|
|
72
|
+
# ("urn:example:user:%s" "u1") string:format "urn:example:user:u1" .
|
|
73
|
+
# <urn:example:user:u1> log:uri "urn:example:user:u1" .
|
|
74
|
+
# via the schematic forward rule:
|
|
75
|
+
# {
|
|
76
|
+
# ex:doc ex:json ?J .
|
|
77
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
78
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
79
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
80
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
81
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
82
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
83
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
84
|
+
# ?Allowed list:member ?EmailDomain .
|
|
85
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
86
|
+
# ?User log:uri ?UriStr .
|
|
87
|
+
# } => {
|
|
88
|
+
# ?User a ex:AllowedUser .
|
|
89
|
+
# ?User ex:name ?Name .
|
|
90
|
+
# ?User ex:email ?Email .
|
|
91
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
92
|
+
# ?User ex:userIndex ?Idx .
|
|
93
|
+
# } .
|
|
94
|
+
# with substitution (on rule variables):
|
|
95
|
+
# ?Allowed = ("example.org" "example.com")
|
|
96
|
+
# ?Email = "ada@example.org"
|
|
97
|
+
# ?EmailDomain = "example.org"
|
|
98
|
+
# ?Id = "u1"
|
|
99
|
+
# ?Idx = 0
|
|
100
|
+
# ?J = """{
|
|
101
|
+
# "users": [
|
|
102
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
103
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
104
|
+
# ],
|
|
105
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
106
|
+
# }"""
|
|
107
|
+
# ?Name = "Ada Lovelace"
|
|
108
|
+
# ?UriStr = "urn:example:user:u1"
|
|
109
|
+
# ?User = <urn:example:user:u1>
|
|
110
|
+
# ?UserJson = """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}"""
|
|
111
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
112
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
113
|
+
# ----------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
<urn:example:user:u1> a ex:AllowedUser .
|
|
116
|
+
|
|
117
|
+
# ----------------------------------------------------------------------
|
|
118
|
+
# Proof for derived triple:
|
|
119
|
+
# <urn:example:user:u1> ex:name "Ada Lovelace" .
|
|
120
|
+
# It holds because the following instance of the rule body is provable:
|
|
121
|
+
# ex:doc ex:json """{
|
|
122
|
+
# "users": [
|
|
123
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
124
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
125
|
+
# ],
|
|
126
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
127
|
+
# }""" .
|
|
128
|
+
# ("""{
|
|
129
|
+
# "users": [
|
|
130
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
131
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
132
|
+
# ],
|
|
133
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
134
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
135
|
+
# ("""{
|
|
136
|
+
# "users": [
|
|
137
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
138
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
139
|
+
# ],
|
|
140
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
141
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
142
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (0 """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""") .
|
|
143
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/id") string:jsonPointer "u1" .
|
|
144
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/email") string:jsonPointer "ada@example.org" .
|
|
145
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
146
|
+
# ("ada@example.org" "@([^@]+)$") string:scrape "example.org" .
|
|
147
|
+
# ("example.org" "example.com") list:member "example.org" .
|
|
148
|
+
# ("urn:example:user:%s" "u1") string:format "urn:example:user:u1" .
|
|
149
|
+
# <urn:example:user:u1> log:uri "urn:example:user:u1" .
|
|
150
|
+
# via the schematic forward rule:
|
|
151
|
+
# {
|
|
152
|
+
# ex:doc ex:json ?J .
|
|
153
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
154
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
155
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
156
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
157
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
158
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
159
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
160
|
+
# ?Allowed list:member ?EmailDomain .
|
|
161
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
162
|
+
# ?User log:uri ?UriStr .
|
|
163
|
+
# } => {
|
|
164
|
+
# ?User a ex:AllowedUser .
|
|
165
|
+
# ?User ex:name ?Name .
|
|
166
|
+
# ?User ex:email ?Email .
|
|
167
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
168
|
+
# ?User ex:userIndex ?Idx .
|
|
169
|
+
# } .
|
|
170
|
+
# with substitution (on rule variables):
|
|
171
|
+
# ?Allowed = ("example.org" "example.com")
|
|
172
|
+
# ?Email = "ada@example.org"
|
|
173
|
+
# ?EmailDomain = "example.org"
|
|
174
|
+
# ?Id = "u1"
|
|
175
|
+
# ?Idx = 0
|
|
176
|
+
# ?J = """{
|
|
177
|
+
# "users": [
|
|
178
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
179
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
180
|
+
# ],
|
|
181
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
182
|
+
# }"""
|
|
183
|
+
# ?Name = "Ada Lovelace"
|
|
184
|
+
# ?UriStr = "urn:example:user:u1"
|
|
185
|
+
# ?User = <urn:example:user:u1>
|
|
186
|
+
# ?UserJson = """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}"""
|
|
187
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
188
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
189
|
+
# ----------------------------------------------------------------------
|
|
190
|
+
|
|
191
|
+
<urn:example:user:u1> ex:name "Ada Lovelace" .
|
|
192
|
+
|
|
193
|
+
# ----------------------------------------------------------------------
|
|
194
|
+
# Proof for derived triple:
|
|
195
|
+
# <urn:example:user:u1> ex:email "ada@example.org" .
|
|
196
|
+
# It holds because the following instance of the rule body is provable:
|
|
197
|
+
# ex:doc ex:json """{
|
|
198
|
+
# "users": [
|
|
199
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
200
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
201
|
+
# ],
|
|
202
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
203
|
+
# }""" .
|
|
204
|
+
# ("""{
|
|
205
|
+
# "users": [
|
|
206
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
207
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
208
|
+
# ],
|
|
209
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
210
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
211
|
+
# ("""{
|
|
212
|
+
# "users": [
|
|
213
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
214
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
215
|
+
# ],
|
|
216
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
217
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
218
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (0 """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""") .
|
|
219
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/id") string:jsonPointer "u1" .
|
|
220
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/email") string:jsonPointer "ada@example.org" .
|
|
221
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
222
|
+
# ("ada@example.org" "@([^@]+)$") string:scrape "example.org" .
|
|
223
|
+
# ("example.org" "example.com") list:member "example.org" .
|
|
224
|
+
# ("urn:example:user:%s" "u1") string:format "urn:example:user:u1" .
|
|
225
|
+
# <urn:example:user:u1> log:uri "urn:example:user:u1" .
|
|
226
|
+
# via the schematic forward rule:
|
|
227
|
+
# {
|
|
228
|
+
# ex:doc ex:json ?J .
|
|
229
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
230
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
231
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
232
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
233
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
234
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
235
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
236
|
+
# ?Allowed list:member ?EmailDomain .
|
|
237
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
238
|
+
# ?User log:uri ?UriStr .
|
|
239
|
+
# } => {
|
|
240
|
+
# ?User a ex:AllowedUser .
|
|
241
|
+
# ?User ex:name ?Name .
|
|
242
|
+
# ?User ex:email ?Email .
|
|
243
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
244
|
+
# ?User ex:userIndex ?Idx .
|
|
245
|
+
# } .
|
|
246
|
+
# with substitution (on rule variables):
|
|
247
|
+
# ?Allowed = ("example.org" "example.com")
|
|
248
|
+
# ?Email = "ada@example.org"
|
|
249
|
+
# ?EmailDomain = "example.org"
|
|
250
|
+
# ?Id = "u1"
|
|
251
|
+
# ?Idx = 0
|
|
252
|
+
# ?J = """{
|
|
253
|
+
# "users": [
|
|
254
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
255
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
256
|
+
# ],
|
|
257
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
258
|
+
# }"""
|
|
259
|
+
# ?Name = "Ada Lovelace"
|
|
260
|
+
# ?UriStr = "urn:example:user:u1"
|
|
261
|
+
# ?User = <urn:example:user:u1>
|
|
262
|
+
# ?UserJson = """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}"""
|
|
263
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
264
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
265
|
+
# ----------------------------------------------------------------------
|
|
266
|
+
|
|
267
|
+
<urn:example:user:u1> ex:email "ada@example.org" .
|
|
268
|
+
|
|
269
|
+
# ----------------------------------------------------------------------
|
|
270
|
+
# Proof for derived triple:
|
|
271
|
+
# <urn:example:user:u1> ex:emailDomain "example.org" .
|
|
272
|
+
# It holds because the following instance of the rule body is provable:
|
|
273
|
+
# ex:doc ex:json """{
|
|
274
|
+
# "users": [
|
|
275
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
276
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
277
|
+
# ],
|
|
278
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
279
|
+
# }""" .
|
|
280
|
+
# ("""{
|
|
281
|
+
# "users": [
|
|
282
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
283
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
284
|
+
# ],
|
|
285
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
286
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
287
|
+
# ("""{
|
|
288
|
+
# "users": [
|
|
289
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
290
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
291
|
+
# ],
|
|
292
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
293
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
294
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (0 """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""") .
|
|
295
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/id") string:jsonPointer "u1" .
|
|
296
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/email") string:jsonPointer "ada@example.org" .
|
|
297
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
298
|
+
# ("ada@example.org" "@([^@]+)$") string:scrape "example.org" .
|
|
299
|
+
# ("example.org" "example.com") list:member "example.org" .
|
|
300
|
+
# ("urn:example:user:%s" "u1") string:format "urn:example:user:u1" .
|
|
301
|
+
# <urn:example:user:u1> log:uri "urn:example:user:u1" .
|
|
302
|
+
# via the schematic forward rule:
|
|
303
|
+
# {
|
|
304
|
+
# ex:doc ex:json ?J .
|
|
305
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
306
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
307
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
308
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
309
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
310
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
311
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
312
|
+
# ?Allowed list:member ?EmailDomain .
|
|
313
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
314
|
+
# ?User log:uri ?UriStr .
|
|
315
|
+
# } => {
|
|
316
|
+
# ?User a ex:AllowedUser .
|
|
317
|
+
# ?User ex:name ?Name .
|
|
318
|
+
# ?User ex:email ?Email .
|
|
319
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
320
|
+
# ?User ex:userIndex ?Idx .
|
|
321
|
+
# } .
|
|
322
|
+
# with substitution (on rule variables):
|
|
323
|
+
# ?Allowed = ("example.org" "example.com")
|
|
324
|
+
# ?Email = "ada@example.org"
|
|
325
|
+
# ?EmailDomain = "example.org"
|
|
326
|
+
# ?Id = "u1"
|
|
327
|
+
# ?Idx = 0
|
|
328
|
+
# ?J = """{
|
|
329
|
+
# "users": [
|
|
330
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
331
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
332
|
+
# ],
|
|
333
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
334
|
+
# }"""
|
|
335
|
+
# ?Name = "Ada Lovelace"
|
|
336
|
+
# ?UriStr = "urn:example:user:u1"
|
|
337
|
+
# ?User = <urn:example:user:u1>
|
|
338
|
+
# ?UserJson = """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}"""
|
|
339
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
340
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
341
|
+
# ----------------------------------------------------------------------
|
|
342
|
+
|
|
343
|
+
<urn:example:user:u1> ex:emailDomain "example.org" .
|
|
344
|
+
|
|
345
|
+
# ----------------------------------------------------------------------
|
|
346
|
+
# Proof for derived triple:
|
|
347
|
+
# <urn:example:user:u1> ex:userIndex 0 .
|
|
348
|
+
# It holds because the following instance of the rule body is provable:
|
|
349
|
+
# ex:doc ex:json """{
|
|
350
|
+
# "users": [
|
|
351
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
352
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
353
|
+
# ],
|
|
354
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
355
|
+
# }""" .
|
|
356
|
+
# ("""{
|
|
357
|
+
# "users": [
|
|
358
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
359
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
360
|
+
# ],
|
|
361
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
362
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
363
|
+
# ("""{
|
|
364
|
+
# "users": [
|
|
365
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
366
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
367
|
+
# ],
|
|
368
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
369
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
370
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (0 """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""") .
|
|
371
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/id") string:jsonPointer "u1" .
|
|
372
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/email") string:jsonPointer "ada@example.org" .
|
|
373
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" "/profile~1name") string:jsonPointer "Ada Lovelace" .
|
|
374
|
+
# ("ada@example.org" "@([^@]+)$") string:scrape "example.org" .
|
|
375
|
+
# ("example.org" "example.com") list:member "example.org" .
|
|
376
|
+
# ("urn:example:user:%s" "u1") string:format "urn:example:user:u1" .
|
|
377
|
+
# <urn:example:user:u1> log:uri "urn:example:user:u1" .
|
|
378
|
+
# via the schematic forward rule:
|
|
379
|
+
# {
|
|
380
|
+
# ex:doc ex:json ?J .
|
|
381
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
382
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
383
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
384
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
385
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
386
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
387
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
388
|
+
# ?Allowed list:member ?EmailDomain .
|
|
389
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
390
|
+
# ?User log:uri ?UriStr .
|
|
391
|
+
# } => {
|
|
392
|
+
# ?User a ex:AllowedUser .
|
|
393
|
+
# ?User ex:name ?Name .
|
|
394
|
+
# ?User ex:email ?Email .
|
|
395
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
396
|
+
# ?User ex:userIndex ?Idx .
|
|
397
|
+
# } .
|
|
398
|
+
# with substitution (on rule variables):
|
|
399
|
+
# ?Allowed = ("example.org" "example.com")
|
|
400
|
+
# ?Email = "ada@example.org"
|
|
401
|
+
# ?EmailDomain = "example.org"
|
|
402
|
+
# ?Id = "u1"
|
|
403
|
+
# ?Idx = 0
|
|
404
|
+
# ?J = """{
|
|
405
|
+
# "users": [
|
|
406
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
407
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
408
|
+
# ],
|
|
409
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
410
|
+
# }"""
|
|
411
|
+
# ?Name = "Ada Lovelace"
|
|
412
|
+
# ?UriStr = "urn:example:user:u1"
|
|
413
|
+
# ?User = <urn:example:user:u1>
|
|
414
|
+
# ?UserJson = """{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}"""
|
|
415
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
416
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
417
|
+
# ----------------------------------------------------------------------
|
|
418
|
+
|
|
419
|
+
<urn:example:user:u1> ex:userIndex 0 .
|
|
420
|
+
|
|
421
|
+
# ----------------------------------------------------------------------
|
|
422
|
+
# Proof for derived triple:
|
|
423
|
+
# <urn:example:user:u2> a ex:BlockedUser .
|
|
424
|
+
# It holds because the following instance of the rule body is provable:
|
|
425
|
+
# ex:doc ex:json """{
|
|
426
|
+
# "users": [
|
|
427
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
428
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
429
|
+
# ],
|
|
430
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
431
|
+
# }""" .
|
|
432
|
+
# ("""{
|
|
433
|
+
# "users": [
|
|
434
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
435
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
436
|
+
# ],
|
|
437
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
438
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
439
|
+
# ("""{
|
|
440
|
+
# "users": [
|
|
441
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
442
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
443
|
+
# ],
|
|
444
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
445
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
446
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (1 """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
447
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/id") string:jsonPointer "u2" .
|
|
448
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/email") string:jsonPointer "bob@evil.invalid" .
|
|
449
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/profile~1name") string:jsonPointer "Bob Mallory" .
|
|
450
|
+
# ("bob@evil.invalid" "@([^@]+)$") string:scrape "evil.invalid" .
|
|
451
|
+
# ("urn:example:user:%s" "u2") string:format "urn:example:user:u2" .
|
|
452
|
+
# <urn:example:user:u2> log:uri "urn:example:user:u2" .
|
|
453
|
+
# ("example.org" "example.com") list:notMember "evil.invalid" .
|
|
454
|
+
# via the schematic forward rule:
|
|
455
|
+
# {
|
|
456
|
+
# ex:doc ex:json ?J .
|
|
457
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
458
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
459
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
460
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
461
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
462
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
463
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
464
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
465
|
+
# ?User log:uri ?UriStr .
|
|
466
|
+
# ?Allowed list:notMember ?EmailDomain .
|
|
467
|
+
# } => {
|
|
468
|
+
# ?User a ex:BlockedUser .
|
|
469
|
+
# ?User ex:name ?Name .
|
|
470
|
+
# ?User ex:email ?Email .
|
|
471
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
472
|
+
# ?User ex:userIndex ?Idx .
|
|
473
|
+
# } .
|
|
474
|
+
# with substitution (on rule variables):
|
|
475
|
+
# ?Allowed = ("example.org" "example.com")
|
|
476
|
+
# ?Email = "bob@evil.invalid"
|
|
477
|
+
# ?EmailDomain = "evil.invalid"
|
|
478
|
+
# ?Id = "u2"
|
|
479
|
+
# ?Idx = 1
|
|
480
|
+
# ?J = """{
|
|
481
|
+
# "users": [
|
|
482
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
483
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
484
|
+
# ],
|
|
485
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
486
|
+
# }"""
|
|
487
|
+
# ?Name = "Bob Mallory"
|
|
488
|
+
# ?UriStr = "urn:example:user:u2"
|
|
489
|
+
# ?User = <urn:example:user:u2>
|
|
490
|
+
# ?UserJson = """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}"""
|
|
491
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
492
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
493
|
+
# ----------------------------------------------------------------------
|
|
494
|
+
|
|
495
|
+
<urn:example:user:u2> a ex:BlockedUser .
|
|
496
|
+
|
|
497
|
+
# ----------------------------------------------------------------------
|
|
498
|
+
# Proof for derived triple:
|
|
499
|
+
# <urn:example:user:u2> ex:name "Bob Mallory" .
|
|
500
|
+
# It holds because the following instance of the rule body is provable:
|
|
501
|
+
# ex:doc ex:json """{
|
|
502
|
+
# "users": [
|
|
503
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
504
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
505
|
+
# ],
|
|
506
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
507
|
+
# }""" .
|
|
508
|
+
# ("""{
|
|
509
|
+
# "users": [
|
|
510
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
511
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
512
|
+
# ],
|
|
513
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
514
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
515
|
+
# ("""{
|
|
516
|
+
# "users": [
|
|
517
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
518
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
519
|
+
# ],
|
|
520
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
521
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
522
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (1 """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
523
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/id") string:jsonPointer "u2" .
|
|
524
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/email") string:jsonPointer "bob@evil.invalid" .
|
|
525
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/profile~1name") string:jsonPointer "Bob Mallory" .
|
|
526
|
+
# ("bob@evil.invalid" "@([^@]+)$") string:scrape "evil.invalid" .
|
|
527
|
+
# ("urn:example:user:%s" "u2") string:format "urn:example:user:u2" .
|
|
528
|
+
# <urn:example:user:u2> log:uri "urn:example:user:u2" .
|
|
529
|
+
# ("example.org" "example.com") list:notMember "evil.invalid" .
|
|
530
|
+
# via the schematic forward rule:
|
|
531
|
+
# {
|
|
532
|
+
# ex:doc ex:json ?J .
|
|
533
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
534
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
535
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
536
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
537
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
538
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
539
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
540
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
541
|
+
# ?User log:uri ?UriStr .
|
|
542
|
+
# ?Allowed list:notMember ?EmailDomain .
|
|
543
|
+
# } => {
|
|
544
|
+
# ?User a ex:BlockedUser .
|
|
545
|
+
# ?User ex:name ?Name .
|
|
546
|
+
# ?User ex:email ?Email .
|
|
547
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
548
|
+
# ?User ex:userIndex ?Idx .
|
|
549
|
+
# } .
|
|
550
|
+
# with substitution (on rule variables):
|
|
551
|
+
# ?Allowed = ("example.org" "example.com")
|
|
552
|
+
# ?Email = "bob@evil.invalid"
|
|
553
|
+
# ?EmailDomain = "evil.invalid"
|
|
554
|
+
# ?Id = "u2"
|
|
555
|
+
# ?Idx = 1
|
|
556
|
+
# ?J = """{
|
|
557
|
+
# "users": [
|
|
558
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
559
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
560
|
+
# ],
|
|
561
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
562
|
+
# }"""
|
|
563
|
+
# ?Name = "Bob Mallory"
|
|
564
|
+
# ?UriStr = "urn:example:user:u2"
|
|
565
|
+
# ?User = <urn:example:user:u2>
|
|
566
|
+
# ?UserJson = """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}"""
|
|
567
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
568
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
569
|
+
# ----------------------------------------------------------------------
|
|
570
|
+
|
|
571
|
+
<urn:example:user:u2> ex:name "Bob Mallory" .
|
|
572
|
+
|
|
573
|
+
# ----------------------------------------------------------------------
|
|
574
|
+
# Proof for derived triple:
|
|
575
|
+
# <urn:example:user:u2> ex:email "bob@evil.invalid" .
|
|
576
|
+
# It holds because the following instance of the rule body is provable:
|
|
577
|
+
# ex:doc ex:json """{
|
|
578
|
+
# "users": [
|
|
579
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
580
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
581
|
+
# ],
|
|
582
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
583
|
+
# }""" .
|
|
584
|
+
# ("""{
|
|
585
|
+
# "users": [
|
|
586
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
587
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
588
|
+
# ],
|
|
589
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
590
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
591
|
+
# ("""{
|
|
592
|
+
# "users": [
|
|
593
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
594
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
595
|
+
# ],
|
|
596
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
597
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
598
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (1 """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
599
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/id") string:jsonPointer "u2" .
|
|
600
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/email") string:jsonPointer "bob@evil.invalid" .
|
|
601
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/profile~1name") string:jsonPointer "Bob Mallory" .
|
|
602
|
+
# ("bob@evil.invalid" "@([^@]+)$") string:scrape "evil.invalid" .
|
|
603
|
+
# ("urn:example:user:%s" "u2") string:format "urn:example:user:u2" .
|
|
604
|
+
# <urn:example:user:u2> log:uri "urn:example:user:u2" .
|
|
605
|
+
# ("example.org" "example.com") list:notMember "evil.invalid" .
|
|
606
|
+
# via the schematic forward rule:
|
|
607
|
+
# {
|
|
608
|
+
# ex:doc ex:json ?J .
|
|
609
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
610
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
611
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
612
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
613
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
614
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
615
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
616
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
617
|
+
# ?User log:uri ?UriStr .
|
|
618
|
+
# ?Allowed list:notMember ?EmailDomain .
|
|
619
|
+
# } => {
|
|
620
|
+
# ?User a ex:BlockedUser .
|
|
621
|
+
# ?User ex:name ?Name .
|
|
622
|
+
# ?User ex:email ?Email .
|
|
623
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
624
|
+
# ?User ex:userIndex ?Idx .
|
|
625
|
+
# } .
|
|
626
|
+
# with substitution (on rule variables):
|
|
627
|
+
# ?Allowed = ("example.org" "example.com")
|
|
628
|
+
# ?Email = "bob@evil.invalid"
|
|
629
|
+
# ?EmailDomain = "evil.invalid"
|
|
630
|
+
# ?Id = "u2"
|
|
631
|
+
# ?Idx = 1
|
|
632
|
+
# ?J = """{
|
|
633
|
+
# "users": [
|
|
634
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
635
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
636
|
+
# ],
|
|
637
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
638
|
+
# }"""
|
|
639
|
+
# ?Name = "Bob Mallory"
|
|
640
|
+
# ?UriStr = "urn:example:user:u2"
|
|
641
|
+
# ?User = <urn:example:user:u2>
|
|
642
|
+
# ?UserJson = """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}"""
|
|
643
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
644
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
645
|
+
# ----------------------------------------------------------------------
|
|
646
|
+
|
|
647
|
+
<urn:example:user:u2> ex:email "bob@evil.invalid" .
|
|
648
|
+
|
|
649
|
+
# ----------------------------------------------------------------------
|
|
650
|
+
# Proof for derived triple:
|
|
651
|
+
# <urn:example:user:u2> ex:emailDomain "evil.invalid" .
|
|
652
|
+
# It holds because the following instance of the rule body is provable:
|
|
653
|
+
# ex:doc ex:json """{
|
|
654
|
+
# "users": [
|
|
655
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
656
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
657
|
+
# ],
|
|
658
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
659
|
+
# }""" .
|
|
660
|
+
# ("""{
|
|
661
|
+
# "users": [
|
|
662
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
663
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
664
|
+
# ],
|
|
665
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
666
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
667
|
+
# ("""{
|
|
668
|
+
# "users": [
|
|
669
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
670
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
671
|
+
# ],
|
|
672
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
673
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
674
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (1 """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
675
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/id") string:jsonPointer "u2" .
|
|
676
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/email") string:jsonPointer "bob@evil.invalid" .
|
|
677
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/profile~1name") string:jsonPointer "Bob Mallory" .
|
|
678
|
+
# ("bob@evil.invalid" "@([^@]+)$") string:scrape "evil.invalid" .
|
|
679
|
+
# ("urn:example:user:%s" "u2") string:format "urn:example:user:u2" .
|
|
680
|
+
# <urn:example:user:u2> log:uri "urn:example:user:u2" .
|
|
681
|
+
# ("example.org" "example.com") list:notMember "evil.invalid" .
|
|
682
|
+
# via the schematic forward rule:
|
|
683
|
+
# {
|
|
684
|
+
# ex:doc ex:json ?J .
|
|
685
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
686
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
687
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
688
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
689
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
690
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
691
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
692
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
693
|
+
# ?User log:uri ?UriStr .
|
|
694
|
+
# ?Allowed list:notMember ?EmailDomain .
|
|
695
|
+
# } => {
|
|
696
|
+
# ?User a ex:BlockedUser .
|
|
697
|
+
# ?User ex:name ?Name .
|
|
698
|
+
# ?User ex:email ?Email .
|
|
699
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
700
|
+
# ?User ex:userIndex ?Idx .
|
|
701
|
+
# } .
|
|
702
|
+
# with substitution (on rule variables):
|
|
703
|
+
# ?Allowed = ("example.org" "example.com")
|
|
704
|
+
# ?Email = "bob@evil.invalid"
|
|
705
|
+
# ?EmailDomain = "evil.invalid"
|
|
706
|
+
# ?Id = "u2"
|
|
707
|
+
# ?Idx = 1
|
|
708
|
+
# ?J = """{
|
|
709
|
+
# "users": [
|
|
710
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
711
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
712
|
+
# ],
|
|
713
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
714
|
+
# }"""
|
|
715
|
+
# ?Name = "Bob Mallory"
|
|
716
|
+
# ?UriStr = "urn:example:user:u2"
|
|
717
|
+
# ?User = <urn:example:user:u2>
|
|
718
|
+
# ?UserJson = """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}"""
|
|
719
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
720
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
721
|
+
# ----------------------------------------------------------------------
|
|
722
|
+
|
|
723
|
+
<urn:example:user:u2> ex:emailDomain "evil.invalid" .
|
|
724
|
+
|
|
725
|
+
# ----------------------------------------------------------------------
|
|
726
|
+
# Proof for derived triple:
|
|
727
|
+
# <urn:example:user:u2> ex:userIndex 1 .
|
|
728
|
+
# It holds because the following instance of the rule body is provable:
|
|
729
|
+
# ex:doc ex:json """{
|
|
730
|
+
# "users": [
|
|
731
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
732
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
733
|
+
# ],
|
|
734
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
735
|
+
# }""" .
|
|
736
|
+
# ("""{
|
|
737
|
+
# "users": [
|
|
738
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
739
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
740
|
+
# ],
|
|
741
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
742
|
+
# }""" "/policy/allowedDomains") string:jsonPointer ("example.org" "example.com") .
|
|
743
|
+
# ("""{
|
|
744
|
+
# "users": [
|
|
745
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
746
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
747
|
+
# ],
|
|
748
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
749
|
+
# }""" "/users") string:jsonPointer ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
750
|
+
# ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") list:iterate (1 """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""") .
|
|
751
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/id") string:jsonPointer "u2" .
|
|
752
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/email") string:jsonPointer "bob@evil.invalid" .
|
|
753
|
+
# ("""{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""" "/profile~1name") string:jsonPointer "Bob Mallory" .
|
|
754
|
+
# ("bob@evil.invalid" "@([^@]+)$") string:scrape "evil.invalid" .
|
|
755
|
+
# ("urn:example:user:%s" "u2") string:format "urn:example:user:u2" .
|
|
756
|
+
# <urn:example:user:u2> log:uri "urn:example:user:u2" .
|
|
757
|
+
# ("example.org" "example.com") list:notMember "evil.invalid" .
|
|
758
|
+
# via the schematic forward rule:
|
|
759
|
+
# {
|
|
760
|
+
# ex:doc ex:json ?J .
|
|
761
|
+
# (?J "/policy/allowedDomains") string:jsonPointer ?Allowed .
|
|
762
|
+
# (?J "/users") string:jsonPointer ?Users .
|
|
763
|
+
# ?Users list:iterate (?Idx ?UserJson) .
|
|
764
|
+
# (?UserJson "/id") string:jsonPointer ?Id .
|
|
765
|
+
# (?UserJson "/email") string:jsonPointer ?Email .
|
|
766
|
+
# (?UserJson "/profile~1name") string:jsonPointer ?Name .
|
|
767
|
+
# (?Email "@([^@]+)$") string:scrape ?EmailDomain .
|
|
768
|
+
# ("urn:example:user:%s" ?Id) string:format ?UriStr .
|
|
769
|
+
# ?User log:uri ?UriStr .
|
|
770
|
+
# ?Allowed list:notMember ?EmailDomain .
|
|
771
|
+
# } => {
|
|
772
|
+
# ?User a ex:BlockedUser .
|
|
773
|
+
# ?User ex:name ?Name .
|
|
774
|
+
# ?User ex:email ?Email .
|
|
775
|
+
# ?User ex:emailDomain ?EmailDomain .
|
|
776
|
+
# ?User ex:userIndex ?Idx .
|
|
777
|
+
# } .
|
|
778
|
+
# with substitution (on rule variables):
|
|
779
|
+
# ?Allowed = ("example.org" "example.com")
|
|
780
|
+
# ?Email = "bob@evil.invalid"
|
|
781
|
+
# ?EmailDomain = "evil.invalid"
|
|
782
|
+
# ?Id = "u2"
|
|
783
|
+
# ?Idx = 1
|
|
784
|
+
# ?J = """{
|
|
785
|
+
# "users": [
|
|
786
|
+
# { "id": "u1", "email": "ada@example.org", "profile/name": "Ada Lovelace" },
|
|
787
|
+
# { "id": "u2", "email": "bob@evil.invalid", "profile/name": "Bob Mallory" }
|
|
788
|
+
# ],
|
|
789
|
+
# "policy": { "allowedDomains": ["example.org", "example.com"] }
|
|
790
|
+
# }"""
|
|
791
|
+
# ?Name = "Bob Mallory"
|
|
792
|
+
# ?UriStr = "urn:example:user:u2"
|
|
793
|
+
# ?User = <urn:example:user:u2>
|
|
794
|
+
# ?UserJson = """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}"""
|
|
795
|
+
# ?Users = ("""{"id":"u1","email":"ada@example.org","profile/name":"Ada Lovelace"}""" """{"id":"u2","email":"bob@evil.invalid","profile/name":"Bob Mallory"}""")
|
|
796
|
+
# Therefore the derived triple above is entailed by the rules and facts.
|
|
797
|
+
# ----------------------------------------------------------------------
|
|
798
|
+
|
|
799
|
+
<urn:example:user:u2> ex:userIndex 1 .
|
|
800
|
+
|
package/eyeling.js
CHANGED
|
@@ -39,6 +39,9 @@ const SKOLEM_NS = "https://eyereasoner.github.io/.well-known/genid/";
|
|
|
39
39
|
// of the subject term in log:skolem to a Skolem IRI.
|
|
40
40
|
const skolemCache = new Map();
|
|
41
41
|
|
|
42
|
+
// Cache for string:jsonPointer: jsonText -> { parsed: any|null, ptrCache: Map<string, Term|null> }
|
|
43
|
+
const jsonPointerCache = new Map();
|
|
44
|
+
|
|
42
45
|
// Controls whether human-readable proof comments are printed.
|
|
43
46
|
let proofCommentsEnabled = true;
|
|
44
47
|
|
|
@@ -1819,6 +1822,195 @@ function makeStringLiteral(str) {
|
|
|
1819
1822
|
return new Literal(JSON.stringify(str));
|
|
1820
1823
|
}
|
|
1821
1824
|
|
|
1825
|
+
function termToJsStringDecoded(t) {
|
|
1826
|
+
// Like termToJsString, but for short literals it *also* interprets escapes
|
|
1827
|
+
// (\" \n \uXXXX …) by attempting JSON.parse on the quoted lexical form.
|
|
1828
|
+
if (!(t instanceof Literal)) return null;
|
|
1829
|
+
const [lex, _dt] = literalParts(t.value);
|
|
1830
|
+
|
|
1831
|
+
// Long strings: """ ... """ are taken verbatim.
|
|
1832
|
+
if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
|
|
1833
|
+
return lex.slice(3, -3);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
// Short strings: try to decode escapes (this makes "{\"a\":1}" usable too).
|
|
1837
|
+
if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
|
|
1838
|
+
try { return JSON.parse(lex); } catch (e) { /* fall through */ }
|
|
1839
|
+
return stripQuotes(lex);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
return stripQuotes(lex);
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
function _jsonPointerUnescape(seg) {
|
|
1846
|
+
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
1847
|
+
// Any other '~' escape is invalid.
|
|
1848
|
+
let out = "";
|
|
1849
|
+
for (let i = 0; i < seg.length; i++) {
|
|
1850
|
+
const c = seg[i];
|
|
1851
|
+
if (c !== "~") { out += c; continue; }
|
|
1852
|
+
if (i + 1 >= seg.length) return null;
|
|
1853
|
+
const n = seg[i + 1];
|
|
1854
|
+
if (n === "0") out += "~";
|
|
1855
|
+
else if (n === "1") out += "/";
|
|
1856
|
+
else return null;
|
|
1857
|
+
i++;
|
|
1858
|
+
}
|
|
1859
|
+
return out;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
function _jsonToTerm(v) {
|
|
1863
|
+
if (v === null) return makeStringLiteral("null");
|
|
1864
|
+
if (typeof v === "string") return makeStringLiteral(v);
|
|
1865
|
+
if (typeof v === "number") return new Literal(String(v));
|
|
1866
|
+
if (typeof v === "boolean") return new Literal(v ? "true" : "false");
|
|
1867
|
+
if (Array.isArray(v)) return new ListTerm(v.map(_jsonToTerm));
|
|
1868
|
+
if (typeof v === "object") return makeStringLiteral(JSON.stringify(v));
|
|
1869
|
+
return null;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
function _jsonPointerLookup(jsonText, pointer) {
|
|
1873
|
+
// Support URI fragment form "#/a/b" (percent-decoded) as well.
|
|
1874
|
+
let ptr = pointer;
|
|
1875
|
+
if (ptr.startsWith("#")) {
|
|
1876
|
+
try { ptr = decodeURIComponent(ptr.slice(1)); } catch (e) { return null; }
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
// Cache per JSON document
|
|
1880
|
+
let entry = jsonPointerCache.get(jsonText);
|
|
1881
|
+
if (!entry) {
|
|
1882
|
+
let parsed = null;
|
|
1883
|
+
try { parsed = JSON.parse(jsonText); } catch (e) { parsed = null; }
|
|
1884
|
+
entry = { parsed, ptrCache: new Map() };
|
|
1885
|
+
jsonPointerCache.set(jsonText, entry);
|
|
1886
|
+
}
|
|
1887
|
+
if (entry.parsed === null) return null;
|
|
1888
|
+
|
|
1889
|
+
// Cache per pointer within this doc
|
|
1890
|
+
if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
|
|
1891
|
+
|
|
1892
|
+
let cur = entry.parsed;
|
|
1893
|
+
|
|
1894
|
+
if (ptr === "") {
|
|
1895
|
+
const t = _jsonToTerm(cur);
|
|
1896
|
+
entry.ptrCache.set(ptr, t);
|
|
1897
|
+
return t;
|
|
1898
|
+
}
|
|
1899
|
+
if (!ptr.startsWith("/")) { entry.ptrCache.set(ptr, null); return null; }
|
|
1900
|
+
|
|
1901
|
+
const parts = ptr.split("/").slice(1);
|
|
1902
|
+
for (const raw of parts) {
|
|
1903
|
+
const seg = _jsonPointerUnescape(raw);
|
|
1904
|
+
if (seg === null) { entry.ptrCache.set(ptr, null); return null; }
|
|
1905
|
+
|
|
1906
|
+
if (Array.isArray(cur)) {
|
|
1907
|
+
// JSON Pointer uses array indices as decimal strings
|
|
1908
|
+
if (!/^(0|[1-9]\d*)$/.test(seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
1909
|
+
const idx = Number(seg);
|
|
1910
|
+
if (!Number.isFinite(idx) || idx < 0 || idx >= cur.length) { entry.ptrCache.set(ptr, null); return null; }
|
|
1911
|
+
cur = cur[idx];
|
|
1912
|
+
continue;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (cur !== null && typeof cur === "object") {
|
|
1916
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
1917
|
+
cur = cur[seg];
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
entry.ptrCache.set(ptr, null);
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
const out = _jsonToTerm(cur);
|
|
1926
|
+
entry.ptrCache.set(ptr, out);
|
|
1927
|
+
return out;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
function jsonPointerUnescape(seg) {
|
|
1931
|
+
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
1932
|
+
let out = "";
|
|
1933
|
+
for (let i = 0; i < seg.length; i++) {
|
|
1934
|
+
const c = seg[i];
|
|
1935
|
+
if (c !== "~") { out += c; continue; }
|
|
1936
|
+
if (i + 1 >= seg.length) return null;
|
|
1937
|
+
const n = seg[i + 1];
|
|
1938
|
+
if (n === "0") out += "~";
|
|
1939
|
+
else if (n === "1") out += "/";
|
|
1940
|
+
else return null;
|
|
1941
|
+
i++;
|
|
1942
|
+
}
|
|
1943
|
+
return out;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
function jsonToTerm(v) {
|
|
1947
|
+
if (v === null) return makeStringLiteral("null");
|
|
1948
|
+
if (typeof v === "string") return makeStringLiteral(v);
|
|
1949
|
+
if (typeof v === "number") return new Literal(String(v));
|
|
1950
|
+
if (typeof v === "boolean") return new Literal(v ? "true" : "false");
|
|
1951
|
+
if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
|
|
1952
|
+
|
|
1953
|
+
if (v && typeof v === "object") {
|
|
1954
|
+
// IMPORTANT: long literal so it can be parsed again via termToJsString()
|
|
1955
|
+
// without needing escape decoding.
|
|
1956
|
+
const raw = JSON.stringify(v);
|
|
1957
|
+
return new Literal('"""' + raw + '"""');
|
|
1958
|
+
}
|
|
1959
|
+
return null;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
function jsonPointerLookup(jsonText, pointer) {
|
|
1963
|
+
let ptr = pointer;
|
|
1964
|
+
|
|
1965
|
+
// Support URI fragment form "#/a/b"
|
|
1966
|
+
if (ptr.startsWith("#")) {
|
|
1967
|
+
try { ptr = decodeURIComponent(ptr.slice(1)); } catch { return null; }
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
let entry = jsonPointerCache.get(jsonText);
|
|
1971
|
+
if (!entry) {
|
|
1972
|
+
let parsed = null;
|
|
1973
|
+
try { parsed = JSON.parse(jsonText); } catch { parsed = null; }
|
|
1974
|
+
entry = { parsed, ptrCache: new Map() };
|
|
1975
|
+
jsonPointerCache.set(jsonText, entry);
|
|
1976
|
+
}
|
|
1977
|
+
if (entry.parsed === null) return null;
|
|
1978
|
+
|
|
1979
|
+
if (entry.ptrCache.has(ptr)) return entry.ptrCache.get(ptr);
|
|
1980
|
+
|
|
1981
|
+
let cur = entry.parsed;
|
|
1982
|
+
|
|
1983
|
+
if (ptr === "") {
|
|
1984
|
+
const t = jsonToTerm(cur);
|
|
1985
|
+
entry.ptrCache.set(ptr, t);
|
|
1986
|
+
return t;
|
|
1987
|
+
}
|
|
1988
|
+
if (!ptr.startsWith("/")) { entry.ptrCache.set(ptr, null); return null; }
|
|
1989
|
+
|
|
1990
|
+
const parts = ptr.split("/").slice(1);
|
|
1991
|
+
for (const raw of parts) {
|
|
1992
|
+
const seg = jsonPointerUnescape(raw);
|
|
1993
|
+
if (seg === null) { entry.ptrCache.set(ptr, null); return null; }
|
|
1994
|
+
|
|
1995
|
+
if (Array.isArray(cur)) {
|
|
1996
|
+
if (!/^(0|[1-9]\d*)$/.test(seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
1997
|
+
const idx = Number(seg);
|
|
1998
|
+
if (idx < 0 || idx >= cur.length) { entry.ptrCache.set(ptr, null); return null; }
|
|
1999
|
+
cur = cur[idx];
|
|
2000
|
+
} else if (cur !== null && typeof cur === "object") {
|
|
2001
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) { entry.ptrCache.set(ptr, null); return null; }
|
|
2002
|
+
cur = cur[seg];
|
|
2003
|
+
} else {
|
|
2004
|
+
entry.ptrCache.set(ptr, null);
|
|
2005
|
+
return null;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
const out = jsonToTerm(cur);
|
|
2010
|
+
entry.ptrCache.set(ptr, out);
|
|
2011
|
+
return out;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
1822
2014
|
// Tiny subset of sprintf: supports only %s and %%.
|
|
1823
2015
|
// Good enough for most N3 string:format use cases that just splice strings.
|
|
1824
2016
|
function simpleStringFormat(fmt, args) {
|
|
@@ -3370,6 +3562,21 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3370
3562
|
return s2 !== null ? [s2] : [];
|
|
3371
3563
|
}
|
|
3372
3564
|
|
|
3565
|
+
// string:jsonPointer
|
|
3566
|
+
// Schema: ( $jsonText $pointer ) string:jsonPointer $value
|
|
3567
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + "jsonPointer") {
|
|
3568
|
+
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3569
|
+
const jsonText = termToJsString(g.s.elems[0]);
|
|
3570
|
+
const ptr = termToJsString(g.s.elems[1]);
|
|
3571
|
+
if (jsonText === null || ptr === null) return [];
|
|
3572
|
+
|
|
3573
|
+
const valTerm = jsonPointerLookup(jsonText, ptr);
|
|
3574
|
+
if (valTerm === null) return [];
|
|
3575
|
+
|
|
3576
|
+
const s2 = unifyTerm(g.o, valTerm, subst);
|
|
3577
|
+
return s2 !== null ? [s2] : [];
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3373
3580
|
// string:greaterThan
|
|
3374
3581
|
if (g.p instanceof Iri && g.p.value === STRING_NS + "greaterThan") {
|
|
3375
3582
|
const sStr = termToJsString(g.s);
|