샘플
ajv 8.20.0: Serialize Infinity and NaN to valid JSON using Ajv JTD compileSerializer with specialNumbers
검증된 샘플 — npm ajv 8.20.0: Serialize Infinity and NaN to valid JSON using Ajv JTD compileSerializer with specialNumbers. node 22 · linux alpine/x64 · docker에서…
sha256:ad81da3e23ff9ca943d2bdf2e20b6ec713e6c014e97019f81d1ff823a68e62d7
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 2
- 빌드한 서명 키
- 2
선언된 환경
node linux x64 node node npm
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-16 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
케이스
HOW- 목표
- Serialize Infinity and NaN to valid JSON using Ajv JTD compileSerializer with specialNumbers
- 패키지
- 심벌
-
- AjvJTD
- ajv.compileSerializer
- 환경
- node
- 생성일
- 2026-08-16T06:23:03Z
컨트랙트
- compile a JTD serializer with float64 property under default settings
- assert default serialization emits unquoted Infinity and NaN literals causing JSON.parse to throw SyntaxError
- compile a JTD serializer with specialNumbers set to null
- assert specialNumbers: null serializes Infinity, -Infinity, and NaN to null conforming to RFC 8259 and JSON.stringify
- assert finite numbers continue to serialize normally
파일
- NOTES.md
- csx.json
- package-lock.json
- package.json
- src/index.mjs
- test/contract.mjs
소스
# Notes
- **search_known_solution answer**: Found sample `sha256:de249b2f65992de63dd2adece0fd7b0829b25af3cd75a5ad075a49696ed69ffc` addressing "Fix ajv throwing \"strict mode: unknown keyword\" when compiling an existing JSON Schema".
- **What a model would have written instead**: A model would assume `ajv.compileSerializer` outputs standard-compliant JSON by default, serializing `Infinity` and `NaN` to `null` like `JSON.stringify`, without knowing that `specialNumbers: "null"` is required to avoid invalid JSON literal emission.
- **How the wrong version fails**: On Ajv versions before 8.18.0 (e.g., 8.17.1), the missing `specialNumbers` option caused `compileSerializer` to unconditionally emit unquoted `Infinity` / `NaN` literals, failing loudly when any downstream consumer called `JSON.parse()` with `SyntaxError: Unexpected token I in JSON at position ...`.
{"case":{"caseId":"case:sha256:452d2f75b96529598aa8c3f2572fbcbfa7a99656454d44ab9fff51f3491970ae","contract":["compile a JTD serializer with float64 property under default settings","assert default serialization emits unquoted Infinity and NaN literals causing JSON.parse to throw SyntaxError","compile a JTD serializer with specialNumbers set to null","assert specialNumbers: null serializes Infinity, -Infinity, and NaN to null conforming to RFC 8259 and JSON.stringify","assert finite numbers continue to serialize normally"],"goal":"Serialize Infinity and NaN to valid JSON using Ajv JTD compileSerializer with specialNumbers","kind":"HOW","packages":["pkg:npm/ajv@8.20.0"],"schemaVersion":1,"symbols":["AjvJTD","ajv.compileSerializer"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/ajv@8.20.0"],"schemaVersion":1,"symbols":["AjvJTD","ajv.compileSerializer"],"verifierAdapter":"node-typescript@1"}
{
"name": "csx-sample-ajv-jtd-special-numbers",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "csx-sample-ajv-jtd-special-numbers",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"ajv": "8.20.0"
}
},
"node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
}
}
}
{
"name": "csx-sample-ajv-jtd-special-numbers",
"version": "1.0.0",
"private": true,
"type": "module",
"license": "MIT-0",
"dependencies": {
"ajv": "8.20.0"
}
}
import AjvJTD from 'ajv/dist/jtd.js';
// By default (or with specialNumbers: 'fast'), Ajv's JTD serializer performs raw string
// concatenation without checking for non-finite float values, emitting unquoted
// Infinity / NaN literals that violate RFC 8259 JSON syntax.
export function compileFastSerializer(schema) {
const ajv = new AjvJTD({ specialNumbers: 'fast' });
return ajv.compileSerializer(schema);
}
// Added in Ajv v8.18.0 (fixing issue #2482 / PR #2487): configuring specialNumbers: 'null'
// ensures Infinity, -Infinity, and NaN serialize to null, matching JSON.stringify behavior
// and producing valid JSON output.
export function compileSafeSerializer(schema) {
const ajv = new AjvJTD({ specialNumbers: 'null' });
return ajv.compileSerializer(schema);
}
import { strict as assert } from 'node:assert';
import { compileFastSerializer, compileSafeSerializer } from '../src/index.mjs';
const schema = {
properties: {
score: { type: 'float64' },
},
};
// 1. By default (and in specialNumbers: "fast" mode), ajv.compileSerializer outputs
// unquoted Infinity and NaN literals for raw speed, producing invalid JSON syntax.
const fastSerializer = compileFastSerializer(schema);
const fastInf = fastSerializer({ score: Infinity });
const fastNegInf = fastSerializer({ score: -Infinity });
const fastNaN = fastSerializer({ score: NaN });
assert.equal(fastInf, '{"score":Infinity}');
assert.equal(fastNegInf, '{"score":-Infinity}');
assert.equal(fastNaN, '{"score":NaN}');
assert.throws(() => JSON.parse(fastInf), SyntaxError);
assert.throws(() => JSON.parse(fastNegInf), SyntaxError);
assert.throws(() => JSON.parse(fastNaN), SyntaxError);
// 2. Since v8.18.0 (fixing #2482), specialNumbers: "null" serializes Infinity, -Infinity,
// and NaN to null, producing valid JSON conforming to JSON.stringify and RFC 8259.
const safeSerializer = compileSafeSerializer(schema);
const safeInf = safeSerializer({ score: Infinity });
const safeNegInf = safeSerializer({ score: -Infinity });
const safeNaN = safeSerializer({ score: NaN });
assert.equal(safeInf, '{"score":null}');
assert.equal(safeNegInf, '{"score":null}');
assert.equal(safeNaN, '{"score":null}');
assert.deepEqual(JSON.parse(safeInf), { score: null });
assert.deepEqual(JSON.parse(safeNegInf), { score: null });
assert.deepEqual(JSON.parse(safeNaN), { score: null });
// 3. Finite numbers continue to serialize normally
const safeFinite = safeSerializer({ score: 42.5 });
assert.equal(safeFinite, '{"score":42.5}');
assert.deepEqual(JSON.parse(safeFinite), { score: 42.5 });
console.log('CONTRACT PASS: ajv JTD specialNumbers: "null" safely serializes non-finite numbers');