stream-validate 0.1.0
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 +145 -0
- package/dist/__tests__/parser.test.d.ts +2 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +77 -0
- package/dist/__tests__/parser.test.js.map +1 -0
- package/dist/__tests__/stream-validate.test.d.ts +2 -0
- package/dist/__tests__/stream-validate.test.d.ts.map +1 -0
- package/dist/__tests__/stream-validate.test.js +203 -0
- package/dist/__tests__/stream-validate.test.js.map +1 -0
- package/dist/events.d.ts +9 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +30 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +40 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +257 -0
- package/dist/parser.js.map +1 -0
- package/dist/stream-validate.d.ts +9 -0
- package/dist/stream-validate.d.ts.map +1 -0
- package/dist/stream-validate.js +44 -0
- package/dist/stream-validate.js.map +1 -0
- package/dist/stream-validator.d.ts +4 -0
- package/dist/stream-validator.d.ts.map +1 -0
- package/dist/stream-validator.js +162 -0
- package/dist/stream-validator.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +23 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +146 -0
- package/dist/validator.js.map +1 -0
- package/package.json +36 -0
package/dist/parser.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IncrementalJsonParser = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Incremental JSON parser that emits ParsedField events as object fields complete.
|
|
6
|
+
* Uses a buffering + scanning approach: buffer incoming chunks, scan for complete
|
|
7
|
+
* JSON values using balanced delimiter counting.
|
|
8
|
+
*/
|
|
9
|
+
class IncrementalJsonParser {
|
|
10
|
+
buf = '';
|
|
11
|
+
streamPos = 0; // cumulative position in overall stream
|
|
12
|
+
scanPos = 0; // where in buf we've already scanned
|
|
13
|
+
feed(chunk) {
|
|
14
|
+
this.buf += chunk;
|
|
15
|
+
this.streamPos += chunk.length;
|
|
16
|
+
return this.scan();
|
|
17
|
+
}
|
|
18
|
+
end() {
|
|
19
|
+
// Flush: attempt to parse whatever remains as a complete object
|
|
20
|
+
const remaining = this.buf.slice(this.scanPos).trim();
|
|
21
|
+
if (!remaining)
|
|
22
|
+
return [];
|
|
23
|
+
try {
|
|
24
|
+
const val = JSON.parse(remaining);
|
|
25
|
+
if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
|
|
26
|
+
return this.extractFields(val, '', this.streamPos);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// incomplete/malformed — nothing more to emit
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
insideObject = false;
|
|
35
|
+
scan() {
|
|
36
|
+
const fields = [];
|
|
37
|
+
// Find the opening '{' if we haven't entered the object yet
|
|
38
|
+
if (!this.insideObject) {
|
|
39
|
+
const openIdx = this.buf.indexOf('{');
|
|
40
|
+
if (openIdx === -1)
|
|
41
|
+
return fields;
|
|
42
|
+
this.insideObject = true;
|
|
43
|
+
this.scanPos = openIdx + 1;
|
|
44
|
+
}
|
|
45
|
+
// Continue scanning for key-value pairs from scanPos
|
|
46
|
+
let pos = this.scanPos;
|
|
47
|
+
while (pos < this.buf.length) {
|
|
48
|
+
// Skip whitespace
|
|
49
|
+
pos = this.skipWhitespace(this.buf, pos);
|
|
50
|
+
if (pos >= this.buf.length)
|
|
51
|
+
break;
|
|
52
|
+
const ch = this.buf[pos];
|
|
53
|
+
// End of object
|
|
54
|
+
if (ch === '}') {
|
|
55
|
+
this.scanPos = pos + 1;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
// Skip commas between fields
|
|
59
|
+
if (ch === ',') {
|
|
60
|
+
pos++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Expect a key (string)
|
|
64
|
+
if (ch !== '"') {
|
|
65
|
+
pos++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// Parse the key
|
|
69
|
+
const keyResult = this.parseString(this.buf, pos);
|
|
70
|
+
if (keyResult === null)
|
|
71
|
+
break; // incomplete key, wait for more data
|
|
72
|
+
const { value: key, endPos: afterKey } = keyResult;
|
|
73
|
+
// Skip whitespace and colon
|
|
74
|
+
let p = this.skipWhitespace(this.buf, afterKey);
|
|
75
|
+
if (p >= this.buf.length)
|
|
76
|
+
break;
|
|
77
|
+
if (this.buf[p] !== ':') {
|
|
78
|
+
pos = p + 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
p++;
|
|
82
|
+
// Skip whitespace before value
|
|
83
|
+
p = this.skipWhitespace(this.buf, p);
|
|
84
|
+
if (p >= this.buf.length)
|
|
85
|
+
break;
|
|
86
|
+
// Parse the value
|
|
87
|
+
const valResult = this.parseValue(this.buf, p);
|
|
88
|
+
if (valResult === null)
|
|
89
|
+
break; // incomplete value, wait for more data
|
|
90
|
+
const { value, endPos: afterVal } = valResult;
|
|
91
|
+
const absPos = this.streamPos - this.buf.length + afterVal;
|
|
92
|
+
// Emit leaf fields for this value
|
|
93
|
+
const subFields = this.extractFields({ [key]: value }, '', absPos);
|
|
94
|
+
fields.push(...subFields);
|
|
95
|
+
this.scanPos = afterVal;
|
|
96
|
+
pos = afterVal;
|
|
97
|
+
}
|
|
98
|
+
return fields;
|
|
99
|
+
}
|
|
100
|
+
skipWhitespace(s, pos) {
|
|
101
|
+
while (pos < s.length && /\s/.test(s[pos]))
|
|
102
|
+
pos++;
|
|
103
|
+
return pos;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse a JSON string starting at pos (which must be `"`).
|
|
107
|
+
* Returns { value, endPos } where endPos is one past the closing `"`, or null if incomplete.
|
|
108
|
+
*/
|
|
109
|
+
parseString(s, pos) {
|
|
110
|
+
if (s[pos] !== '"')
|
|
111
|
+
return null;
|
|
112
|
+
let i = pos + 1;
|
|
113
|
+
while (i < s.length) {
|
|
114
|
+
if (s[i] === '\\') {
|
|
115
|
+
i += 2; // skip escaped character
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (s[i] === '"') {
|
|
119
|
+
const raw = s.slice(pos, i + 1);
|
|
120
|
+
try {
|
|
121
|
+
return { value: JSON.parse(raw), endPos: i + 1 };
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
i++;
|
|
128
|
+
}
|
|
129
|
+
return null; // incomplete
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Parse any JSON value starting at pos.
|
|
133
|
+
* Returns { value, endPos } or null if incomplete.
|
|
134
|
+
*/
|
|
135
|
+
parseValue(s, pos) {
|
|
136
|
+
if (pos >= s.length)
|
|
137
|
+
return null;
|
|
138
|
+
const ch = s[pos];
|
|
139
|
+
if (ch === '"') {
|
|
140
|
+
return this.parseString(s, pos);
|
|
141
|
+
}
|
|
142
|
+
if (ch === '{' || ch === '[') {
|
|
143
|
+
return this.parseBalanced(s, pos);
|
|
144
|
+
}
|
|
145
|
+
// null, true, false
|
|
146
|
+
const literals = [
|
|
147
|
+
['null', null],
|
|
148
|
+
['true', true],
|
|
149
|
+
['false', false],
|
|
150
|
+
];
|
|
151
|
+
for (const [lit, val] of literals) {
|
|
152
|
+
if (s.startsWith(lit, pos)) {
|
|
153
|
+
return { value: val, endPos: pos + lit.length };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Number: ends at `,`, `}`, `]`, whitespace
|
|
157
|
+
const numMatch = s.slice(pos).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/);
|
|
158
|
+
if (numMatch) {
|
|
159
|
+
const numStr = numMatch[0];
|
|
160
|
+
// Make sure the number is actually complete (followed by delimiter or end of known token)
|
|
161
|
+
const afterNum = pos + numStr.length;
|
|
162
|
+
if (afterNum >= s.length) {
|
|
163
|
+
// Could be incomplete (e.g. "1" might become "123") — only safe if followed by delimiter
|
|
164
|
+
// Check if next non-whitespace is a delimiter
|
|
165
|
+
const next = this.skipWhitespace(s, afterNum);
|
|
166
|
+
if (next >= s.length)
|
|
167
|
+
return null; // wait for more
|
|
168
|
+
const nextCh = s[next];
|
|
169
|
+
if (nextCh === ',' || nextCh === '}' || nextCh === ']') {
|
|
170
|
+
return { value: JSON.parse(numStr), endPos: afterNum };
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return { value: JSON.parse(numStr), endPos: afterNum };
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Parse a balanced `{...}` or `[...]` block.
|
|
180
|
+
*/
|
|
181
|
+
parseBalanced(s, pos) {
|
|
182
|
+
const open = s[pos];
|
|
183
|
+
const close = open === '{' ? '}' : ']';
|
|
184
|
+
let depth = 0;
|
|
185
|
+
let i = pos;
|
|
186
|
+
let inString = false;
|
|
187
|
+
while (i < s.length) {
|
|
188
|
+
const ch = s[i];
|
|
189
|
+
if (inString) {
|
|
190
|
+
if (ch === '\\') {
|
|
191
|
+
i += 2;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (ch === '"')
|
|
195
|
+
inString = false;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
if (ch === '"')
|
|
199
|
+
inString = true;
|
|
200
|
+
else if (ch === open)
|
|
201
|
+
depth++;
|
|
202
|
+
else if (ch === close) {
|
|
203
|
+
depth--;
|
|
204
|
+
if (depth === 0) {
|
|
205
|
+
const raw = s.slice(pos, i + 1);
|
|
206
|
+
try {
|
|
207
|
+
return { value: JSON.parse(raw), endPos: i + 1 };
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
i++;
|
|
216
|
+
}
|
|
217
|
+
return null; // incomplete
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Recursively extract leaf fields from a (possibly nested) object/value,
|
|
221
|
+
* emitting one ParsedField per leaf.
|
|
222
|
+
*/
|
|
223
|
+
extractFields(obj, prefix, absPos) {
|
|
224
|
+
const fields = [];
|
|
225
|
+
if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
226
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
227
|
+
const path = prefix ? `${prefix}.${k}` : k;
|
|
228
|
+
if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
|
|
229
|
+
fields.push(...this.extractFields(v, path, absPos));
|
|
230
|
+
}
|
|
231
|
+
else if (Array.isArray(v)) {
|
|
232
|
+
// Emit the array as a single field (with path), plus individual items
|
|
233
|
+
fields.push({ path, value: v, position: absPos });
|
|
234
|
+
for (let idx = 0; idx < v.length; idx++) {
|
|
235
|
+
fields.push(...this.extractFields(v[idx], `${path}[${idx}]`, absPos));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
fields.push({ path, value: v, position: absPos });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else if (Array.isArray(obj)) {
|
|
244
|
+
for (let idx = 0; idx < obj.length; idx++) {
|
|
245
|
+
fields.push(...this.extractFields(obj[idx], `${prefix}[${idx}]`, absPos));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
if (prefix) {
|
|
250
|
+
fields.push({ path: prefix, value: obj, position: absPos });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return fields;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
exports.IncrementalJsonParser = IncrementalJsonParser;
|
|
257
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { StreamValidatorOptions, ValidatedPartial } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Async generator that consumes an AsyncIterable<string> of JSON chunks,
|
|
5
|
+
* progressively validates each field against the schema, and yields
|
|
6
|
+
* ValidatedPartial<T> events as fields complete.
|
|
7
|
+
*/
|
|
8
|
+
export declare function streamValidate<T>(stream: AsyncIterable<string>, schema: z.ZodSchema<T>, options?: StreamValidatorOptions): AsyncIterable<ValidatedPartial<T>>;
|
|
9
|
+
//# sourceMappingURL=stream-validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validate.d.ts","sourceRoot":"","sources":["../src/stream-validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAEvE;;;;GAIG;AACH,wBAAuB,cAAc,CAAC,CAAC,EACrC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EACtB,OAAO,GAAE,sBAA2B,GACnC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CA0CpC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.streamValidate = streamValidate;
|
|
4
|
+
const stream_validator_1 = require("./stream-validator");
|
|
5
|
+
/**
|
|
6
|
+
* Async generator that consumes an AsyncIterable<string> of JSON chunks,
|
|
7
|
+
* progressively validates each field against the schema, and yields
|
|
8
|
+
* ValidatedPartial<T> events as fields complete.
|
|
9
|
+
*/
|
|
10
|
+
async function* streamValidate(stream, schema, options = {}) {
|
|
11
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema, options);
|
|
12
|
+
// Collect partials via the async iterator from the validator
|
|
13
|
+
// We drive the validator with stream chunks and pull partials as they come.
|
|
14
|
+
// Use a two-pump approach: one for the input stream, one for output.
|
|
15
|
+
const partials = [];
|
|
16
|
+
const completionEvents = [];
|
|
17
|
+
let inputDone = false;
|
|
18
|
+
// Run input pump in background (push chunks to validator)
|
|
19
|
+
const inputDonePromise = (async () => {
|
|
20
|
+
for await (const chunk of stream) {
|
|
21
|
+
validator.write(chunk);
|
|
22
|
+
}
|
|
23
|
+
validator.end();
|
|
24
|
+
inputDone = true;
|
|
25
|
+
})();
|
|
26
|
+
// Subscribe to partial events to collect them
|
|
27
|
+
const unsubPartial = validator.on('partial', (p) => {
|
|
28
|
+
partials.push(p);
|
|
29
|
+
});
|
|
30
|
+
const unsubComplete = validator.on('complete', () => {
|
|
31
|
+
completionEvents.push({ done: true });
|
|
32
|
+
});
|
|
33
|
+
// Wait for input to complete, then flush
|
|
34
|
+
await inputDonePromise;
|
|
35
|
+
unsubPartial();
|
|
36
|
+
unsubComplete();
|
|
37
|
+
// Yield all collected partials
|
|
38
|
+
for (const p of partials) {
|
|
39
|
+
yield p;
|
|
40
|
+
}
|
|
41
|
+
void inputDone; // suppress unused warning
|
|
42
|
+
void completionEvents;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=stream-validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validate.js","sourceRoot":"","sources":["../src/stream-validate.ts"],"names":[],"mappings":";;AASA,wCA8CC;AAtDD,yDAA0D;AAG1D;;;;GAIG;AACI,KAAK,SAAS,CAAC,CAAC,cAAc,CACnC,MAA6B,EAC7B,MAAsB,EACtB,UAAkC,EAAE;IAEpC,MAAM,SAAS,GAAG,IAAA,wCAAqB,EAAI,MAAM,EAAE,OAAO,CAAC,CAAA;IAE3D,6DAA6D;IAC7D,4EAA4E;IAC5E,qEAAqE;IAErE,MAAM,QAAQ,GAA+B,EAAE,CAAA;IAC/C,MAAM,gBAAgB,GAA6B,EAAE,CAAA;IACrD,IAAI,SAAS,GAAG,KAAK,CAAA;IAErB,0DAA0D;IAC1D,MAAM,gBAAgB,GAAG,CAAC,KAAK,IAAI,EAAE;QACnC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;QACD,SAAS,CAAC,GAAG,EAAE,CAAA;QACf,SAAS,GAAG,IAAI,CAAA;IAClB,CAAC,CAAC,EAAE,CAAA;IAEJ,8CAA8C;IAC9C,MAAM,YAAY,GAAG,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;QACjD,QAAQ,CAAC,IAAI,CAAC,CAAwB,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,MAAM,aAAa,GAAG,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;QAClD,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,yCAAyC;IACzC,MAAM,gBAAgB,CAAA;IAEtB,YAAY,EAAE,CAAA;IACd,aAAa,EAAE,CAAA;IAEf,+BAA+B;IAC/B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,CAAA;IACT,CAAC;IAED,KAAK,SAAS,CAAA,CAAC,0BAA0B;IACzC,KAAK,gBAAgB,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { StreamValidator, StreamValidatorOptions } from './types';
|
|
3
|
+
export declare function createStreamValidator<T>(schema: z.ZodSchema<T>, options?: StreamValidatorOptions): StreamValidator<T>;
|
|
4
|
+
//# sourceMappingURL=stream-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validator.d.ts","sourceRoot":"","sources":["../src/stream-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EAKvB,MAAM,SAAS,CAAA;AAShB,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EACtB,OAAO,GAAE,sBAA2B,GACnC,eAAe,CAAC,CAAC,CAAC,CAiKpB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStreamValidator = createStreamValidator;
|
|
4
|
+
const parser_1 = require("./parser");
|
|
5
|
+
const validator_1 = require("./validator");
|
|
6
|
+
const events_1 = require("./events");
|
|
7
|
+
function createStreamValidator(schema, options = {}) {
|
|
8
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
9
|
+
const validator = new validator_1.ProgressiveValidator(schema);
|
|
10
|
+
const emitter = new events_1.TypedEmitter();
|
|
11
|
+
const startTime = Date.now();
|
|
12
|
+
let currentPartial = null;
|
|
13
|
+
let done = false;
|
|
14
|
+
const queue = [];
|
|
15
|
+
const waiters = [];
|
|
16
|
+
function enqueue(item) {
|
|
17
|
+
if (waiters.length > 0) {
|
|
18
|
+
const resolve = waiters.shift();
|
|
19
|
+
resolve(item);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
queue.push(item);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function processFields(fields) {
|
|
26
|
+
for (const field of fields) {
|
|
27
|
+
const { partial, error } = validator.applyField(field.path, field.value, {
|
|
28
|
+
strategy: options.validationErrorStrategy ?? 'skip',
|
|
29
|
+
});
|
|
30
|
+
currentPartial = partial;
|
|
31
|
+
if (error) {
|
|
32
|
+
emitter.emit('validation-error', error);
|
|
33
|
+
options.onValidationError?.(error);
|
|
34
|
+
}
|
|
35
|
+
emitter.emit('partial', partial);
|
|
36
|
+
enqueue({ value: partial, done: false });
|
|
37
|
+
if (partial.isComplete && !done) {
|
|
38
|
+
done = true;
|
|
39
|
+
emitComplete(false);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function emitComplete(truncated) {
|
|
44
|
+
const totalMs = Date.now() - startTime;
|
|
45
|
+
const meta = currentPartial?.meta ?? {};
|
|
46
|
+
const requiredPaths = validator.getRequiredPaths();
|
|
47
|
+
const completedFields = Object.values(meta).filter(s => s === 'complete').length;
|
|
48
|
+
const totalFields = requiredPaths.length || Object.keys(meta).length;
|
|
49
|
+
const event = {
|
|
50
|
+
data: (currentPartial?.data ?? {}),
|
|
51
|
+
isComplete: !truncated && validator.isComplete(),
|
|
52
|
+
truncated,
|
|
53
|
+
totalMs,
|
|
54
|
+
completedFields,
|
|
55
|
+
totalFields,
|
|
56
|
+
failedPaths: validator.getFailedPaths(),
|
|
57
|
+
};
|
|
58
|
+
emitter.emit('complete', event);
|
|
59
|
+
enqueue({ done: true });
|
|
60
|
+
}
|
|
61
|
+
// Timeout handling
|
|
62
|
+
let timeoutHandle;
|
|
63
|
+
if (options.timeoutMs) {
|
|
64
|
+
timeoutHandle = setTimeout(() => {
|
|
65
|
+
if (!done) {
|
|
66
|
+
done = true;
|
|
67
|
+
emitComplete(true);
|
|
68
|
+
}
|
|
69
|
+
}, options.timeoutMs);
|
|
70
|
+
}
|
|
71
|
+
// AbortSignal handling
|
|
72
|
+
if (options.signal) {
|
|
73
|
+
options.signal.addEventListener('abort', () => {
|
|
74
|
+
if (!done) {
|
|
75
|
+
done = true;
|
|
76
|
+
if (timeoutHandle)
|
|
77
|
+
clearTimeout(timeoutHandle);
|
|
78
|
+
emitComplete(true);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const streamValidator = {
|
|
83
|
+
write(chunk) {
|
|
84
|
+
if (done)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
const fields = parser.feed(chunk);
|
|
88
|
+
processFields(fields);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const parseErr = {
|
|
92
|
+
message: err instanceof Error ? err.message : String(err),
|
|
93
|
+
position: 0,
|
|
94
|
+
path: '',
|
|
95
|
+
elapsedMs: Date.now() - startTime,
|
|
96
|
+
};
|
|
97
|
+
emitter.emit('parse-error', parseErr);
|
|
98
|
+
options.onParseError?.(parseErr);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
end() {
|
|
102
|
+
if (done)
|
|
103
|
+
return;
|
|
104
|
+
try {
|
|
105
|
+
const fields = parser.end();
|
|
106
|
+
processFields(fields);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
const parseErr = {
|
|
110
|
+
message: err instanceof Error ? err.message : String(err),
|
|
111
|
+
position: 0,
|
|
112
|
+
path: '',
|
|
113
|
+
elapsedMs: Date.now() - startTime,
|
|
114
|
+
};
|
|
115
|
+
emitter.emit('parse-error', parseErr);
|
|
116
|
+
options.onParseError?.(parseErr);
|
|
117
|
+
}
|
|
118
|
+
if (!done) {
|
|
119
|
+
done = true;
|
|
120
|
+
if (timeoutHandle)
|
|
121
|
+
clearTimeout(timeoutHandle);
|
|
122
|
+
emitComplete(false);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
abort(_error) {
|
|
126
|
+
if (done)
|
|
127
|
+
return;
|
|
128
|
+
done = true;
|
|
129
|
+
if (timeoutHandle)
|
|
130
|
+
clearTimeout(timeoutHandle);
|
|
131
|
+
emitComplete(true);
|
|
132
|
+
},
|
|
133
|
+
on(event, fn) {
|
|
134
|
+
return emitter.on(event, fn);
|
|
135
|
+
},
|
|
136
|
+
get current() {
|
|
137
|
+
return currentPartial;
|
|
138
|
+
},
|
|
139
|
+
[Symbol.asyncIterator]() {
|
|
140
|
+
return {
|
|
141
|
+
next() {
|
|
142
|
+
if (queue.length > 0) {
|
|
143
|
+
const item = queue.shift();
|
|
144
|
+
if (item.done)
|
|
145
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
146
|
+
return Promise.resolve({ value: item.value, done: false });
|
|
147
|
+
}
|
|
148
|
+
return new Promise(resolve => {
|
|
149
|
+
waiters.push((item) => {
|
|
150
|
+
if (item.done)
|
|
151
|
+
resolve({ value: undefined, done: true });
|
|
152
|
+
else
|
|
153
|
+
resolve({ value: item.value, done: false });
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
return streamValidator;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=stream-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validator.js","sourceRoot":"","sources":["../src/stream-validator.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
export type DeepPartial<T> = T extends object ? {
|
|
3
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
4
|
+
} : T;
|
|
5
|
+
export type FieldStatus = 'complete' | 'active' | 'pending' | 'error';
|
|
6
|
+
export type FieldMeta = Record<string, FieldStatus>;
|
|
7
|
+
export interface ValidatedPartial<T> {
|
|
8
|
+
data: DeepPartial<T>;
|
|
9
|
+
meta: FieldMeta;
|
|
10
|
+
isComplete: boolean;
|
|
11
|
+
seq: number;
|
|
12
|
+
elapsedMs: number;
|
|
13
|
+
}
|
|
14
|
+
export interface StreamCompletionEvent<T> {
|
|
15
|
+
data: T | DeepPartial<T>;
|
|
16
|
+
isComplete: boolean;
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
totalMs: number;
|
|
19
|
+
completedFields: number;
|
|
20
|
+
totalFields: number;
|
|
21
|
+
failedPaths: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface StreamValidationError {
|
|
24
|
+
path: string;
|
|
25
|
+
value: unknown;
|
|
26
|
+
message: string;
|
|
27
|
+
elapsedMs: number;
|
|
28
|
+
}
|
|
29
|
+
export interface StreamParseError {
|
|
30
|
+
message: string;
|
|
31
|
+
position: number;
|
|
32
|
+
path: string;
|
|
33
|
+
elapsedMs: number;
|
|
34
|
+
}
|
|
35
|
+
export interface StreamValidatorOptions {
|
|
36
|
+
onParseError?: (err: StreamParseError) => void;
|
|
37
|
+
onValidationError?: (err: StreamValidationError) => void;
|
|
38
|
+
validationErrorStrategy?: 'skip' | 'include-invalid' | 'error';
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}
|
|
42
|
+
export interface StreamValidator<T> {
|
|
43
|
+
write(chunk: string): void;
|
|
44
|
+
end(): void;
|
|
45
|
+
abort(error?: Error): void;
|
|
46
|
+
on(event: 'partial', fn: (p: ValidatedPartial<T>) => void): () => void;
|
|
47
|
+
on(event: 'complete', fn: (e: StreamCompletionEvent<T>) => void): () => void;
|
|
48
|
+
on(event: 'parse-error', fn: (e: StreamParseError) => void): () => void;
|
|
49
|
+
on(event: 'validation-error', fn: (e: StreamValidationError) => void): () => void;
|
|
50
|
+
get current(): ValidatedPartial<T> | null;
|
|
51
|
+
[Symbol.asyncIterator](): AsyncIterator<ValidatedPartial<T>>;
|
|
52
|
+
}
|
|
53
|
+
export type _ZodSchemaRef = z.ZodSchema<unknown>;
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ValidatedPartial, StreamValidationError } from './types';
|
|
3
|
+
export declare class ProgressiveValidator<T> {
|
|
4
|
+
private schema;
|
|
5
|
+
private data;
|
|
6
|
+
private meta;
|
|
7
|
+
private seq;
|
|
8
|
+
private startTime;
|
|
9
|
+
private requiredPaths;
|
|
10
|
+
private failedPaths;
|
|
11
|
+
constructor(schema: z.ZodSchema<T>);
|
|
12
|
+
applyField(path: string, value: unknown, options?: {
|
|
13
|
+
strategy?: 'skip' | 'include-invalid' | 'error';
|
|
14
|
+
}): {
|
|
15
|
+
partial: ValidatedPartial<T>;
|
|
16
|
+
error?: StreamValidationError;
|
|
17
|
+
};
|
|
18
|
+
isComplete(): boolean;
|
|
19
|
+
getFailedPaths(): string[];
|
|
20
|
+
getRequiredPaths(): string[];
|
|
21
|
+
buildPartial(): ValidatedPartial<T>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAA0B,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAoF9F,qBAAa,oBAAoB,CAAC,CAAC;IAQrB,OAAO,CAAC,MAAM;IAP1B,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,IAAI,CAAgB;IAC5B,OAAO,CAAC,GAAG,CAAI;IACf,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,WAAW,CAAe;gBAEd,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAI1C,UAAU,CACR,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,OAAO,CAAA;KAAE,GAC5D;QAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,qBAAqB,CAAA;KAAE;IAsClE,UAAU,IAAI,OAAO;IAQrB,cAAc,IAAI,MAAM,EAAE;IAI1B,gBAAgB,IAAI,MAAM,EAAE;IAI5B,YAAY,IAAI,gBAAgB,CAAC,CAAC,CAAC;CASpC"}
|