@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,57 @@
|
|
|
1
|
+
export { JtltCompileError, JtltRuntimeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compile a Jaren JTLT 0.1 template into a reusable renderer.
|
|
4
|
+
*
|
|
5
|
+
* The returned function renders any input document to a string in the
|
|
6
|
+
* template's output method ('text' by default, 'xml' for markup with
|
|
7
|
+
* escaped interpolation). Metadata:
|
|
8
|
+
*
|
|
9
|
+
* - `render.externals` - user parameter names in first-appearance order
|
|
10
|
+
* (`root` and `path` are engine-bound and excluded)
|
|
11
|
+
* - `render.output` - the resolved output method
|
|
12
|
+
* - `render.doc` - an independent, deeply frozen template copy
|
|
13
|
+
* - `render.stylesheet` - the frozen JSLT stylesheet it compiled to
|
|
14
|
+
*
|
|
15
|
+
* @param {any} doc - a bare rule array or `{"$jtlt":"0.1","output":...,
|
|
16
|
+
* "rules":[]}` template envelope
|
|
17
|
+
* @param {object} [options] - compile options, passed to the JSLT layer
|
|
18
|
+
* @param {(schemaJson: any, docPath: string) => ((value: any) => boolean)}
|
|
19
|
+
* [options.compileTypeTest] - validator-agnostic hook for schema
|
|
20
|
+
* matches and schema operators inside segment expressions
|
|
21
|
+
* @param {number} [options.maxDepth=1024] - maximum dispatch nesting depth
|
|
22
|
+
* @returns {function} reusable `render(data, externals?)` function
|
|
23
|
+
* @throws {JtltCompileError} when compilation fails
|
|
24
|
+
* @example
|
|
25
|
+
* const render = compileJtltStylesheet([
|
|
26
|
+
* { match: '$.items[*]', body: ['- ', '$.name', '\n'] },
|
|
27
|
+
* ]);
|
|
28
|
+
* render({ items: [{ name: 'a' }, { name: 'b' }] });
|
|
29
|
+
* // '- a\n- b\n'
|
|
30
|
+
*/
|
|
31
|
+
export declare function compileJtltStylesheet(doc: any, options?: {
|
|
32
|
+
compileTypeTest?: (schemaJson: any, docPath: string) => ((value: any) => boolean);
|
|
33
|
+
maxDepth?: number;
|
|
34
|
+
}): Function;
|
|
35
|
+
/**
|
|
36
|
+
* Render a JSON value with a JTLT template in one call. Object/array
|
|
37
|
+
* template documents are compiled once and cached by identity in a
|
|
38
|
+
* WeakMap.
|
|
39
|
+
* @param {any} template - JTLT template document
|
|
40
|
+
* @param {any} data - input JSON value
|
|
41
|
+
* @param {object} [externals] - user parameter bindings
|
|
42
|
+
* @param {object} [options] - compile options used on a cache miss
|
|
43
|
+
* @param {(schemaJson: any, docPath: string) => ((value: any) => boolean)}
|
|
44
|
+
* [options.compileTypeTest] - schema type-test compiler
|
|
45
|
+
* @param {number} [options.maxDepth=1024] - maximum dispatch nesting depth
|
|
46
|
+
* @returns {string} the rendered output text
|
|
47
|
+
* @throws {JtltCompileError} when compilation fails
|
|
48
|
+
* @throws {JtltRuntimeError} when rendering fails
|
|
49
|
+
* @example
|
|
50
|
+
* renderText([{ match: '$.name', body: ['Hello ', '$', '!'] }],
|
|
51
|
+
* { name: 'world' });
|
|
52
|
+
* // 'Hello world!'
|
|
53
|
+
*/
|
|
54
|
+
export declare function renderText(template: any, data: any, externals?: object, options?: {
|
|
55
|
+
compileTypeTest?: (schemaJson: any, docPath: string) => ((value: any) => boolean);
|
|
56
|
+
maxDepth?: number;
|
|
57
|
+
}): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const RESERVED_PRIORITY_FLOOR = -1e+307;
|
|
2
|
+
/**
|
|
3
|
+
* Normalize a frozen JTLT template document into a frozen model.
|
|
4
|
+
* @param {any} doc - deeply frozen template document
|
|
5
|
+
* @returns {object} frozen template model
|
|
6
|
+
* @throws {JtltCompileError} on TL0001-TL0003 and TL0006 shape errors
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeJtltTemplate(doc: any): object;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create the serializer for one output method.
|
|
3
|
+
* @param {'text' | 'xml'} method - the template's output method
|
|
4
|
+
* @returns {(value: any) => string} segment-stream serializer
|
|
5
|
+
*/
|
|
6
|
+
export declare function createWriter(method: 'text' | 'xml'): (value: any) => string;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel for the absence of a value ("Nothing" in RFC 9535 terms), as
|
|
3
|
+
* distinct from the JSON value `null`.
|
|
4
|
+
*/
|
|
5
|
+
export declare const JSONPATH_NOTHING: symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown when a JSONPath query is not valid RFC 9535 syntax
|
|
8
|
+
* (including queries that are not well-typed per section 2.4.3).
|
|
9
|
+
*/
|
|
10
|
+
export declare class JSONPathSyntaxError extends SyntaxError {
|
|
11
|
+
source: any;
|
|
12
|
+
position: any;
|
|
13
|
+
constructor(message: any, source: any, position: any);
|
|
14
|
+
}
|
|
15
|
+
export type JSONPathNameSelector = {
|
|
16
|
+
/**
|
|
17
|
+
* - Discriminator
|
|
18
|
+
*/
|
|
19
|
+
kind: 'name';
|
|
20
|
+
/**
|
|
21
|
+
* - The member name to select
|
|
22
|
+
*/
|
|
23
|
+
name: string;
|
|
24
|
+
};
|
|
25
|
+
export type JSONPathWildcardSelector = {
|
|
26
|
+
/**
|
|
27
|
+
* - Discriminator
|
|
28
|
+
*/
|
|
29
|
+
kind: 'wildcard';
|
|
30
|
+
};
|
|
31
|
+
export type JSONPathIndexSelector = {
|
|
32
|
+
/**
|
|
33
|
+
* - Discriminator
|
|
34
|
+
*/
|
|
35
|
+
kind: 'index';
|
|
36
|
+
/**
|
|
37
|
+
* - The array index to select
|
|
38
|
+
*/
|
|
39
|
+
index: number;
|
|
40
|
+
};
|
|
41
|
+
export type JSONPathSliceSelector = {
|
|
42
|
+
/**
|
|
43
|
+
* - Discriminator
|
|
44
|
+
*/
|
|
45
|
+
kind: 'slice';
|
|
46
|
+
/**
|
|
47
|
+
* - Slice start, or null when omitted
|
|
48
|
+
*/
|
|
49
|
+
start: number | null;
|
|
50
|
+
/**
|
|
51
|
+
* - Slice end (exclusive), or null when omitted
|
|
52
|
+
*/
|
|
53
|
+
end: number | null;
|
|
54
|
+
/**
|
|
55
|
+
* - Slice step, or null when omitted
|
|
56
|
+
*/
|
|
57
|
+
step: number | null;
|
|
58
|
+
};
|
|
59
|
+
export type JSONPathFilterSelector = {
|
|
60
|
+
/**
|
|
61
|
+
* - Discriminator
|
|
62
|
+
*/
|
|
63
|
+
kind: 'filter';
|
|
64
|
+
/**
|
|
65
|
+
* - The parsed filter expression tree
|
|
66
|
+
*/
|
|
67
|
+
expr: object;
|
|
68
|
+
};
|
|
69
|
+
export type JSONPathSelector = JSONPathNameSelector | JSONPathWildcardSelector | JSONPathIndexSelector | JSONPathSliceSelector | JSONPathFilterSelector;
|
|
70
|
+
export type JSONPathSegment = {
|
|
71
|
+
/**
|
|
72
|
+
* - True for a descendant (`..`) segment
|
|
73
|
+
*/
|
|
74
|
+
descendant: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* - The segment's selectors
|
|
77
|
+
*/
|
|
78
|
+
selectors: JSONPathSelector[];
|
|
79
|
+
};
|
|
80
|
+
export type JSONPathAst = {
|
|
81
|
+
/**
|
|
82
|
+
* - True for a relative query (`@`), false for a root query (`$`)
|
|
83
|
+
*/
|
|
84
|
+
relative: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* - The query's segments in order
|
|
87
|
+
*/
|
|
88
|
+
segments: JSONPathSegment[];
|
|
89
|
+
};
|
|
90
|
+
export type JSONPathNode = {
|
|
91
|
+
/**
|
|
92
|
+
* - The normalized path (e.g. `$['store']['book'][0]`)
|
|
93
|
+
*/
|
|
94
|
+
path: string;
|
|
95
|
+
/**
|
|
96
|
+
* - The matched value
|
|
97
|
+
*/
|
|
98
|
+
value: any;
|
|
99
|
+
};
|
|
100
|
+
export type JSONPathQuery = ((data: any) => any[]) & {
|
|
101
|
+
values: (data: any) => any[];
|
|
102
|
+
first: (data: any) => any;
|
|
103
|
+
exists: (data: any) => boolean;
|
|
104
|
+
nodes: (data: any) => JSONPathNode[];
|
|
105
|
+
paths: (data: any) => string[];
|
|
106
|
+
source: string;
|
|
107
|
+
ast: JSONPathAst;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Selects a named object member (RFC 9535 name selector).
|
|
111
|
+
* @typedef {Object} JSONPathNameSelector
|
|
112
|
+
* @property {'name'} kind - Discriminator
|
|
113
|
+
* @property {string} name - The member name to select
|
|
114
|
+
*/
|
|
115
|
+
/**
|
|
116
|
+
* Selects all members of an object / all elements of an array
|
|
117
|
+
* (RFC 9535 wildcard selector).
|
|
118
|
+
* @typedef {Object} JSONPathWildcardSelector
|
|
119
|
+
* @property {'wildcard'} kind - Discriminator
|
|
120
|
+
*/
|
|
121
|
+
/**
|
|
122
|
+
* Selects an array element by index; negative indexes count from the end
|
|
123
|
+
* (RFC 9535 index selector).
|
|
124
|
+
* @typedef {Object} JSONPathIndexSelector
|
|
125
|
+
* @property {'index'} kind - Discriminator
|
|
126
|
+
* @property {number} index - The array index to select
|
|
127
|
+
*/
|
|
128
|
+
/**
|
|
129
|
+
* Selects a range of array elements (RFC 9535 array slice selector).
|
|
130
|
+
* `null` means the bound was omitted in the query.
|
|
131
|
+
* @typedef {Object} JSONPathSliceSelector
|
|
132
|
+
* @property {'slice'} kind - Discriminator
|
|
133
|
+
* @property {number | null} start - Slice start, or null when omitted
|
|
134
|
+
* @property {number | null} end - Slice end (exclusive), or null when omitted
|
|
135
|
+
* @property {number | null} step - Slice step, or null when omitted
|
|
136
|
+
*/
|
|
137
|
+
/**
|
|
138
|
+
* Selects children for which a filter expression yields a truthy result
|
|
139
|
+
* (RFC 9535 filter selector).
|
|
140
|
+
* @typedef {Object} JSONPathFilterSelector
|
|
141
|
+
* @property {'filter'} kind - Discriminator
|
|
142
|
+
* @property {object} expr - The parsed filter expression tree
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* Any RFC 9535 selector, discriminated by its `kind` property.
|
|
146
|
+
* @typedef {JSONPathNameSelector | JSONPathWildcardSelector | JSONPathIndexSelector | JSONPathSliceSelector | JSONPathFilterSelector} JSONPathSelector
|
|
147
|
+
*/
|
|
148
|
+
/**
|
|
149
|
+
* One segment of a JSONPath query: a child (`.` / `[...]`) or descendant
|
|
150
|
+
* (`..`) step holding one or more selectors.
|
|
151
|
+
* @typedef {Object} JSONPathSegment
|
|
152
|
+
* @property {boolean} descendant - True for a descendant (`..`) segment
|
|
153
|
+
* @property {JSONPathSelector[]} selectors - The segment's selectors
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* The parsed AST of a JSONPath query.
|
|
157
|
+
* @typedef {Object} JSONPathAst
|
|
158
|
+
* @property {boolean} relative - True for a relative query (`@`), false for a root query (`$`)
|
|
159
|
+
* @property {JSONPathSegment[]} segments - The query's segments in order
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* One result of a JSONPath query in nodes mode: the matched value together
|
|
163
|
+
* with its normalized path (RFC 9535 section 2.7).
|
|
164
|
+
* @typedef {Object} JSONPathNode
|
|
165
|
+
* @property {string} path - The normalized path (e.g. `$['store']['book'][0]`)
|
|
166
|
+
* @property {any} value - The matched value
|
|
167
|
+
*/
|
|
168
|
+
/**
|
|
169
|
+
* A compiled JSONPath query. Calling it returns the matched values; the
|
|
170
|
+
* attached methods expose the other result modes, and `source`/`ast`
|
|
171
|
+
* expose the original query string and its parsed (deeply frozen) AST.
|
|
172
|
+
* @typedef {((data: any) => any[]) & {
|
|
173
|
+
* values: (data: any) => any[],
|
|
174
|
+
* first: (data: any) => any,
|
|
175
|
+
* exists: (data: any) => boolean,
|
|
176
|
+
* nodes: (data: any) => JSONPathNode[],
|
|
177
|
+
* paths: (data: any) => string[],
|
|
178
|
+
* source: string,
|
|
179
|
+
* ast: JSONPathAst,
|
|
180
|
+
* }} JSONPathQuery
|
|
181
|
+
*/
|
|
182
|
+
/**
|
|
183
|
+
* Parse a JSONPath query string into an AST.
|
|
184
|
+
* @param {string} source - The JSONPath expression (e.g. `$.store.book[?@.price < 10].title`)
|
|
185
|
+
* @returns {JSONPathAst} The parsed query AST
|
|
186
|
+
* @throws {JSONPathSyntaxError} When the query violates the RFC 9535 grammar
|
|
187
|
+
*/
|
|
188
|
+
export declare function parseJSONPath(source: string): JSONPathAst;
|
|
189
|
+
/**
|
|
190
|
+
* Compile a JSONPath query (RFC 9535) into a reusable query function.
|
|
191
|
+
*
|
|
192
|
+
* The returned function applies the query to a JSON value and returns
|
|
193
|
+
* the resulting nodelist as an array of values. It also carries helper
|
|
194
|
+
* methods:
|
|
195
|
+
*
|
|
196
|
+
* - `query(data)` / `query.values(data)` - array of matched values
|
|
197
|
+
* - `query.first(data)` - first matched value, or `undefined`
|
|
198
|
+
* - `query.exists(data)` - true when the query selects at least one node
|
|
199
|
+
* - `query.nodes(data)` - array of `{ path, value }` with normalized paths
|
|
200
|
+
* - `query.paths(data)` - array of normalized paths (RFC 9535 section 2.7)
|
|
201
|
+
* - `query.source` - the original query string
|
|
202
|
+
* - `query.ast` - the parsed query AST (deeply frozen; the lazily
|
|
203
|
+
* compiled path mode must agree with the eagerly compiled value mode)
|
|
204
|
+
*
|
|
205
|
+
* @param {string} source - The JSONPath expression
|
|
206
|
+
* @returns {JSONPathQuery} The compiled query function
|
|
207
|
+
* @throws {JSONPathSyntaxError} When the query is not valid RFC 9535
|
|
208
|
+
* @example
|
|
209
|
+
* const q = compileJSONPath('$.store.book[?@.price < 10].title');
|
|
210
|
+
* q(data); // ['Sayings of the Century', 'Moby Dick']
|
|
211
|
+
* q.paths(data); // ["$['store']['book'][0]['title']", ...]
|
|
212
|
+
*/
|
|
213
|
+
export declare function compileJSONPath(source: string): JSONPathQuery;
|
|
214
|
+
/**
|
|
215
|
+
* Apply a JSONPath query to a JSON value in one call. Compiled queries
|
|
216
|
+
* are cached (FIFO, 512 entries), so repeated calls with the same query
|
|
217
|
+
* string reuse the compiled function.
|
|
218
|
+
* @param {string} source - The JSONPath expression
|
|
219
|
+
* @param {any} data - The JSON value to query
|
|
220
|
+
* @returns {any[]} Array of matched values
|
|
221
|
+
* @throws {JSONPathSyntaxError} When the query is not valid RFC 9535
|
|
222
|
+
*/
|
|
223
|
+
export declare function queryJSONPath(source: string, data: any): any[];
|
|
224
|
+
/**
|
|
225
|
+
* Validates a JSONPath expression strictly against the RFC 9535 grammar,
|
|
226
|
+
* including well-typedness of function expressions. Unlike the heuristic
|
|
227
|
+
* `isValidJSONPath` in basic.js, this uses the full parser.
|
|
228
|
+
* @param {string} str - The JSONPath expression to validate
|
|
229
|
+
* @returns {boolean} True when the string is a valid RFC 9535 query
|
|
230
|
+
* @example
|
|
231
|
+
* isValidJSONPathStrict('$.store.book[?@.price < 10]'); // true
|
|
232
|
+
* isValidJSONPathStrict('$.store.book[0 5]'); // false
|
|
233
|
+
* isValidJSONPathStrict('@.name'); // false (queries start at $)
|
|
234
|
+
*/
|
|
235
|
+
export declare function isValidJSONPathStrict(str: string): boolean;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel for the absence of a value, as distinct from the JSON value
|
|
3
|
+
* `null`. This is the same sentinel as `JSONPATH_NOTHING` in path.js, so
|
|
4
|
+
* pointer and path results can share checks.
|
|
5
|
+
*/
|
|
6
|
+
export declare const JSONPOINTER_NOTHING: symbol;
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when a (relative) JSON Pointer is not valid RFC 6901 /
|
|
9
|
+
* draft-luff-relative-json-pointer syntax.
|
|
10
|
+
*/
|
|
11
|
+
export declare class JSONPointerSyntaxError extends SyntaxError {
|
|
12
|
+
source: any;
|
|
13
|
+
position: any;
|
|
14
|
+
constructor(message: any, source: any, position: any);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a JSON Pointer strictly per RFC 6901 into its decoded segments.
|
|
18
|
+
* @param {string} pointer - The JSON Pointer (e.g. `/store/book/0`)
|
|
19
|
+
* @returns {string[]} Array of decoded reference tokens
|
|
20
|
+
* @throws {JSONPointerSyntaxError} When the pointer violates the grammar
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseJSONPointer(pointer: string): string[];
|
|
23
|
+
export type RelativeJsonPointer = {
|
|
24
|
+
/**
|
|
25
|
+
* - Number of levels to ascend from the current location
|
|
26
|
+
*/
|
|
27
|
+
levels: number;
|
|
28
|
+
/**
|
|
29
|
+
* - True for the `#` form, which addresses the member name or array index itself
|
|
30
|
+
*/
|
|
31
|
+
hash: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* - Decoded reference tokens applied after ascending
|
|
34
|
+
*/
|
|
35
|
+
segments: string[];
|
|
36
|
+
};
|
|
37
|
+
export type JsonPointerGetter = (root: any) => any;
|
|
38
|
+
export type RelativeJsonPointerResolver = (dataRoot: any, dataPath: string) => any;
|
|
39
|
+
/**
|
|
40
|
+
* A parsed Relative JSON Pointer (draft-luff-relative-json-pointer).
|
|
41
|
+
* @typedef {Object} RelativeJsonPointer
|
|
42
|
+
* @property {number} levels - Number of levels to ascend from the current location
|
|
43
|
+
* @property {boolean} hash - True for the `#` form, which addresses the member name or array index itself
|
|
44
|
+
* @property {string[]} segments - Decoded reference tokens applied after ascending
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* A compiled JSON Pointer: returns the value addressed in `root`, or the
|
|
48
|
+
* `JSONPOINTER_NOTHING` sentinel when the pointer does not address a location.
|
|
49
|
+
* @typedef {(root: any) => any} JsonPointerGetter
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* A compiled Relative JSON Pointer / data reference: resolves against the
|
|
53
|
+
* RFC 6901 location `dataPath` inside `dataRoot`, returning the addressed
|
|
54
|
+
* value or the `JSONPOINTER_NOTHING` sentinel.
|
|
55
|
+
* @typedef {(dataRoot: any, dataPath: string) => any} RelativeJsonPointerResolver
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Parse a Relative JSON Pointer strictly per
|
|
59
|
+
* draft-luff-relative-json-pointer: a non-negative integer without
|
|
60
|
+
* leading zeros, followed by `#` or a JSON Pointer.
|
|
61
|
+
* @param {string} pointer - The relative pointer (e.g. `1/sibling`, `0#`)
|
|
62
|
+
* @returns {RelativeJsonPointer} The parsed relative pointer
|
|
63
|
+
* @throws {JSONPointerSyntaxError} When the pointer violates the grammar
|
|
64
|
+
*/
|
|
65
|
+
export declare function parseRelativeJSONPointer(pointer: string): RelativeJsonPointer;
|
|
66
|
+
/**
|
|
67
|
+
* Compile a JSON Pointer (RFC 6901) into a reusable getter.
|
|
68
|
+
*
|
|
69
|
+
* All decisions are taken at compile time: member names are pre-decoded,
|
|
70
|
+
* array indexes pre-parsed, and the getter is specialized by segment
|
|
71
|
+
* count. Resolution allocates nothing.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} pointer - The JSON Pointer (e.g. `/store/book/0`)
|
|
74
|
+
* @returns {JsonPointerGetter} getter returning the addressed value, or
|
|
75
|
+
* `JSONPOINTER_NOTHING` when the pointer does not address a location
|
|
76
|
+
* @throws {JSONPointerSyntaxError} When the pointer is not valid RFC 6901
|
|
77
|
+
* @example
|
|
78
|
+
* const get = compileJSONPointer('/limits/min');
|
|
79
|
+
* get({ limits: { min: 2 } }); // 2
|
|
80
|
+
* get({}); // JSONPOINTER_NOTHING
|
|
81
|
+
*/
|
|
82
|
+
export declare function compileJSONPointer(pointer: string): JsonPointerGetter;
|
|
83
|
+
/**
|
|
84
|
+
* Compile a Relative JSON Pointer into a reusable resolver.
|
|
85
|
+
*
|
|
86
|
+
* The relative part (level count, `#` form, trailing segments) compiles
|
|
87
|
+
* once; per call only `dataPath` - the current location in `dataRoot` as
|
|
88
|
+
* an RFC 6901 pointer - varies. The `#` form resolves to the member name
|
|
89
|
+
* or array index of the location **as a string** (`''` at the root),
|
|
90
|
+
* matching the historical behavior relied on by the validator's `$data`
|
|
91
|
+
* keyword.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} pointer - The relative pointer (e.g. `1/sibling`, `0#`)
|
|
94
|
+
* @returns {RelativeJsonPointerResolver} resolver returning
|
|
95
|
+
* the addressed value, or `JSONPOINTER_NOTHING`
|
|
96
|
+
* @throws {JSONPointerSyntaxError} When the pointer is not valid
|
|
97
|
+
* @example
|
|
98
|
+
* const resolve = compileRelativeJSONPointer('1/limits');
|
|
99
|
+
* resolve({ limits: { min: 2 } , value: 5 }, '/value'); // { min: 2 }
|
|
100
|
+
*/
|
|
101
|
+
export declare function compileRelativeJSONPointer(pointer: string): RelativeJsonPointerResolver;
|
|
102
|
+
/**
|
|
103
|
+
* Compile a data reference - the accepted forms of the validator's
|
|
104
|
+
* `data`/`$data` keywords - into a reusable resolver. The dispatch is
|
|
105
|
+
* decided once at compile time: a leading digit is a Relative JSON
|
|
106
|
+
* Pointer, a leading `/` an absolute JSON Pointer, and `''` the root.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} ref - The reference string
|
|
109
|
+
* @returns {RelativeJsonPointerResolver} resolver returning
|
|
110
|
+
* the addressed value, or `JSONPOINTER_NOTHING`
|
|
111
|
+
* @throws {JSONPointerSyntaxError} When the reference is none of the
|
|
112
|
+
* accepted forms
|
|
113
|
+
*/
|
|
114
|
+
export declare function compileDataRef(ref: string): RelativeJsonPointerResolver;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel stored in the frame slot of an external parameter the caller
|
|
3
|
+
* did not bind; evaluating a reference to it raises JQ2006.
|
|
4
|
+
*/
|
|
5
|
+
export declare const UNBOUND: unique symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Existence-only compilation for `$exists`/`$empty` (and any future
|
|
8
|
+
* boolean context): paths never materialize a result sequence (the
|
|
9
|
+
* analogue of path.js's compileExists). Takes the operand AST node -
|
|
10
|
+
* this is why registry `compile` functions receive arg nodes, not just
|
|
11
|
+
* getters.
|
|
12
|
+
* @param {object} node - a frozen AST node from normalize.js
|
|
13
|
+
* @returns {(frame: any[]) => boolean}
|
|
14
|
+
*/
|
|
15
|
+
export declare function compileExistsTest(node: object): (frame: any[]) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Compile a normalized AST node into its getter closure.
|
|
18
|
+
* @param {object} node - a frozen AST node from normalize.js
|
|
19
|
+
* @returns {(frame: any[]) => any} getter returning an item, EMPTY, or a Seq
|
|
20
|
+
*/
|
|
21
|
+
export declare function compileNode(node: object): (frame: any[]) => any;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when a query document is rejected at compile time
|
|
3
|
+
* (`JQ0xxx` codes, QUERY-FORMAT.md section 10.2).
|
|
4
|
+
*/
|
|
5
|
+
export declare class JsonQueryCompileError extends Error {
|
|
6
|
+
code: any;
|
|
7
|
+
docPath: any;
|
|
8
|
+
constructor(code: any, message: any, docPath: any);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when evaluating a compiled query fails
|
|
12
|
+
* (`JQ2xxx` codes, QUERY-FORMAT.md section 10.3).
|
|
13
|
+
*/
|
|
14
|
+
export declare class JsonQueryRuntimeError extends Error {
|
|
15
|
+
code: any;
|
|
16
|
+
docPath: any;
|
|
17
|
+
constructor(code: any, message: any, docPath: any);
|
|
18
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export { JsonQueryCompileError, JsonQueryRuntimeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compile a Jaren JSON Query document into a reusable query function.
|
|
4
|
+
*
|
|
5
|
+
* The returned function applies the query to a JSON value and returns the
|
|
6
|
+
* result as plain JSON: `undefined` for the empty sequence, the item
|
|
7
|
+
* itself for a singleton result, an array of items for a longer sequence.
|
|
8
|
+
* It also carries helper methods and metadata:
|
|
9
|
+
*
|
|
10
|
+
* - `query(data, externals?)` - the query result as described above
|
|
11
|
+
* - `query.first(data, externals?)` - first item of the result, or `undefined`
|
|
12
|
+
* - `query.exists(data, externals?)` - true when the result is non-empty
|
|
13
|
+
* - `query.ebv(data, externals?)` - the effective boolean value of the
|
|
14
|
+
* result per the EBV table (section 2.2): empty -> false, a singleton
|
|
15
|
+
* per its type (array/object -> true, D3), two or more items ->
|
|
16
|
+
* `JsonQueryRuntimeError` JQ2003. Computed on the internal sequence
|
|
17
|
+
* value, before the plain-JSON mapping - the mapped result is ambiguous
|
|
18
|
+
* there (an array is both a multi-item sequence and one array item).
|
|
19
|
+
* - `query.externals` - names of the external parameters (section 9), in
|
|
20
|
+
* order of first appearance; bind them via the `externals` argument
|
|
21
|
+
* (`{ name: value, ... }`). Evaluating a reference to an unbound
|
|
22
|
+
* external raises `JQ2006`.
|
|
23
|
+
* - `query.doc` - a deeply frozen copy of the query document (the
|
|
24
|
+
* caller's object is never frozen)
|
|
25
|
+
*
|
|
26
|
+
* @param {any} doc - the query document (any JSON value; a bare RFC 9535
|
|
27
|
+
* JSONPath string is the degenerate query)
|
|
28
|
+
* @param {object} [options] - compile options
|
|
29
|
+
* @param {(schemaJson: any, docPath: string) => ((value: any) => boolean)}
|
|
30
|
+
* [options.compileTypeTest] - hook compiling a JSON Schema literal into
|
|
31
|
+
* a boolean item predicate, called once per schema literal at query
|
|
32
|
+
* compile time (QUERY-FORMAT.md section 8.11). `@jarenjs/validate/query`
|
|
33
|
+
* exports `createTypeTestCompiler()` producing one; any conforming
|
|
34
|
+
* implementation works - this package never imports the validator.
|
|
35
|
+
* Without a hook, the schema operators `$valid`/`$assert`/`$as` are
|
|
36
|
+
* compile error JQ0008.
|
|
37
|
+
* @param {object} [options.extensions] - package-internal operator
|
|
38
|
+
* extension point, the operator analogue of `compileTypeTest` (used by
|
|
39
|
+
* the JSLT layer; not a public contract). A plain object of
|
|
40
|
+
* `name -> entry` following the operator registry contract; see
|
|
41
|
+
* normalizeQuery in normalize.js for the full shape. The published
|
|
42
|
+
* format vocabulary is unchanged: without extensions, documents using
|
|
43
|
+
* such operators fail JQ0002.
|
|
44
|
+
* @returns {function} the compiled query function
|
|
45
|
+
* @throws {JsonQueryCompileError} when the document violates the format
|
|
46
|
+
* @example
|
|
47
|
+
* const q = compileJsonQuery({
|
|
48
|
+
* "$let": { "b": "$.store.book[0]" },
|
|
49
|
+
* "$return": { "title": "$b.title", "cheap": { "$lt": ["$b.price", "$max"] } }
|
|
50
|
+
* });
|
|
51
|
+
* q.externals; // ['max']
|
|
52
|
+
* q(data, { max: 10 }); // { title: 'Sayings of the Century', cheap: true }
|
|
53
|
+
*/
|
|
54
|
+
export declare function compileJsonQuery(doc: any, options?: {
|
|
55
|
+
compileTypeTest?: (schemaJson: any, docPath: string) => ((value: any) => boolean);
|
|
56
|
+
extensions?: object;
|
|
57
|
+
}): Function;
|
|
58
|
+
/**
|
|
59
|
+
* Apply a Jaren JSON Query document to a JSON value in one call.
|
|
60
|
+
* Compiled queries are cached: object documents by identity (WeakMap),
|
|
61
|
+
* string documents (the degenerate JSONPath case) by value (FIFO, 512
|
|
62
|
+
* entries - the same pattern as `queryJSONPath`).
|
|
63
|
+
* @param {any} doc - the query document
|
|
64
|
+
* @param {any} data - the JSON value to query
|
|
65
|
+
* @param {object} [externals] - external parameter bindings (`{ name: value }`)
|
|
66
|
+
* @returns {any} the query result (undefined | item | array of items)
|
|
67
|
+
* @throws {JsonQueryCompileError} when the document violates the format
|
|
68
|
+
* @throws {JsonQueryRuntimeError} on any JQ2xxx runtime condition
|
|
69
|
+
*/
|
|
70
|
+
export declare function queryJson(doc: any, data: any, externals?: object): any;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Statically empty (the node always evaluates to the empty sequence). */
|
|
2
|
+
export declare const CARD_ZERO = 0;
|
|
3
|
+
/** Always exactly one item; compile.js skips all sequence checks. */
|
|
4
|
+
export declare const CARD_ONE = 1;
|
|
5
|
+
/** Zero or one item. */
|
|
6
|
+
export declare const CARD_OPT = 2;
|
|
7
|
+
/** Any number of items (the analysis top). */
|
|
8
|
+
export declare const CARD_MANY = 3;
|
|
9
|
+
/**
|
|
10
|
+
* join = least upper bound over {ZERO, ONE, OPT, MANY}: the cardinality
|
|
11
|
+
* of "one of the two branches" ($if).
|
|
12
|
+
* @param {number} a - a CARD_* value
|
|
13
|
+
* @param {number} b - a CARD_* value
|
|
14
|
+
* @returns {number}
|
|
15
|
+
*/
|
|
16
|
+
export declare function joinCard(a: number, b: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* sum = cardinality of two concatenated sequences ($seq); two non-empty
|
|
19
|
+
* contributions can exceed one item, which only MANY can express.
|
|
20
|
+
* @param {number} a - a CARD_* value
|
|
21
|
+
* @param {number} b - a CARD_* value
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
export declare function sumCard(a: number, b: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Deep-copy a JSON value and freeze every object/array in the copy.
|
|
27
|
+
* Used for `$const` values and the compiled query's `.doc` property, so
|
|
28
|
+
* the engine never freezes (or shares mutable state with) caller objects.
|
|
29
|
+
* @param {any} value - a JSON value
|
|
30
|
+
* @returns {any} an independent, deeply frozen copy
|
|
31
|
+
*/
|
|
32
|
+
export declare function deepFreezeCopy(value: any): any;
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a query document into the internal AST.
|
|
35
|
+
* @param {any} doc - the query document (any JSON value)
|
|
36
|
+
* @param {object} [options] - compile options
|
|
37
|
+
* @param {(schemaJson: any, docPath: string) => ((value: any) => boolean)}
|
|
38
|
+
* [options.compileTypeTest] - host hook compiling a JSON Schema literal
|
|
39
|
+
* into a boolean item predicate (QUERY-FORMAT.md section 8.11). Called
|
|
40
|
+
* once per schema literal, at query compile time. Without it, schema
|
|
41
|
+
* operators ($valid/$assert/$as) are compile error JQ0008.
|
|
42
|
+
* @param {object} [options.extensions] - package-internal operator
|
|
43
|
+
* extension point, the operator analogue of `compileTypeTest` (used by
|
|
44
|
+
* the JSLT layer; not a public contract). A plain object of
|
|
45
|
+
* `name -> entry`, where entry follows the operator registry contract
|
|
46
|
+
* (`params`/`result`/`compile`, operators.js header) plus an optional
|
|
47
|
+
* `normalize(arg, docPath, opPath, scope, ctx, helpers) -> {args, card?}`
|
|
48
|
+
* override for polymorphic value shapes. Names must start with '$' and
|
|
49
|
+
* must not collide with the core vocabulary (TypeError - a host
|
|
50
|
+
* programming error, not a JQ0xxx document error). The published format
|
|
51
|
+
* and its schema are unchanged: without extensions, the same documents
|
|
52
|
+
* fail JQ0002.
|
|
53
|
+
* @returns {{ root: object, frameSize: number, externals: {name: string, slot: number}[] }}
|
|
54
|
+
* the AST root, the frame size, and the external parameters in order of
|
|
55
|
+
* first appearance (slot order)
|
|
56
|
+
* @throws {JsonQueryCompileError} on any JQ0xxx condition
|
|
57
|
+
*/
|
|
58
|
+
export declare function normalizeQuery(doc: any, options?: {
|
|
59
|
+
compileTypeTest?: (schemaJson: any, docPath: string) => ((value: any) => boolean);
|
|
60
|
+
extensions?: object;
|
|
61
|
+
}): {
|
|
62
|
+
root: object;
|
|
63
|
+
frameSize: number;
|
|
64
|
+
externals: {
|
|
65
|
+
name: string;
|
|
66
|
+
slot: number;
|
|
67
|
+
}[];
|
|
68
|
+
};
|