@elaraai/east-node-std 1.0.69 → 1.0.71
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 +10 -10
- package/dist/src/fs.d.ts +81 -1
- package/dist/src/fs.d.ts.map +1 -1
- package/dist/src/fs.js +169 -2
- package/dist/src/fs.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/json.d.ts +191 -0
- package/dist/src/json.d.ts.map +1 -0
- package/dist/src/json.js +265 -0
- package/dist/src/json.js.map +1 -0
- package/dist/src/json_reader.d.ts +153 -0
- package/dist/src/json_reader.d.ts.map +1 -0
- package/dist/src/json_reader.js +1271 -0
- package/dist/src/json_reader.js.map +1 -0
- package/package.json +2 -2
package/dist/src/json.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { East, StringType, NullType, BooleanType, printType, } from "@elaraai/east";
|
|
6
|
+
import { EastError } from "@elaraai/east/internal";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { JsonReader } from "./json_reader.js";
|
|
9
|
+
/** Open readers, keyed by the opaque handle an East program carries. */
|
|
10
|
+
const readers = new Map();
|
|
11
|
+
function hold(reader) {
|
|
12
|
+
const handle = randomUUID();
|
|
13
|
+
readers.set(handle, reader);
|
|
14
|
+
return handle;
|
|
15
|
+
}
|
|
16
|
+
function get(handle, fn) {
|
|
17
|
+
const reader = readers.get(handle);
|
|
18
|
+
if (reader === undefined) {
|
|
19
|
+
throw new EastError(`${fn}: no open JSON reader for this handle`, {
|
|
20
|
+
location: [{ filename: fn, line: 0n, column: 0n }],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return reader;
|
|
24
|
+
}
|
|
25
|
+
/** Wraps a reader failure as an East error, keeping its pointer in the message. */
|
|
26
|
+
function wrap(fn, body) {
|
|
27
|
+
try {
|
|
28
|
+
return body();
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
// An East error is already worded for the caller — the handle lookup's
|
|
32
|
+
// is — so it passes through, as the Time and Fetch wrappers let theirs.
|
|
33
|
+
if (err instanceof EastError)
|
|
34
|
+
throw err;
|
|
35
|
+
throw new EastError(`${fn}: ${err.message}`, {
|
|
36
|
+
location: [{ filename: fn, line: 0n, column: 0n }],
|
|
37
|
+
cause: err,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Opens a JSON file and positions a reader on the array or object to iterate.
|
|
43
|
+
*
|
|
44
|
+
* @param path - The file to read
|
|
45
|
+
* @param pointer - RFC 6901 pointer to the container, `""` for the whole document
|
|
46
|
+
* @returns An opaque handle
|
|
47
|
+
*
|
|
48
|
+
* @throws {EastError} When the file cannot be opened, the pointer does not
|
|
49
|
+
* resolve, or the node it names is not an array or object
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* The document is never held: the reader pulls one chunk of text at a time and
|
|
53
|
+
* constructs one value per {@link json_next}. Reading past the container is
|
|
54
|
+
* skipping, not parsing, so a pointer naming a small envelope member costs a
|
|
55
|
+
* scan and nothing more.
|
|
56
|
+
*/
|
|
57
|
+
export const json_open = East.platform("json_open", [StringType, StringType], StringType);
|
|
58
|
+
/**
|
|
59
|
+
* Opens an in-memory JSON payload, as {@link json_open} opens a file.
|
|
60
|
+
*
|
|
61
|
+
* @param text - The document
|
|
62
|
+
* @param pointer - RFC 6901 pointer to the container, `""` for the whole document
|
|
63
|
+
* @returns An opaque handle
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* The same reader over a string, so a request body and a multi-gigabyte file
|
|
67
|
+
* are read by one implementation and held to one definition of strict.
|
|
68
|
+
*/
|
|
69
|
+
export const json_open_text = East.platform("json_open_text", [StringType, StringType], StringType);
|
|
70
|
+
/**
|
|
71
|
+
* Whether the container being iterated has another element.
|
|
72
|
+
*
|
|
73
|
+
* @param handle - A handle from {@link json_open} or {@link json_open_text}
|
|
74
|
+
* @returns True while elements remain
|
|
75
|
+
*
|
|
76
|
+
* @throws {EastError} When the handle is not open, or the document is malformed
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* A predicate, not an advance: {@link json_next} moves the cursor, so the two
|
|
80
|
+
* need not alternate and asking twice is harmless.
|
|
81
|
+
*/
|
|
82
|
+
export const json_more = East.platform("json_more", [StringType], BooleanType);
|
|
83
|
+
/**
|
|
84
|
+
* Reads the next element of the container as `T`.
|
|
85
|
+
*
|
|
86
|
+
* @param handle - A handle from {@link json_open} or {@link json_open_text}
|
|
87
|
+
* @returns The decoded value
|
|
88
|
+
*
|
|
89
|
+
* @throws {EastError} When the element does not satisfy `T` under East JSON's
|
|
90
|
+
* encoding, naming the RFC 6901 pointer of the offending node
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* Strict: it accepts exactly what `jsonSchemaFor(T)` describes, which is what
|
|
94
|
+
* the ENCODER emits rather than what the historic decoder tolerated. An
|
|
95
|
+
* integer must be a quoted decimal in i64 range — not `"0x10"`, not `" 7 "`,
|
|
96
|
+
* not `"007"`; a timestamp must carry an explicit `+00:00`, not `Z` and not a
|
|
97
|
+
* numeric offset; a blob's hex must be lowercase.
|
|
98
|
+
*
|
|
99
|
+
* When the container is a JSON object, `T` must be a `Struct` of exactly `key`
|
|
100
|
+
* and `value`, in either order, and each member arrives as one of those —
|
|
101
|
+
* which is what a `Dict` output needs. An error inside an element is located
|
|
102
|
+
* by its index in an array and by its member name in an object, and reads
|
|
103
|
+
* word for word as it does on east-c and east-py.
|
|
104
|
+
*/
|
|
105
|
+
export const json_next = East.genericPlatform("json_next", ["T"], [StringType], "T");
|
|
106
|
+
/**
|
|
107
|
+
* Reads one whole value from a file, without iterating.
|
|
108
|
+
*
|
|
109
|
+
* @param path - The file to read
|
|
110
|
+
* @param pointer - RFC 6901 pointer to the value
|
|
111
|
+
* @returns The decoded value
|
|
112
|
+
*
|
|
113
|
+
* @throws {EastError} When the file cannot be read, the pointer does not
|
|
114
|
+
* resolve, or the value does not satisfy `T`
|
|
115
|
+
*
|
|
116
|
+
* @remarks
|
|
117
|
+
* For the small parts of a document whose large parts are streamed — an
|
|
118
|
+
* envelope's metadata beside a ten-million-row array. Everything outside the
|
|
119
|
+
* pointer is skipped rather than constructed.
|
|
120
|
+
*/
|
|
121
|
+
export const json_value = East.genericPlatform("json_value", ["T"], [StringType, StringType], "T");
|
|
122
|
+
/**
|
|
123
|
+
* Closes a reader and releases its file descriptor.
|
|
124
|
+
*
|
|
125
|
+
* @param handle - A handle from {@link json_open} or {@link json_open_text}
|
|
126
|
+
* @returns Null
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* Handles are held until closed, as a database connection is. A body that can
|
|
130
|
+
* fail mid-document should close in a `.catch` that re-raises, since a `$.try`
|
|
131
|
+
* whose `.catch` is left implicit swallows the error.
|
|
132
|
+
*/
|
|
133
|
+
export const json_close = East.platform("json_close", [StringType], NullType);
|
|
134
|
+
/** Node.js implementation of the JSON reader platform functions. */
|
|
135
|
+
const JsonImpl = [
|
|
136
|
+
json_open.implement((path, pointer) => wrap("json_open", () => hold(JsonReader.openFile(path, pointer)))),
|
|
137
|
+
json_open_text.implement((text, pointer) => wrap("json_open_text", () => hold(JsonReader.openText(text, pointer)))),
|
|
138
|
+
json_more.implement((handle) => wrap("json_more", () => get(handle, "json_more").more())),
|
|
139
|
+
json_next.implement((T) => (handle) => wrap("json_next", () => get(handle, "json_next").next(T))),
|
|
140
|
+
json_value.implement((T) => (path, pointer) => wrap("json_value", () => {
|
|
141
|
+
// A pointer to a scalar cannot be "entered", so the value is read
|
|
142
|
+
// from a reader opened on the parent and positioned by the last
|
|
143
|
+
// segment — openValue does that in one step.
|
|
144
|
+
const reader = JsonReader.openValueFile(path, pointer);
|
|
145
|
+
try {
|
|
146
|
+
return reader.readValue(T);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
reader.close();
|
|
150
|
+
}
|
|
151
|
+
})),
|
|
152
|
+
json_close.implement((handle) => {
|
|
153
|
+
const reader = readers.get(handle);
|
|
154
|
+
if (reader === undefined) {
|
|
155
|
+
throw new EastError("json_close: no open JSON reader for this handle", {
|
|
156
|
+
location: [{ filename: "json_close", line: 0n, column: 0n }],
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
readers.delete(handle);
|
|
160
|
+
reader.close();
|
|
161
|
+
return null;
|
|
162
|
+
}),
|
|
163
|
+
];
|
|
164
|
+
/** The element type a container's rows decode as must have a JSON form. */
|
|
165
|
+
function checkRowType(type, fn) {
|
|
166
|
+
if (type.type === "Function" || type.type === "AsyncFunction" || type.type === "Never") {
|
|
167
|
+
throw new Error(`${fn} cannot read ${printType(type)} — it has no JSON form`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Reading JSON documents that do not fit in memory.
|
|
172
|
+
*
|
|
173
|
+
* @remarks
|
|
174
|
+
* The ingest half of the contract boundary: `jsonSchemaFor(T)` publishes what a
|
|
175
|
+
* producer must send, and these read it back under exactly that contract. One
|
|
176
|
+
* element is in flight at a time, whatever the document's size, so the natural
|
|
177
|
+
* home is an `e3.streamTask` producer that emits as it reads.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* const rows = e3.streamTask('rows', {
|
|
182
|
+
* inputs: [path],
|
|
183
|
+
* output: ArrayType(RowType),
|
|
184
|
+
* }, ($, p, emit) => {
|
|
185
|
+
* const handle = $.let(Json.open(p, "/data"));
|
|
186
|
+
* $.while(Json.more(handle), $ => {
|
|
187
|
+
* $(emit(Json.next(RowType, handle)));
|
|
188
|
+
* });
|
|
189
|
+
* $(Json.close(handle));
|
|
190
|
+
* });
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export const Json = {
|
|
194
|
+
/**
|
|
195
|
+
* Opens a JSON file and positions a reader on the container to iterate.
|
|
196
|
+
*
|
|
197
|
+
* @param path - The file to read
|
|
198
|
+
* @param pointer - RFC 6901 pointer to the container, `""` for the whole document
|
|
199
|
+
* @returns An opaque handle
|
|
200
|
+
* @throws {EastError} When the file cannot be opened or the pointer does not resolve
|
|
201
|
+
*/
|
|
202
|
+
open: json_open,
|
|
203
|
+
/**
|
|
204
|
+
* Opens an in-memory payload, as {@link Json.open} opens a file.
|
|
205
|
+
*
|
|
206
|
+
* @param text - The document
|
|
207
|
+
* @param pointer - RFC 6901 pointer to the container, `""` for the whole document
|
|
208
|
+
* @returns An opaque handle
|
|
209
|
+
* @throws {EastError} When the pointer does not resolve
|
|
210
|
+
*/
|
|
211
|
+
openText: json_open_text,
|
|
212
|
+
/**
|
|
213
|
+
* Whether the container has another element.
|
|
214
|
+
*
|
|
215
|
+
* @param handle - A handle from {@link Json.open} or {@link Json.openText}
|
|
216
|
+
* @returns True while elements remain
|
|
217
|
+
*/
|
|
218
|
+
more: json_more,
|
|
219
|
+
/**
|
|
220
|
+
* Reads the next element as `type`.
|
|
221
|
+
*
|
|
222
|
+
* @typeParam T - The element's East type
|
|
223
|
+
* @param type - The type to decode the element as
|
|
224
|
+
* @param handle - A handle from {@link Json.open} or {@link Json.openText}
|
|
225
|
+
* @returns The decoded element
|
|
226
|
+
* @throws {Error} When `type` has no JSON form (at build time)
|
|
227
|
+
* @throws {EastError} When the element does not satisfy `type`, naming the
|
|
228
|
+
* RFC 6901 pointer of the offending node
|
|
229
|
+
*/
|
|
230
|
+
next(type, handle) {
|
|
231
|
+
checkRowType(type, "Json.next");
|
|
232
|
+
return json_next([type], handle);
|
|
233
|
+
},
|
|
234
|
+
/**
|
|
235
|
+
* Reads one whole value from a file without iterating.
|
|
236
|
+
*
|
|
237
|
+
* @typeParam T - The value's East type
|
|
238
|
+
* @param type - The type to decode the value as
|
|
239
|
+
* @param path - The file to read
|
|
240
|
+
* @param pointer - RFC 6901 pointer to the value
|
|
241
|
+
* @returns The decoded value
|
|
242
|
+
* @throws {Error} When `type` has no JSON form (at build time)
|
|
243
|
+
* @throws {EastError} When the value does not satisfy `type`
|
|
244
|
+
*/
|
|
245
|
+
value(type, path, pointer) {
|
|
246
|
+
checkRowType(type, "Json.value");
|
|
247
|
+
return json_value([type], path, pointer);
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Closes a reader and releases its file descriptor.
|
|
251
|
+
*
|
|
252
|
+
* @param handle - A handle from {@link Json.open} or {@link Json.openText}
|
|
253
|
+
* @returns Null
|
|
254
|
+
*/
|
|
255
|
+
close: json_close,
|
|
256
|
+
/**
|
|
257
|
+
* Node.js implementation of the JSON reader platform functions.
|
|
258
|
+
*
|
|
259
|
+
* Pass this to {@link East.compile} to enable them.
|
|
260
|
+
*/
|
|
261
|
+
Implementation: JsonImpl,
|
|
262
|
+
};
|
|
263
|
+
export { JsonImpl };
|
|
264
|
+
export { JsonReadError } from "./json_reader.js";
|
|
265
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { type EastTypeValue } from "@elaraai/east";
|
|
6
|
+
/** A JSON document that does not satisfy the contract, located by pointer. */
|
|
7
|
+
export declare class JsonReadError extends Error {
|
|
8
|
+
/** RFC 6901 pointer to the offending node. */
|
|
9
|
+
readonly pointer: string;
|
|
10
|
+
constructor(message: string, pointer: string);
|
|
11
|
+
}
|
|
12
|
+
/** A source of document bytes, pulled a chunk at a time. */
|
|
13
|
+
interface Chunks {
|
|
14
|
+
/** The next chunk, or null once the source is exhausted. */
|
|
15
|
+
next(): Uint8Array | null;
|
|
16
|
+
close(): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A pull reader over a JSON document.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Holds one chunk of bytes and the path it has descended, never the document
|
|
23
|
+
* and never a batch. Values are constructed one at a time, directly against
|
|
24
|
+
* the East type, so nothing intermediate is materialised either — a string is
|
|
25
|
+
* decoded from its bytes in runs, never grown a character at a time, and a
|
|
26
|
+
* skipped value is validated without being built at all.
|
|
27
|
+
*/
|
|
28
|
+
export declare class JsonReader {
|
|
29
|
+
private chunks;
|
|
30
|
+
private buf;
|
|
31
|
+
private pos;
|
|
32
|
+
private eof;
|
|
33
|
+
/** The path descended so far, for error pointers. */
|
|
34
|
+
private path;
|
|
35
|
+
/** Index within the array currently being iterated. */
|
|
36
|
+
private index;
|
|
37
|
+
/** Whether iteration has begun, so a separator is expected next. */
|
|
38
|
+
private started;
|
|
39
|
+
/** The container kind at the cursor: `[` for an array, `{` for an object. */
|
|
40
|
+
private container;
|
|
41
|
+
/** Nesting depth of the value currently being read or skipped. */
|
|
42
|
+
private depth;
|
|
43
|
+
private closed;
|
|
44
|
+
private decoder;
|
|
45
|
+
private constructor();
|
|
46
|
+
/** Opens a document and descends to the container the pointer names. */
|
|
47
|
+
static open(chunks: Chunks, pointer: string): JsonReader;
|
|
48
|
+
/**
|
|
49
|
+
* Opens a document and positions on the value the pointer names, without
|
|
50
|
+
* entering it — for reading one whole value rather than iterating.
|
|
51
|
+
*/
|
|
52
|
+
static openValue(chunks: Chunks, pointer: string): JsonReader;
|
|
53
|
+
static openFile(path: string, pointer: string): JsonReader;
|
|
54
|
+
static openText(text: string, pointer: string): JsonReader;
|
|
55
|
+
static openValueFile(path: string, pointer: string): JsonReader;
|
|
56
|
+
static openValueText(text: string, pointer: string): JsonReader;
|
|
57
|
+
close(): void;
|
|
58
|
+
/** Ensures at least `n` bytes are buffered; false once the input cannot supply them. */
|
|
59
|
+
private ensure;
|
|
60
|
+
/** The byte at the cursor, or {@link EOF}. */
|
|
61
|
+
private peek;
|
|
62
|
+
private take;
|
|
63
|
+
private skipSpace;
|
|
64
|
+
/** Whether the bytes at the cursor spell `word`, without consuming them. */
|
|
65
|
+
private startsWith;
|
|
66
|
+
/**
|
|
67
|
+
* The code point at the cursor, for a message — U+FFFD when the bytes
|
|
68
|
+
* there are not a well-formed sequence.
|
|
69
|
+
*/
|
|
70
|
+
private charAtCursor;
|
|
71
|
+
/**
|
|
72
|
+
* What sits at the cursor, for a message: `a string`, `a number`, `an
|
|
73
|
+
* array`, `an object`, `a boolean`, `null`, `end of document`, or the
|
|
74
|
+
* quoted character when it starts no JSON value.
|
|
75
|
+
*/
|
|
76
|
+
private describe;
|
|
77
|
+
private fail;
|
|
78
|
+
/**
|
|
79
|
+
* Reads the string whose opening quote is at the cursor.
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* The bytes between escapes are validated as UTF-8 and decoded in runs,
|
|
83
|
+
* one chunk at a time, so a long string costs its own size and no more —
|
|
84
|
+
* appending a character at a time would build a rope of thirty-odd bytes
|
|
85
|
+
* per character.
|
|
86
|
+
*/
|
|
87
|
+
private readString;
|
|
88
|
+
/** One escape, the backslash already consumed. */
|
|
89
|
+
private readEscape;
|
|
90
|
+
/** Validates the string at the cursor without building it. */
|
|
91
|
+
private skipString;
|
|
92
|
+
/** The JSON number at the cursor, exactly as written, checked against the grammar. */
|
|
93
|
+
private readNumber;
|
|
94
|
+
private readLiteral;
|
|
95
|
+
/** Consumes one value without constructing anything, checking it against the grammar. */
|
|
96
|
+
private skipValue;
|
|
97
|
+
private skipValueInner;
|
|
98
|
+
/** A quoted name — a struct field, an object member, a variant case — at the cursor. */
|
|
99
|
+
private readName;
|
|
100
|
+
/** The `:` after a name. */
|
|
101
|
+
private expectColon;
|
|
102
|
+
/**
|
|
103
|
+
* Descends to the node the RFC 6901 pointer names.
|
|
104
|
+
*
|
|
105
|
+
* @param pointer - The pointer to follow
|
|
106
|
+
* @param enter - Whether to step inside the node and iterate it, rather
|
|
107
|
+
* than stop in front of it to read it whole
|
|
108
|
+
*/
|
|
109
|
+
private descend;
|
|
110
|
+
/** Positions the cursor on the value of `key`, skipping the members before it. */
|
|
111
|
+
private enterObjectMember;
|
|
112
|
+
/** Positions the cursor on element `index`, skipping the elements before it. */
|
|
113
|
+
private enterArrayIndex;
|
|
114
|
+
/**
|
|
115
|
+
* Whether another element remains in the container being iterated.
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* A predicate: it consumes the container's closing bracket once there is
|
|
119
|
+
* nothing left, and otherwise leaves the cursor where it was. Advancing is
|
|
120
|
+
* {@link next}'s job, so the two do not have to alternate.
|
|
121
|
+
*/
|
|
122
|
+
more(): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Reads the next element as `type`.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* For an object container, `type` must be a two-field struct named `key`
|
|
128
|
+
* and `value`, in either order, and each member arrives as one of those.
|
|
129
|
+
* An error inside an element is located by its index in an array and by
|
|
130
|
+
* its member name in an object, as RFC 6901 addresses them.
|
|
131
|
+
*/
|
|
132
|
+
next(type: EastTypeValue): unknown;
|
|
133
|
+
/**
|
|
134
|
+
* The value type of an object entry: `type` must be a struct of exactly
|
|
135
|
+
* the fields `key` and `value`, in either order, with a String key.
|
|
136
|
+
*/
|
|
137
|
+
private entryValueType;
|
|
138
|
+
/** One object member, as a `{ key, value }` struct. */
|
|
139
|
+
private readMember;
|
|
140
|
+
/** Reads one whole value, strictly, as `type`. */
|
|
141
|
+
readValue(type: EastTypeValue): unknown;
|
|
142
|
+
private readValueInner;
|
|
143
|
+
/** Recursive type bodies, keyed by the id their wrapper carries. */
|
|
144
|
+
private recursive;
|
|
145
|
+
/** Runs `body` for each element of a JSON array. */
|
|
146
|
+
private eachElement;
|
|
147
|
+
private readOneElementArray;
|
|
148
|
+
private readEntry;
|
|
149
|
+
private readStruct;
|
|
150
|
+
private readVariant;
|
|
151
|
+
}
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=json_reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json_reader.d.ts","sourceRoot":"","sources":["../../src/json_reader.ts"],"names":[],"mappings":"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"}
|