@amritk/generate-parsers 0.20.0 → 0.21.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/AI.md +4 -2
- package/README.md +87 -23
- package/dist/generators/build-schema.d.ts +7 -1
- package/dist/generators/build-schema.js +4 -2
- package/dist/generators/generate-files.d.ts +7 -0
- package/dist/generators/generate-files.js +4 -1
- package/dist/generators/generate-parser-function.d.ts +9 -1
- package/dist/generators/generate-parser-function.js +333 -128
- package/dist/generators/generate-schema-checks.js +9 -8
- package/dist/generators/generate-strict-assertion.d.ts +6 -0
- package/dist/generators/generate-strict-assertion.js +5 -4
- package/package.json +9 -4
package/AI.md
CHANGED
|
@@ -22,9 +22,11 @@ const files = await buildSchema(schema, 'Document')
|
|
|
22
22
|
|
|
23
23
|
1. **`buildSchema` is `async` and takes POSITIONAL args, no options object.** The
|
|
24
24
|
full signature is
|
|
25
|
-
`buildSchema(rootSchema, rootTypeName, extensions?, typesOnly?, logWarnings?, strict?, helpersMode?, helpersImportPrefix?, readonly?, stripUnknown?, typeSuffix?, importExt?, caseInsensitive?)`.
|
|
25
|
+
`buildSchema(rootSchema, rootTypeName, extensions?, typesOnly?, logWarnings?, strict?, helpersMode?, helpersImportPrefix?, readonly?, stripUnknown?, typeSuffix?, importExt?, caseInsensitive?, schemas?, unknownKeys?)`.
|
|
26
26
|
To set a later flag you must pass every intervening positional. (The README's
|
|
27
|
-
short form omits the trailing seven.)
|
|
27
|
+
short form omits the trailing seven.) `unknownKeys` (`'count-keys'` by default,
|
|
28
|
+
`'count-enumerable'` for Node-only output) picks how a closed object's fast
|
|
29
|
+
path counts keys; nothing in the generated code detects its runtime.
|
|
28
30
|
2. **It returns files in memory — it does NOT write to disk.** You write the
|
|
29
31
|
`GeneratedFile[]` (`{ filename, content }`) yourself. `rootTypeName` becomes
|
|
30
32
|
that filename (lowercased) as well as the `export type` name, so it must be a
|
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ Every option after the first two is **positional** — pass them in this order:
|
|
|
95
95
|
| 12 | `importExt` | `'js' \| 'ts'` | `'js'` | Extension emitted on relative import specifiers. `'js'` is the NodeNext form for output you compile; `'ts'` emits the literal on-disk paths so the sources run unbuilt. |
|
|
96
96
|
| 13 | `caseInsensitive` | `boolean` | `false` | Normalize a mis-cased string to the exact casing of an enum/const member it matches case-insensitively. Coerce mode only. |
|
|
97
97
|
| 14 | `schemas` | `Record<string, unknown>` | — | Documents you have **already loaded**, keyed by the absolute URI a `$ref` names them by. See below. |
|
|
98
|
+
| 15 | `unknownKeys` | `'count-keys' \| 'count-enumerable'` | `'count-keys'` | How a fast path proves a closed object (`additionalProperties: false`, or a `stripUnknown` build) has no undeclared key: a prototype-guarded `Object.keys(input).length` (fastest on Bun) or a `for…in` count (fastest on Node). See [Counting keys on the fast path](#counting-keys-on-the-fast-path). |
|
|
98
99
|
|
|
99
100
|
Returns: `Promise<GeneratedFile[]>`.
|
|
100
101
|
|
|
@@ -184,6 +185,14 @@ nobody registered still stops the build, with a message naming the ref.
|
|
|
184
185
|
<tr>
|
|
185
186
|
<td colspan="3">Normalize a mis-cased string to the exact casing of a declared enum/const member it matches case-insensitively (e.g. hElLo → hello) instead of coercing to the default. Coerce mode only — strict parsers still reject a casing mismatch. Correctly-cased input keeps the exact-match fast path, so the hot path is unaffected.</td>
|
|
186
187
|
</tr>
|
|
188
|
+
<tr>
|
|
189
|
+
<td>🔢 <code>unknownKeys</code></td>
|
|
190
|
+
<td><code>string</code></td>
|
|
191
|
+
<td align="center"><code>"count-keys"</code></td>
|
|
192
|
+
</tr>
|
|
193
|
+
<tr>
|
|
194
|
+
<td colspan="3">How a fast path proves a closed object (additionalProperties: false, or a stripUnknown build) carries no undeclared key. 'count-keys' is a prototype-guarded Object.keys(input).length comparison, the faster form on JavaScriptCore (Bun); 'count-enumerable' is a for…in count that allocates nothing; it was the faster form on Node 22, but on Node 26 'count-keys' ties or wins there too. Keep the default unless you are pinned to an older V8 and have measured your own shapes; nothing detects the runtime at runtime.<br><strong>Allowed:</strong> <code>"count-enumerable"</code>, <code>"count-keys"</code></td>
|
|
195
|
+
</tr>
|
|
187
196
|
</tbody>
|
|
188
197
|
</table>
|
|
189
198
|
<!-- config-table-end -->
|
|
@@ -237,9 +246,10 @@ Three deliberate departures:
|
|
|
237
246
|
Ajv accepts `"a string"` against `{ properties: { a: {} } }`; a parser has to
|
|
238
247
|
return the type it declares, and the declared type is an object.
|
|
239
248
|
|
|
240
|
-
If a strict parser cannot enforce something — a `$ref` cycle
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
If a strict parser cannot enforce something — a `$ref` cycle inside a subschema it
|
|
250
|
+
has to match inline (`contains`, `not`, `propertyNames`, `dependentSchemas`, or an
|
|
251
|
+
`unevaluated*` backstop), which the inline matcher will not unroll; a subschema
|
|
252
|
+
using a keyword it cannot prove — generation **fails with an error naming the keyword** rather than
|
|
243
253
|
emitting a parser that quietly accepts what the schema forbids. Coercing
|
|
244
254
|
(non-strict) parsers are documented to repair rather than reject, so they ignore
|
|
245
255
|
the rejecting keywords by design.
|
|
@@ -266,8 +276,9 @@ no I/O to answer the retrieval step. Everything else — applying the base URIs,
|
|
|
266
276
|
walking anchors across documents, emitting a parser per definition and an import
|
|
267
277
|
graph that links — the generator still has to do.
|
|
268
278
|
|
|
269
|
-
Of the 41 that do not, **18**
|
|
270
|
-
|
|
279
|
+
Of the 41 that do not, **18** follow from the third departure above — the
|
|
280
|
+
`ignores a non-object` cases plus three `ref.json` cases where a recursive `$ref`
|
|
281
|
+
lands on a root that declares `properties` — and **12** are a keyword strict mode will not
|
|
271
282
|
approximate (a cyclic `$ref` with siblings, a cyclic `unevaluatedProperties`) —
|
|
272
283
|
those cost a build error naming the cause, never a wrong verdict. The rest: **8**
|
|
273
284
|
`$dynamicRef`s whose binding depends on the evaluation path (a generator emits one
|
|
@@ -296,20 +307,34 @@ keys) and `parseStrict` (assert + reject undeclared keys) halves of
|
|
|
296
307
|
[`moltar/typescript-runtime-type-benchmarks`](https://github.com/moltar/typescript-runtime-type-benchmarks)
|
|
297
308
|
against the other *pure* parsers — the ones that return a new typed value rather
|
|
298
309
|
than mutating in place — [zod](https://zod.dev) and
|
|
299
|
-
[TypeBox](https://github.com/sinclairzx81/typebox).
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
~
|
|
310
|
+
[TypeBox](https://github.com/sinclairzx81/typebox).
|
|
311
|
+
|
|
312
|
+
Both runtimes were measured together on one machine (Linux x64, a 4-vCPU cloud
|
|
313
|
+
box, Bun 1.4.0 and Node 26.8.1 — the same machine and runtimes as every table in
|
|
314
|
+
this repo), each cell the median of three separate runs of the whole suite.
|
|
315
|
+
Within one sitting a cell repeats to within a few percent; the same suite
|
|
316
|
+
measured hours later moved ~60% across every case at once, so read the ratios
|
|
317
|
+
and treat the absolutes as a property of that box.
|
|
318
|
+
|
|
319
|
+
Parsing valid input at steady state:
|
|
320
|
+
|
|
321
|
+
| case | mode | Bun: mjst | Bun: zod | Bun: typebox | Node: mjst | Node: zod | Node: typebox |
|
|
322
|
+
|:--|:--|--:|--:|--:|--:|--:|--:|
|
|
323
|
+
| user (4 fields) | parseSafe | **~163M** | ~3.3M | ~1.7M | **~88M** | ~4.0M | ~0.67M |
|
|
324
|
+
| order (nested + array) | parseSafe | **~7.7M** | ~0.60M | ~0.26M | **~8.2M** | ~0.64M | ~0.15M |
|
|
325
|
+
| assert (moltar shape) | parseSafe | **~120M** | ~3.5M | ~0.87M | **~66M** | ~5.3M | ~0.35M |
|
|
326
|
+
| user (4 fields) | parseStrict | **~43M** | ~1.9M | ~2.2M | **~55M** | ~2.7M | ~1.5M |
|
|
327
|
+
| order (nested + array) | parseStrict | **~13M** | ~0.36M | ~0.43M | **~8.7M** | ~0.55M | ~0.25M |
|
|
328
|
+
| assert (moltar shape) | parseStrict | **~44M** | ~1.4M | ~1.2M | **~34M** | ~3.5M | ~0.80M |
|
|
329
|
+
|
|
330
|
+
<sub>ops/s, higher is better.</sub>
|
|
331
|
+
|
|
332
|
+
Unlike the validator suite — where TypeBox's compiled checker takes the loose
|
|
333
|
+
moltar shape on V8 — the generated parser leads every case on both engines:
|
|
334
|
+
~12–49× over zod on Bun and ~13–22× on Node. The two `user`/`assert` safe cells
|
|
335
|
+
are the ones to read as ratios rather than absolutes: stripping to four declared
|
|
336
|
+
keys builds one small object and nothing else, which is fast enough that the
|
|
337
|
+
engine's inlining, not the parser, sets the number.
|
|
313
338
|
|
|
314
339
|
What is replicated upstream is the *cases* — the two parse modes and their
|
|
315
340
|
shapes — not the harness. These numbers come from this repo's own measurement
|
|
@@ -321,9 +346,9 @@ reproducible run of both harnesses:
|
|
|
321
346
|
[Against the moltar harness](../generate-validators#against-the-moltar-harness).
|
|
322
347
|
|
|
323
348
|
The trade is a one-shot **prepare** cost that only mjst pays — generating the
|
|
324
|
-
parser source — which measures **~0.
|
|
325
|
-
|
|
326
|
-
nothing to time). That is trivially amortized: you generate once at build time
|
|
349
|
+
parser source — which measures **~0.20–0.74 ms** per schema on Bun and
|
|
350
|
+
**~0.16–0.72 ms** on Node (zod and TypeBox author or interpret their parsers
|
|
351
|
+
with no separate build step, so there is nothing to time). That is trivially amortized: you generate once at build time
|
|
327
352
|
and run the emitted code forever.
|
|
328
353
|
|
|
329
354
|
Every library is checked for agreement — same stripped/rejected output, same
|
|
@@ -333,9 +358,48 @@ the optimiser can't hoist the work away. Micro-benchmark figures vary by machine
|
|
|
333
358
|
and runtime — reproduce with:
|
|
334
359
|
|
|
335
360
|
```bash
|
|
336
|
-
bun run bench
|
|
361
|
+
bun run bench # Bun / JavaScriptCore
|
|
362
|
+
bun run bench:node # Node / V8 (builds the package first, then runs it under node)
|
|
337
363
|
```
|
|
338
364
|
|
|
365
|
+
### Counting keys on the fast path
|
|
366
|
+
|
|
367
|
+
A closed object whose declared properties are all required proves "no undeclared
|
|
368
|
+
key" by counting: the typed checks ahead of the count have already proven every
|
|
369
|
+
declared key present, so exactly *n* keys means no extra. `unknownKeys` (the 15th
|
|
370
|
+
positional argument, `--unknown-keys` on the CLI) picks how the count is spelled,
|
|
371
|
+
because the two spellings trade places between the engines:
|
|
372
|
+
|
|
373
|
+
- **`'count-keys'`** (default) — `Object.getPrototypeOf(input) === Object.prototype
|
|
374
|
+
&& Object.keys(input).length === n`, one more term of the fast-path guard. The
|
|
375
|
+
prototype guard keeps an own-key count sound: a crafted prototype could satisfy
|
|
376
|
+
the typed checks through an inherited declared key while an own extra kept the
|
|
377
|
+
count at *n*, so a non-plain object takes the cold path instead, whose `for…in`
|
|
378
|
+
rejection sees the inherited key.
|
|
379
|
+
- **`'count-enumerable'`** — `let c = 0; for (const k in input) c++`, as
|
|
380
|
+
statements behind the guard. It allocates nothing and needs no prototype guard
|
|
381
|
+
(the count sees inherited keys too), and on V8 it is answered from the enum
|
|
382
|
+
cache. On JavaScriptCore a `for…in` over a non-extensible object is the engine's
|
|
383
|
+
slow path, and the strict parse runs at half speed.
|
|
384
|
+
|
|
385
|
+
A nested object's shape is proven on the parent's fast path by the same checks
|
|
386
|
+
its own shape validator makes, spelled out over the cached local rather than
|
|
387
|
+
called — `typeof _nested === "object" && … && Object.keys(_nested).length === n`
|
|
388
|
+
— one level deep and within a size budget, because a call was the one thing
|
|
389
|
+
left on the strict fast path that JavaScriptCore would not see through. Under
|
|
390
|
+
the moltar harness (each case alone in its own process) `parseStrict` reaches
|
|
391
|
+
the harness floor on Bun 1.4.0 (~360M ops/s, the call eliminated) with
|
|
392
|
+
`count-keys` against ~22M with `count-enumerable`.
|
|
393
|
+
|
|
394
|
+
On Node the answer has moved with the engine. On Node 22 the two spellings were
|
|
395
|
+
level (~14M either way, which is where the advice to flip it came from); on
|
|
396
|
+
Node 26.8.1 `count-keys` measures ~29M against `count-enumerable`'s ~26M, so the
|
|
397
|
+
default now ties or wins on both engines. Keep the default unless you are
|
|
398
|
+
pinned to an older V8 and have measured your own shapes. See
|
|
399
|
+
[Choosing how keys are counted](../generate-validators#choosing-how-keys-are-counted)
|
|
400
|
+
in the sister package for the validator numbers and the full trade-off. Whichever
|
|
401
|
+
you pick, every verdict on a value that could have come from JSON is the same.
|
|
402
|
+
|
|
339
403
|
---
|
|
340
404
|
|
|
341
405
|
## Related packages
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type UnknownKeysStrategy } from '@amritk/helpers/unknown-keys-strategy';
|
|
1
2
|
import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
|
|
2
3
|
import type { HelpersMode } from '../helpers/collect-helpers.js';
|
|
3
4
|
import type { ImportExtension } from '../helpers/collect-imports.js';
|
|
@@ -70,6 +71,11 @@ export type GeneratedFile = {
|
|
|
70
71
|
* is yours to do (or `@amritk/resolve-refs`'), and a `$ref` to a URI nobody registered still
|
|
71
72
|
* stops generation. Only the documents actually referenced get files, so registering more
|
|
72
73
|
* than the schema uses costs nothing in the output.
|
|
74
|
+
* @param unknownKeys - How the generated fast paths prove a closed object
|
|
75
|
+
* (`additionalProperties: false`, or a `stripUnknown` build) carries no undeclared key:
|
|
76
|
+
* `'count-keys'` (the default) compares `Object.keys(input).length` behind a plain-prototype
|
|
77
|
+
* guard, `'count-enumerable'` counts with `for…in`. The first is the faster form on
|
|
78
|
+
* JavaScriptCore (Bun), the second on V8 (Node) — see the README for the measurements.
|
|
73
79
|
* @returns An array of generated TypeScript files
|
|
74
80
|
*
|
|
75
81
|
* @example
|
|
@@ -102,4 +108,4 @@ export type GeneratedFile = {
|
|
|
102
108
|
* });
|
|
103
109
|
* ```
|
|
104
110
|
*/
|
|
105
|
-
export declare const buildSchema: (rootSchema: JSONSchema, rootTypeName: string, extensions?: SchemaExtensions, typesOnly?: boolean, logWarnings?: boolean, strict?: boolean, helpersMode?: HelpersMode, helpersImportPrefix?: string, readonly?: boolean, stripUnknown?: boolean, typeSuffix?: string, importExt?: ImportExtension, caseInsensitive?: boolean, schemas?: Readonly<Record<string, unknown
|
|
111
|
+
export declare const buildSchema: (rootSchema: JSONSchema, rootTypeName: string, extensions?: SchemaExtensions, typesOnly?: boolean, logWarnings?: boolean, strict?: boolean, helpersMode?: HelpersMode, helpersImportPrefix?: string, readonly?: boolean, stripUnknown?: boolean, typeSuffix?: string, importExt?: ImportExtension, caseInsensitive?: boolean, schemas?: Readonly<Record<string, unknown>>, unknownKeys?: UnknownKeysStrategy) => Promise<GeneratedFile[]>;
|
|
@@ -3,6 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { dirname, resolve as resolvePath } from "node:path";
|
|
4
4
|
import { foldNullable } from "@amritk/helpers/fold-nullable";
|
|
5
5
|
import { generateIndexBarrel } from "@amritk/helpers/generate-index-barrel";
|
|
6
|
+
import { DEFAULT_UNKNOWN_KEYS } from "@amritk/helpers/unknown-keys-strategy";
|
|
6
7
|
import { walkRefGraph } from "@amritk/helpers/walk-ref-graph";
|
|
7
8
|
import { applySchemaExtensions } from "../helpers/apply-schema-extensions.js";
|
|
8
9
|
import { generateFile } from "./generate-files.js";
|
|
@@ -26,7 +27,7 @@ const assertRootTypeName = (rootTypeName) => {
|
|
|
26
27
|
return;
|
|
27
28
|
throw new Error(`Invalid root type name ${JSON.stringify(rootTypeName)}: expected a TypeScript identifier. The name is emitted as \`export type <name>\` and, lowercased, used as the output filename, so anything else either fails to compile or escapes the output directory. Derive it with @amritk/helpers' \`deriveRootTypeName\`, which always produces one.`);
|
|
28
29
|
};
|
|
29
|
-
const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict, helpersMode = "package", helpersImportPrefix = "./", readonly = false, stripUnknown = false, typeSuffix = "", importExt = "js", caseInsensitive = false, schemas) => {
|
|
30
|
+
const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict, helpersMode = "package", helpersImportPrefix = "./", readonly = false, stripUnknown = false, typeSuffix = "", importExt = "js", caseInsensitive = false, schemas, unknownKeys = DEFAULT_UNKNOWN_KEYS) => {
|
|
30
31
|
assertRootTypeName(rootTypeName);
|
|
31
32
|
const files = [];
|
|
32
33
|
const usedHelpers = /* @__PURE__ */ new Set();
|
|
@@ -49,7 +50,8 @@ const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logW
|
|
|
49
50
|
...logWarnings !== void 0 ? { logWarnings } : {},
|
|
50
51
|
...strict !== void 0 ? { strict } : {},
|
|
51
52
|
...stripUnknown ? { stripUnknown } : {},
|
|
52
|
-
...caseInsensitive ? { caseInsensitive } : {}
|
|
53
|
+
...caseInsensitive ? { caseInsensitive } : {},
|
|
54
|
+
unknownKeys
|
|
53
55
|
});
|
|
54
56
|
files.push({ filename: `${node.filename}.ts`, content: result.content });
|
|
55
57
|
for (const helper of result.usedHelpers)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type UnknownKeysStrategy } from '@amritk/helpers/unknown-keys-strategy';
|
|
1
2
|
import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
|
|
2
3
|
import { type HelpersMode, type RuntimeHelperName } from '../helpers/collect-helpers.js';
|
|
3
4
|
import { type ImportExtension } from '../helpers/collect-imports.js';
|
|
@@ -92,6 +93,12 @@ type GenerateFileOptions = {
|
|
|
92
93
|
* already-valid input keeps the exact-match fast path.
|
|
93
94
|
*/
|
|
94
95
|
readonly caseInsensitive?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* How the generated fast paths prove a closed object carries no undeclared
|
|
98
|
+
* key — `Object.keys` (the default) or a `for…in` count. See
|
|
99
|
+
* {@link UnknownKeysStrategy} for the trade-off between the two.
|
|
100
|
+
*/
|
|
101
|
+
readonly unknownKeys?: UnknownKeysStrategy;
|
|
95
102
|
};
|
|
96
103
|
/** Result of generating a single parser file. */
|
|
97
104
|
export type GeneratedFileContent = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateTypeDefinition } from "@amritk/helpers/generate-type-definition";
|
|
2
|
+
import { DEFAULT_UNKNOWN_KEYS } from "@amritk/helpers/unknown-keys-strategy";
|
|
2
3
|
import { collectHelpers } from "../helpers/collect-helpers.js";
|
|
3
4
|
import { collectImports, collectImportTypeNames } from "../helpers/collect-imports.js";
|
|
4
5
|
import { generateParserFunction, generateShapeValidator } from "./generate-parser-function.js";
|
|
@@ -40,12 +41,14 @@ const generateFile = (schema, typeName, options) => {
|
|
|
40
41
|
rootSchema,
|
|
41
42
|
typeSuffix
|
|
42
43
|
});
|
|
43
|
-
const
|
|
44
|
+
const unknownKeys = options?.unknownKeys ?? DEFAULT_UNKNOWN_KEYS;
|
|
45
|
+
const shapeValidator = generateShapeValidator(schema, typeName, true, typeSuffix, true, stripUnknown, reservedNames, unknownKeys);
|
|
44
46
|
const parserFunction = generateParserFunction(schema, typeName, {
|
|
45
47
|
useRefImports: true,
|
|
46
48
|
typeSuffix,
|
|
47
49
|
reservedNames,
|
|
48
50
|
shapeValidatorSource: shapeValidator,
|
|
51
|
+
unknownKeys,
|
|
49
52
|
...options?.isRoot !== void 0 ? { isRoot: options.isRoot } : {},
|
|
50
53
|
...rootSchema !== void 0 ? { rootSchema } : {},
|
|
51
54
|
...options?.logWarnings !== void 0 ? { logWarnings: options.logWarnings } : {},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type UnknownKeysStrategy } from '@amritk/helpers/unknown-keys-strategy';
|
|
1
2
|
import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
|
|
2
3
|
/**
|
|
3
4
|
* Options for controlling parser function generation behavior.
|
|
@@ -67,6 +68,13 @@ type GenerateParserOptions = {
|
|
|
67
68
|
* exact `===` fast path and the hot path is unaffected.
|
|
68
69
|
*/
|
|
69
70
|
readonly caseInsensitive?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* How the fast paths prove a closed object carries no undeclared key —
|
|
73
|
+
* `Object.getPrototypeOf(input) === Object.prototype && Object.keys(input).length`
|
|
74
|
+
* (the default) or a `for…in` count. See {@link UnknownKeysStrategy} for the
|
|
75
|
+
* trade-off, and {@link keyCountCheck} for what each form emits.
|
|
76
|
+
*/
|
|
77
|
+
readonly unknownKeys?: UnknownKeysStrategy;
|
|
70
78
|
/**
|
|
71
79
|
* The exact source of the `validate{TypeName}Shape` predicate emitted into
|
|
72
80
|
* the same file as this parser (generate-files produces it for the root
|
|
@@ -108,5 +116,5 @@ export declare const shapeValidatorFunctionName: (typeName: string) => string;
|
|
|
108
116
|
* in additionalProperties). The stub is safe: parents calling it will fall
|
|
109
117
|
* through to the slow path, matching the pre-deep-fast-path behavior.
|
|
110
118
|
*/
|
|
111
|
-
export declare const generateShapeValidator: (schema: JSONSchema, typeName: string, useRefImports: boolean, suffix?: string, exported?: boolean, stripUnknown?: boolean, reservedNames?: ReadonlySet<string
|
|
119
|
+
export declare const generateShapeValidator: (schema: JSONSchema, typeName: string, useRefImports: boolean, suffix?: string, exported?: boolean, stripUnknown?: boolean, reservedNames?: ReadonlySet<string>, unknownKeys?: UnknownKeysStrategy) => string;
|
|
112
120
|
export {};
|