| @@ -5,14 +5,33 @@ import addFormats from "ajv-formats"; · 4 unmodified lines |
| 5 | import type { StandardSchema } from "./types"; | 5 | import type { StandardSchema } from "./types"; |
| 6 | import { unknownInputSchema } from "./types"; | 6 | import { unknownInputSchema } from "./types"; |
| 7 | | 7 | |
| 8 | const ajv = new Ajv2020({ | 8 | // Built on first use, not at import. Two reasons, and the second is the one |
| 9 | allErrors: true, | 9 | // that matters beyond this file: |
| 10 | strict: false, | 10 | // |
| 11 | validateSchema: false, | 11 | // 1. Constructing an Ajv instance and registering every format is real work, |
| 12 | allowUnionTypes: true, | 12 | // and it ran on each cold isolate that so much as imported this package — |
| 13 | }); | 13 | // including the many that never validate a schema. |
| | 14 | // 2. `new Ajv2020(...)` + `addFormats(...)` at module scope are import-time |
| | 15 | // side effects, so a bundler must keep this module (and therefore ajv) |
| | 16 | // whenever anything touches the package barrel. `packages/core/execution` |
| | 17 | // imports exactly one runtime value from it — `CodeExecutionError` — and |
| | 18 | // the rest as erased types, yet still dragged ajv AND sucrase into the |
| | 19 | // server graph. With no module-scope effects left here, `sideEffects: |
| | 20 | // false` in package.json is honest and the unused modules tree-shake out. |
| | 21 | let ajvInstance: Ajv2020 | undefined; |
| 14 | | 22 | |
| 15 | addFormats(ajv); | 23 | const getAjv = (): Ajv2020 => { |
| | 24 | if (ajvInstance === undefined) { |
| | 25 | ajvInstance = new Ajv2020({ |
| | 26 | allErrors: true, |
| | 27 | strict: false, |
| | 28 | validateSchema: false, |
| | 29 | allowUnionTypes: true, |
| | 30 | }); |
| | 31 | addFormats(ajvInstance); |
| | 32 | } |
| | 33 | return ajvInstance; |
| | 34 | }; |
| 16 | | 35 | |
| 17 | const decodePointerSegment = (segment: string): PropertyKey => { | 36 | const decodePointerSegment = (segment: string): PropertyKey => { |
| 18 | const decoded = segment.replaceAll("~1", "/").replaceAll("~0", "~"); | 37 | const decoded = segment.replaceAll("~1", "/").replaceAll("~0", "~"); |
| @@ -47,7 +66,7 @@ export const standardSchemaFromJsonSchema = ( · 28 unmodified lines |
| 47 | ): StandardSchema => { | 66 | ): StandardSchema => { |
| 48 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: AJV compile throws for invalid schemas and this adapter preserves fallback behavior | 67 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: AJV compile throws for invalid schemas and this adapter preserves fallback behavior |
| 49 | try { | 68 | try { |
| 50 | const validate = ajv.compile(schema as Record<string, unknown>); | 69 | const validate = getAjv().compile(schema as Record<string, unknown>); |
| 51 | | 70 | |
| 52 | return { | 71 | return { |
| 53 | "~standard": { | 72 | "~standard": { |