@jarenjs/json 0.9.2
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/ARCHITECTURE.md +175 -0
- package/LICENSE +21 -0
- package/README.md +471 -0
- package/dist/types/basic.d.ts +32 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/jslt/dispatch.d.ts +11 -0
- package/dist/types/jslt/errors.d.ts +18 -0
- package/dist/types/jslt/index.d.ts +53 -0
- package/dist/types/jslt/stylesheet.d.ts +8 -0
- package/dist/types/jtlt/desugar.d.ts +19 -0
- package/dist/types/jtlt/errors.d.ts +18 -0
- package/dist/types/jtlt/index.d.ts +57 -0
- package/dist/types/jtlt/template.d.ts +8 -0
- package/dist/types/jtlt/writer.d.ts +6 -0
- package/dist/types/path.d.ts +235 -0
- package/dist/types/pointer.d.ts +114 -0
- package/dist/types/query/compile.d.ts +21 -0
- package/dist/types/query/errors.d.ts +18 -0
- package/dist/types/query/index.d.ts +70 -0
- package/dist/types/query/normalize.d.ts +68 -0
- package/dist/types/query/operators.d.ts +424 -0
- package/dist/types/query/runtime.d.ts +93 -0
- package/dist/types/segments.d.ts +62 -0
- package/dist/types/xquery/index.d.ts +19 -0
- package/dist/types/xquery/parse.d.ts +20 -0
- package/docs/JSLT-FORMAT.md +861 -0
- package/docs/JSLT-PRELUDE.md +159 -0
- package/docs/JTLT-FORMAT.md +659 -0
- package/docs/QUERY-FORMAT.md +1221 -0
- package/docs/XQUERY-FRONTEND.md +321 -0
- package/package.json +81 -0
- package/schemas/jaren-jslt.draft-07.schema.json +776 -0
- package/schemas/jaren-jslt.schema.json +776 -0
- package/schemas/jaren-query.draft-07.schema.json +613 -0
- package/schemas/jaren-query.schema.json +375 -0
- package/src/basic.js +300 -0
- package/src/index.js +4 -0
- package/src/jslt/dispatch.js +934 -0
- package/src/jslt/errors.js +34 -0
- package/src/jslt/index.js +121 -0
- package/src/jslt/stylesheet.js +234 -0
- package/src/jtlt/desugar.js +231 -0
- package/src/jtlt/errors.js +34 -0
- package/src/jtlt/index.js +155 -0
- package/src/jtlt/template.js +130 -0
- package/src/jtlt/writer.js +110 -0
- package/src/path.js +977 -0
- package/src/pointer.js +453 -0
- package/src/query/compile.js +817 -0
- package/src/query/errors.js +33 -0
- package/src/query/index.js +150 -0
- package/src/query/normalize.js +1047 -0
- package/src/query/operators.js +1253 -0
- package/src/query/runtime.js +233 -0
- package/src/segments.js +627 -0
- package/src/xquery/index.js +35 -0
- package/src/xquery/parse.js +1647 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# The XQuery Text Front-End
|
|
2
|
+
|
|
3
|
+
**Version 0.1 — Front-end guide (non-normative)**
|
|
4
|
+
|
|
5
|
+
Module: `@jarenjs/json/xquery`.
|
|
6
|
+
|
|
7
|
+
This document describes `parseXQuery(text)`: a parser for a defined
|
|
8
|
+
**subset of XQuery 3.1 text syntax** that emits Jaren JSON Query documents.
|
|
9
|
+
The JSON query document ([QUERY-FORMAT.md](./QUERY-FORMAT.md)) is the
|
|
10
|
+
canonical language; this front-end is (a) a human authoring syntax and (b)
|
|
11
|
+
the compatibility bridge that makes XQuery-oriented test material (the QT3
|
|
12
|
+
suite) runnable against the engine. It is **not a second engine**: the
|
|
13
|
+
output is always a query document that `compileJsonQuery` consumes, and
|
|
14
|
+
where the two languages disagree, the JSON format's semantics win.
|
|
15
|
+
QUERY-FORMAT.md is authoritative; this document only defines the text →
|
|
16
|
+
document mapping.
|
|
17
|
+
|
|
18
|
+
## 1. API
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import { parseXQuery, compileXQuery, XQuerySyntaxError } from '@jarenjs/json/xquery';
|
|
22
|
+
|
|
23
|
+
parseXQuery('for $x in (1,2,3) return $x * 2');
|
|
24
|
+
// -> { "$for": { "x": { "$seq": [1, 2, 3] } }, "$return": { "$mul": ["$x", 2] } }
|
|
25
|
+
|
|
26
|
+
const q = compileXQuery('for $b in $doc?store?book?* where $b?price lt 10 return $b?title');
|
|
27
|
+
q.externals; // ['doc']
|
|
28
|
+
q(null, { doc: data }); // parse + compile convenience; returns the engine's compiled query
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `parseXQuery(text) -> document` — a valid query document (the version
|
|
32
|
+
envelope is never emitted). The parser never emits an invalid document:
|
|
33
|
+
every output validates against `jaren-query.schema.json`.
|
|
34
|
+
- `compileXQuery(text, options?)` — `compileJsonQuery(parseXQuery(text), options)`;
|
|
35
|
+
returns the engine's compiled query function (`query(data, externals?)`,
|
|
36
|
+
`.first`, `.exists`, `.externals`, `.doc`).
|
|
37
|
+
- `XQuerySyntaxError extends SyntaxError` — carries `source` and `position`
|
|
38
|
+
(mirrors `JSONPathSyntaxError`). Constructs outside the subset fail with
|
|
39
|
+
stable, machine-greppable messages:
|
|
40
|
+
|
|
41
|
+
| Message shape | Meaning |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `unsupported construct '<name>'` | recognized XQuery construct outside the subset |
|
|
44
|
+
| `unsupported function '<name>'` / `unsupported function '<name>#<arity>'` | function (or an arity of one) outside the mapping table |
|
|
45
|
+
| `unsupported clause order: '<kw>' after '<kw>'` | FLWOR clause sequence that cannot be expressed by nesting (§5.1) |
|
|
46
|
+
| `unsupported variable name '<name>'`, `unsupported lookup index 0 ...` | lexeme outside the JSON format's rules |
|
|
47
|
+
|
|
48
|
+
Anything *not* prefixed `unsupported` is a plain syntax error — text that
|
|
49
|
+
is not valid XQuery 3.1 to begin with.
|
|
50
|
+
|
|
51
|
+
## 2. Accessing the input document
|
|
52
|
+
|
|
53
|
+
The JSON format's absolute paths (`"$.store.book[*]"`) have **no textual
|
|
54
|
+
XQuery equivalent in v1**: the context item `.` and `/`-rooted path
|
|
55
|
+
expressions are outside the subset. Bind the document (or any part of it)
|
|
56
|
+
as an **external parameter** instead — in the JSON format, use is the
|
|
57
|
+
declaration (QUERY-FORMAT.md §9), and `declare variable $doc external;` is
|
|
58
|
+
accepted for compatibility:
|
|
59
|
+
|
|
60
|
+
```xquery
|
|
61
|
+
declare variable $doc external;
|
|
62
|
+
for $b in $doc?store?book?*
|
|
63
|
+
where $b?price lt 10
|
|
64
|
+
return $b?title
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
compileXQuery(text)(null, { doc: inputDocument });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 3. Prominent caveats
|
|
72
|
+
|
|
73
|
+
> ### ⚠ 1-based XQuery vs 0-based JSON positions (D6)
|
|
74
|
+
>
|
|
75
|
+
> RFC 9535 and the JSON query format are 0-based (deviation **D6**);
|
|
76
|
+
> XQuery is 1-based. The front-end splits the difference along a single
|
|
77
|
+
> rule — **positional inputs are adjusted, positional outputs are not**:
|
|
78
|
+
>
|
|
79
|
+
> **Adjusted at parse time** (the text means what XQuery says it means):
|
|
80
|
+
> - `?N` lookups: `$b?1` → `"$b[0]"` (`?0` is an `unsupported lookup index` error);
|
|
81
|
+
> - `fn:substring` / `fn:subsequence` *start* arguments: `substring("hello", 2)`
|
|
82
|
+
> → `{"$substring": ["hello", 1]}` (a non-literal start emits
|
|
83
|
+
> `{"$sub": [start, 1]}`; length arguments are counts and pass through);
|
|
84
|
+
> - `array:get`: `array:get($a, 1)` → `{"$get": ["$a", 0]}`
|
|
85
|
+
> (`map:get` keys are values, not positions — never adjusted).
|
|
86
|
+
>
|
|
87
|
+
> **Not adjusted — 0-based values surface** (deviation carried into the
|
|
88
|
+
> front-end, because these are *bindings and results* the parser cannot
|
|
89
|
+
> locally rewrite):
|
|
90
|
+
> - `for $x at $i in ...` — `$i` counts from **0**, not 1;
|
|
91
|
+
> - `count $c` — `$c` counts from **0**;
|
|
92
|
+
> - `fn:index-of` — returned positions count from **0**.
|
|
93
|
+
|
|
94
|
+
> ### ⚠ Value comparisons are mapped to general comparisons
|
|
95
|
+
>
|
|
96
|
+
> `eq ne lt le gt ge` emit the same operators as `= != < <= > >=`
|
|
97
|
+
> (`$eq`-family, existential over sequences). For **singleton** operands
|
|
98
|
+
> the two behave identically. For non-singletons XQuery raises a type
|
|
99
|
+
> error on value comparisons while this mapping evaluates existentially,
|
|
100
|
+
> and `1 eq ()` is `false` here instead of XQuery's empty sequence (the
|
|
101
|
+
> difference disappears under EBV, e.g. in `where`). A front-end
|
|
102
|
+
> approximation — use singletons with value comparisons.
|
|
103
|
+
|
|
104
|
+
> ### ⚠ `fn:matches` maps to `$search`, and regexes are I-Regexp
|
|
105
|
+
>
|
|
106
|
+
> F&O `fn:matches` tests a **substring** match, which is the JSON format's
|
|
107
|
+
> `$search` (`$match` is the *anchored* RFC 9535 `match()` — no XQuery
|
|
108
|
+
> function maps to it). Patterns are **I-Regexp (RFC 9485)**, not XSD
|
|
109
|
+
> regular expressions (deviation **D5**); there is no flags argument
|
|
110
|
+
> (`matches#3`, `replace#4` are unsupported arities).
|
|
111
|
+
|
|
112
|
+
> ### ⚠ Square array constructors flatten their members
|
|
113
|
+
>
|
|
114
|
+
> `[E1, E2]` emits a JSON array constructor, which **flattens each
|
|
115
|
+
> member's sequence** (QUERY-FORMAT.md §3.4): `[(1,2), 3]` constructs
|
|
116
|
+
> `[1, 2, 3]` — three members. XQuery's square constructor would keep
|
|
117
|
+
> `(1,2)` as one sequence-valued member, which a JSON array cannot hold.
|
|
118
|
+
> `array { ... }` has identical flattening semantics in both languages.
|
|
119
|
+
> Members that are singletons (the JSON-shaped case) agree everywhere.
|
|
120
|
+
|
|
121
|
+
## 4. The supported subset
|
|
122
|
+
|
|
123
|
+
### 4.1 Prolog
|
|
124
|
+
|
|
125
|
+
| Construct | Handling |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `xquery version "3.1";` (optional `encoding "..."`) | parsed, ignored |
|
|
128
|
+
| `(: comments :)` (nestable) | whitespace, legal between any two tokens |
|
|
129
|
+
| `declare variable $x external;` | validated, emits nothing (use is the declaration, §2) |
|
|
130
|
+
| `declare variable $x := ...`, `... external := ...` | error `unsupported construct 'variable declaration with default value'` |
|
|
131
|
+
| any other `declare ...` (function, namespace, option, default, ...) | error `unsupported construct 'declare <kind>'` |
|
|
132
|
+
| `import module` / `import schema`, `module namespace` (library modules) | error `unsupported construct 'import module'` / `'library module'` |
|
|
133
|
+
|
|
134
|
+
### 4.2 Expressions, by precedence
|
|
135
|
+
|
|
136
|
+
| XQuery construct | Emitted JSON form |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `E1, E2, ...` (top level, in `( )`, in `if (...)`) | `{"$seq": [E1, E2, ...]}` |
|
|
139
|
+
| FLWOR `for/let/where/group by/order by/count/return` | FLWOR phrase, nested when needed (§5) |
|
|
140
|
+
| `some $x in E satisfies C` / `every ...` | `{"$some": {x: E}, "$satisfies": C}` / `$every` |
|
|
141
|
+
| `if (C) then T else E` | `{"$if": [C, T, E]}`; `else ()` folds to `{"$if": [C, T]}` |
|
|
142
|
+
| `A or B or ...` / `A and B and ...` | `{"$or": [A, B, ...]}` / `{"$and": [...]}` (variadic) |
|
|
143
|
+
| `= != < <= > >=` and `eq ne lt le gt ge` | `{"$eq": [L, R]}`, `$ne`, `$lt`, `$le`, `$gt`, `$ge` (caveat §3) |
|
|
144
|
+
| `A \|\| B \|\| ...` | `{"$concat": [A, B, ...]}` |
|
|
145
|
+
| `A to B` | `{"$range": [A, B]}` |
|
|
146
|
+
| `+ - * div idiv mod` | `$add $sub $mul $div $idiv $mod` (binary, left-associative) |
|
|
147
|
+
| unary `-E` / `+E` | `{"$neg": E}` (folded into number literals: `-5` → `-5`) / no-op |
|
|
148
|
+
| postfix lookup `?name ?N ?*` | path fold or `$get` (§4.3) |
|
|
149
|
+
| `map { K: V, ... }` | plain map constructor / `$map` (§4.4) |
|
|
150
|
+
| `[E, ...]`, `array { E }` | array constructor `[E, ...]` (flattening caveat §3) |
|
|
151
|
+
| `( E )` / `()` | the inner expression / `{"$seq": []}` |
|
|
152
|
+
| string literals (both quotes, `""`/`''` doubling) | literal string, `$$`-escaped when it starts with `$` (`"$price"` → `"$$price"`) |
|
|
153
|
+
| number literals (`7`, `.5`, `1.`, `1.5e2`, leading zeros allowed) | the JSON number value |
|
|
154
|
+
| `true()` / `false()` | `true` / `false` (XQuery has no boolean literals) |
|
|
155
|
+
| `$name` | `"$name"` (whole-variable reference) |
|
|
156
|
+
| function calls | operator vocabulary via the mapping table (§4.5) |
|
|
157
|
+
|
|
158
|
+
### 4.3 Postfix lookup and path folding
|
|
159
|
+
|
|
160
|
+
When the base is a **variable reference or a chain of lookups from one**,
|
|
161
|
+
the whole chain folds into one variable-rooted RFC 9535 path string —
|
|
162
|
+
per-item application over the variable's sequence, exactly XQuery's
|
|
163
|
+
postfix-lookup rule:
|
|
164
|
+
|
|
165
|
+
| Text | Emitted |
|
|
166
|
+
|---|---|
|
|
167
|
+
| `$b?price` | `"$b.price"` |
|
|
168
|
+
| `$b?price?1` | `"$b.price[0]"` (1-based → 0-based, §3) |
|
|
169
|
+
| `$doc?store?book?*` | `"$doc.store.book[*]"` |
|
|
170
|
+
| `$b?odd-name`, `$x?prénom` | `"$b['odd-name']"`, `"$x['prénom']"` (bracket form when not shorthand-safe) |
|
|
171
|
+
|
|
172
|
+
On **any other base**, each lookup emits dynamic `{"$get": [base, key]}`
|
|
173
|
+
(numeric keys 1-based → 0-based): `head($xs)?name` →
|
|
174
|
+
`{"$get": [{"$head": "$xs"}, "name"]}`.
|
|
175
|
+
|
|
176
|
+
> **`$get` addresses a single item.** If a non-variable base evaluates to
|
|
177
|
+
> a sequence of two or more items, `$get` yields the empty sequence
|
|
178
|
+
> instead of XQuery's per-item lookup. Bind the base with `let` and use a
|
|
179
|
+
> variable lookup for per-item semantics. Also `?name` on an array,
|
|
180
|
+
> `?N` out of bounds, and lookups on scalars yield the empty sequence
|
|
181
|
+
> where XQuery raises a type/range error.
|
|
182
|
+
|
|
183
|
+
`?*` on a non-variable base, parenthesized key specifiers `?(E)`, and
|
|
184
|
+
unary lookup (`?name` on the context item) are unsupported (§6).
|
|
185
|
+
|
|
186
|
+
### 4.4 Map constructors
|
|
187
|
+
|
|
188
|
+
`map { K: V, ... }` emits a **plain map constructor** `{K: V, ...}` when
|
|
189
|
+
every key is a string literal that does not start with `$`; otherwise the
|
|
190
|
+
general `{"$map": [[K, V], ...]}` form (computed keys must evaluate to a
|
|
191
|
+
single string at runtime, `JQ2004`). Literal keys that start with `$` are
|
|
192
|
+
`$$`-escaped inside `$map`: `map { "$for": 1 }` → `{"$map": [["$$for", 1]]}`.
|
|
193
|
+
|
|
194
|
+
Duplicate literal keys are rejected at parse time (XQuery's XQDY0137 made
|
|
195
|
+
static). Keys that are statically not strings (`map {1: "x"}`,
|
|
196
|
+
`map {true(): "x"}`) are `unsupported construct 'non-string map key'` —
|
|
197
|
+
JSON member names are strings.
|
|
198
|
+
|
|
199
|
+
### 4.5 Function mapping table
|
|
200
|
+
|
|
201
|
+
Bare and `fn:`-prefixed names are equivalent. Any other prefix, any name
|
|
202
|
+
not listed, or any arity not listed is an error (`unsupported function
|
|
203
|
+
'<name>'` / `'<name>#<arity>'`).
|
|
204
|
+
|
|
205
|
+
| Function | Arity | Emitted |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `count` | 1 | `{"$count": e}` |
|
|
208
|
+
| `sum`, `avg`, `min`, `max` | 1 | `$sum $avg $min $max` (collation/zero arities unsupported) |
|
|
209
|
+
| `exists`, `empty` | 1 | `$exists`, `$empty` |
|
|
210
|
+
| `not`, `boolean` | 1 | `$not`, `$boolean` |
|
|
211
|
+
| `string`, `number` | 1 | `$string`, `$number` (0-arg context forms unsupported) |
|
|
212
|
+
| `concat` | ≥ 2 | `{"$concat": [...]}` |
|
|
213
|
+
| `string-join` | 1–2 | `{"$string-join": [seq, sep?]}` |
|
|
214
|
+
| `substring` | 2–3 | `{"$substring": [s, start−1, len?]}` (**start adjusted**, §3) |
|
|
215
|
+
| `contains`, `starts-with`, `ends-with` | 2 | `$contains $starts-with $ends-with` |
|
|
216
|
+
| `upper-case`, `lower-case` | 1 | `$upper`, `$lower` |
|
|
217
|
+
| `string-length`, `normalize-space` | 1 | `$string-length`, `$normalize-space` |
|
|
218
|
+
| `matches` | 2 | `{"$search": [input, pattern]}` (**not** `$match`; §3) |
|
|
219
|
+
| `replace` | 3 | `{"$replace": [input, pattern, replacement]}` (I-Regexp, no flags) |
|
|
220
|
+
| `distinct-values` | 1 | `{"$distinct": e}` |
|
|
221
|
+
| `reverse`, `head`, `tail` | 1 | `$reverse`, `$head`, `$tail` |
|
|
222
|
+
| `subsequence` | 2–3 | `{"$subsequence": [seq, start−1, len?]}` (**start adjusted**, §3) |
|
|
223
|
+
| `index-of` | 2 | `{"$index-of": [seq, item]}` (**results 0-based**, §3) |
|
|
224
|
+
| `true`, `false` | 0 | the literals `true` / `false` |
|
|
225
|
+
| `map:get` | 2 | `{"$get": [map, key]}` (key never adjusted) |
|
|
226
|
+
| `array:get` | 2 | `{"$get": [array, pos−1]}` (**position adjusted**, §3) |
|
|
227
|
+
|
|
228
|
+
## 5. FLWOR
|
|
229
|
+
|
|
230
|
+
Clauses parse in source order, then pack into the JSON FLWOR phrase, whose
|
|
231
|
+
clause keys apply in the fixed semantic order `$for → $let → $where →
|
|
232
|
+
$groupby → $orderby → $count → $return` regardless of key order (D7).
|
|
233
|
+
Sequences that fit that order (with consecutive `for`s / `let`s merged
|
|
234
|
+
into one binding object) emit **one phrase**:
|
|
235
|
+
|
|
236
|
+
```xquery
|
|
237
|
+
for $b in $doc?store?book?*, $r in $doc?ratings?*
|
|
238
|
+
where $b?isbn = $r?isbn
|
|
239
|
+
order by $b?price
|
|
240
|
+
return map { "title": $b?title, "stars": $r?stars }
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{ "$for": { "b": "$doc.store.book[*]", "r": "$doc.ratings[*]" },
|
|
245
|
+
"$where": { "$eq": ["$b.isbn", "$r.isbn"] },
|
|
246
|
+
"$orderby": "$b.price",
|
|
247
|
+
"$return": { "title": "$b.title", "stars": "$r.stars" } }
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Everything else nests mechanically — sound for the **per-tuple** clauses
|
|
251
|
+
(`for`, `let`, `where`), because a phrase nested in `$return` runs once
|
|
252
|
+
per surviving tuple, which is exactly XQuery's tuple-stream semantics:
|
|
253
|
+
|
|
254
|
+
- `let` between `for`s, `for` after `where`, repeated `where`s → the
|
|
255
|
+
remainder becomes a nested phrase in `$return`;
|
|
256
|
+
- a remainder starting with `where` (no bindings of its own) emits
|
|
257
|
+
`{"$if": [condition, rest]}` — the per-tuple filter;
|
|
258
|
+
- name reuse (XQuery shadowing; one JSON phrase cannot bind a name twice,
|
|
259
|
+
`JQ0007`) also forces a split: `for $x in E let $x := $x + 1 ...`
|
|
260
|
+
nests, and the inner phrase shadows — exactly XQuery's scoping.
|
|
261
|
+
|
|
262
|
+
Other clause details:
|
|
263
|
+
|
|
264
|
+
- `for $x at $i in E` → `{"$in": E, "$at": "i"}` (`$i` is **0-based**, §3);
|
|
265
|
+
`allowing empty` is unsupported.
|
|
266
|
+
- `group by $k := E` (multiple specs comma-separated) → `"$groupby":
|
|
267
|
+
{"k": E, ...}`. The grouping variable must be **fresh** — the bare
|
|
268
|
+
rebinding form `group by $x` and `group by $x := ...` over an existing
|
|
269
|
+
name are unsupported (the JSON format's grouping key is always a new
|
|
270
|
+
variable, `JQ0007`).
|
|
271
|
+
- `order by` / `stable order by` (the engine's sort is always stable) with
|
|
272
|
+
`ascending | descending` and `empty least | greatest` modifiers →
|
|
273
|
+
`"$orderby"` key specs; defaults emit the bare key expression, explicit
|
|
274
|
+
non-defaults the `{"$key", "$dir", "$empty"}` form; `collation` is
|
|
275
|
+
unsupported. An array-constructor key always emits the explicit
|
|
276
|
+
`{"$key": [...]}` form (a bare array reads as a spec list).
|
|
277
|
+
- `count $c` → `"$count": "c"` (**0-based**, §3).
|
|
278
|
+
|
|
279
|
+
### 5.1 Unsupported clause orders
|
|
280
|
+
|
|
281
|
+
`group by`, `order by` and `count` operate on the **whole tuple stream**.
|
|
282
|
+
Nesting one under a phrase that iterates (`$for` or `$groupby` present)
|
|
283
|
+
would wrongly scope it to a single tuple, so such sequences are rejected
|
|
284
|
+
with `unsupported clause order: '<kw>' after '<kw>'` rather than
|
|
285
|
+
mis-evaluated. Examples: a second `order by` after a `for ... order by`,
|
|
286
|
+
`group by` after `order by`, `count` after `count`, `order by` after a
|
|
287
|
+
split forced by shadowing. (Equivalent single-phrase spellings — e.g.
|
|
288
|
+
moving the `where` before the `order by` — are supported.)
|
|
289
|
+
|
|
290
|
+
`where` after `group by`/`order by`/`count` is fine (per-tuple), and so is
|
|
291
|
+
anything already in fixed order — including `count $c` **followed by**
|
|
292
|
+
`where` (the filter nests as `$if`, preserving XQuery's
|
|
293
|
+
number-then-filter semantics).
|
|
294
|
+
|
|
295
|
+
## 6. Unsupported constructs (v1)
|
|
296
|
+
|
|
297
|
+
Each is recognized and rejected by name (`unsupported construct '...'`):
|
|
298
|
+
|
|
299
|
+
| Construct | Error name |
|
|
300
|
+
|---|---|
|
|
301
|
+
| `/`-rooted, `//`, relative paths, axis steps, `@attr`, `..`, bare names, `*` | `path expression` |
|
|
302
|
+
| context item `.` | `context item expression` |
|
|
303
|
+
| unary lookup `?name`, `?*` on non-variables, `?( E )` keys, `?0` | `unary lookup`, `wildcard lookup on a non-variable expression`, `parenthesized lookup key`, `unsupported lookup index 0` |
|
|
304
|
+
| predicates `E[...]` | `predicate` |
|
|
305
|
+
| dynamic calls `E(...)`, `name#arity`, inline `function(){}`, `?` placeholder | `dynamic function call`, `named function reference`, `inline function expression`, `argument placeholder` |
|
|
306
|
+
| `instance of`, `treat as`, `castable as`, `cast as` | `instance of`, `treat as`, `castable as`, `cast as` |
|
|
307
|
+
| `union` / `\|`, `intersect`, `except` | `union expression`, ... |
|
|
308
|
+
| node comparisons `is`, `<<`, `>>` | `node comparison` |
|
|
309
|
+
| arrow `=>`, simple map `!` | `arrow expression`, `simple map operator` |
|
|
310
|
+
| `switch`, `typeswitch`, `try { } catch { }` | `switch expression`, `typeswitch expression`, `try/catch expression` |
|
|
311
|
+
| direct (`<a/>`) and computed node constructors, `ordered {}`, `unordered {}`, `validate {}` | `node constructor`, `computed node constructor`, ... |
|
|
312
|
+
| type declarations `as T` (anywhere), `allowing empty`, window clauses, collations | `type declaration`, `allowing empty`, `window clause`, `collation` |
|
|
313
|
+
| string `&`-entities, non-finite number literals (`1e400`) | `character reference`, `non-finite number literal` |
|
|
314
|
+
| string constructors `` `...` ``, ` ``[...]`` ` | `string constructor` |
|
|
315
|
+
| annotations `declare %ann ...` | `annotation` |
|
|
316
|
+
| namespaced variables `$ns:x`; URI-qualified names `$Q{uri}x`; NCName variables outside `[A-Za-z_][A-Za-z0-9_]*` (e.g. `$foo-bar`) | `namespaced variable`, `URI-qualified name`, `unsupported variable name` |
|
|
317
|
+
| library modules, every non-`variable` prolog declaration | §4.1 |
|
|
318
|
+
|
|
319
|
+
**Prime v2 candidates** (noted for planning): the simple map operator `!`
|
|
320
|
+
and the arrow operator `=>` (both are sugar the emitter could expand),
|
|
321
|
+
parenthesized/dynamic lookup keys via `$get`, and positional predicates.
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jarenjs/json",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.9.2",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"files": [
|
|
10
|
+
"src/",
|
|
11
|
+
"dist/types/",
|
|
12
|
+
"docs/",
|
|
13
|
+
"schemas/",
|
|
14
|
+
"ARCHITECTURE.md"
|
|
15
|
+
],
|
|
16
|
+
"description": "Jaren JSON Addressing Standards",
|
|
17
|
+
"author": "joham",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/jklarenbeek/jarenjs.git",
|
|
21
|
+
"directory": "packages/json"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"jaren",
|
|
33
|
+
"json",
|
|
34
|
+
"json-pointer",
|
|
35
|
+
"jsonpath"
|
|
36
|
+
],
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/types/index.d.ts",
|
|
40
|
+
"default": "./src/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./basic": {
|
|
43
|
+
"types": "./dist/types/basic.d.ts",
|
|
44
|
+
"default": "./src/basic.js"
|
|
45
|
+
},
|
|
46
|
+
"./pointer": {
|
|
47
|
+
"types": "./dist/types/pointer.d.ts",
|
|
48
|
+
"default": "./src/pointer.js"
|
|
49
|
+
},
|
|
50
|
+
"./path": {
|
|
51
|
+
"types": "./dist/types/path.d.ts",
|
|
52
|
+
"default": "./src/path.js"
|
|
53
|
+
},
|
|
54
|
+
"./query": {
|
|
55
|
+
"types": "./dist/types/query/index.d.ts",
|
|
56
|
+
"default": "./src/query/index.js"
|
|
57
|
+
},
|
|
58
|
+
"./jslt": {
|
|
59
|
+
"types": "./dist/types/jslt/index.d.ts",
|
|
60
|
+
"default": "./src/jslt/index.js"
|
|
61
|
+
},
|
|
62
|
+
"./jtlt": {
|
|
63
|
+
"types": "./dist/types/jtlt/index.d.ts",
|
|
64
|
+
"default": "./src/jtlt/index.js"
|
|
65
|
+
},
|
|
66
|
+
"./xquery": {
|
|
67
|
+
"types": "./dist/types/xquery/index.d.ts",
|
|
68
|
+
"default": "./src/xquery/index.js"
|
|
69
|
+
},
|
|
70
|
+
"./schemas/*": "./schemas/*",
|
|
71
|
+
"./package.json": "./package.json"
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "npm run build:types",
|
|
75
|
+
"build:types": "tsc -p tsconfig.json",
|
|
76
|
+
"prepack": "npm run build:types"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@jarenjs/core": "^0.9.2"
|
|
80
|
+
}
|
|
81
|
+
}
|