perf(api): fast path json bodies with no large integers (#2214)

This commit is contained in:
Hampus
2026-08-31 00:13:17 +02:00
committed by GitHub
parent 1199b36d1a
commit e160b1bf07
2 changed files with 104 additions and 3 deletions
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
const MAX_SAFE_INTEGER_DECIMAL = Number.MAX_SAFE_INTEGER.toString();
const UNSAFE_INTEGER_DIGIT_RUN = new RegExp(String.raw`\d{${MAX_SAFE_INTEGER_DECIMAL.length}}`);
function isDigit(char: string): boolean {
return char >= '0' && char <= '9';
@@ -21,7 +22,7 @@ function isUnsafeIntegerToken(token: string): boolean {
return digits > MAX_SAFE_INTEGER_DECIMAL;
}
function coerceUnsafeIntegersToStrings(jsonText: string): string {
export function coerceUnsafeIntegersToStrings(jsonText: string): string {
let inString = false;
let escaped = false;
let i = 0;
@@ -76,7 +77,7 @@ function coerceUnsafeIntegersToStrings(jsonText: string): string {
}
export function parseJsonPreservingLargeIntegers(jsonText: string): unknown {
const processed = coerceUnsafeIntegersToStrings(jsonText);
const processed = UNSAFE_INTEGER_DIGIT_RUN.test(jsonText) ? coerceUnsafeIntegersToStrings(jsonText) : jsonText;
const parsed: unknown = JSON.parse(processed);
return parsed;
}
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {describe, expect, it} from 'vitest';
import {parseJsonPreservingLargeIntegers} from '../LosslessJsonParser';
import {coerceUnsafeIntegersToStrings, parseJsonPreservingLargeIntegers} from '../LosslessJsonParser';
describe('parseJsonPreservingLargeIntegers', () => {
it('keeps safe integers as numbers', () => {
@@ -41,3 +41,103 @@ describe('parseJsonPreservingLargeIntegers', () => {
expect(parsed.arr[1]).toBe('1472109478688579732');
});
});
const CORPUS: Array<string> = [
'{"content":"hey","nonce":"1472109478688579732","channel_id":"1472109478688579731"}',
'{"message_ids":["1472109478688579732","1472109478688579733","1472109478688579734"]}',
'{"id":9007199254740991}',
'{"id":9007199254740992}',
'{"id":-9007199254740991}',
'{"id":-9007199254740992}',
'{"id":-1472109478688579732}',
'{"id":999999999999999}',
'{"id":1000000000000000}',
'{"id":9999999999999999}',
'{"id":99999999999999999}',
'{"id":123456789012345}',
'{"id":1234567890123456}',
'{"id":12345678901234567}',
'{"id":0}',
'{"id":-0}',
'{"id":00}',
'{"id":0.00000000000000012345}',
'{"id":1.2345678901234567890}',
'{"id":123456789012345678.9}',
'{"id":1e20}',
'{"id":1E+20}',
'{"id":12345678901234567890e-5}',
'{"id":-1.7976931348623157e308}',
'{"a":1234567890,"b":12345678,"c":9012345678}',
'[1234567890123456789,1,2,3]',
'{"12345678901234567890":1}',
'{"content":"call me at 15551234567890123456789 ok"}',
'{"content":"he said \\"1472109478688579732\\" loudly","id":1472109478688579732}',
'{"content":"trailing backslash \\\\","id":9007199254740993}',
'{"content":"0001472109478688579732"}',
'{"id":0001472109478688579732}',
'{"nested":{"arr":[{"id":1472109478688579732},{"id":15}]},"n":15}',
'{"content":"no digits at all"}',
'{}',
'[]',
'null',
'"1472109478688579732"',
'1472109478688579732',
'{"took":0.062,"id":1472109478688579732}',
];
type ParseResult = {ok: true; value: unknown} | {ok: false; error: string};
function toResult(parse: () => unknown): ParseResult {
try {
return {ok: true, value: parse()};
} catch (error) {
return {ok: false, error: String(error)};
}
}
function parseWithDigitRunGate(jsonText: string, digitRun: number): ParseResult {
const gate = new RegExp(String.raw`\d{${digitRun}}`);
return toResult(() => JSON.parse(gate.test(jsonText) ? coerceUnsafeIntegersToStrings(jsonText) : jsonText));
}
function parseUngated(jsonText: string): ParseResult {
return toResult(() => JSON.parse(coerceUnsafeIntegersToStrings(jsonText)));
}
describe('parseJsonPreservingLargeIntegers digit-run gate', () => {
it('matches the ungated scanner across the corpus', () => {
for (const body of CORPUS) {
expect(
toResult(() => parseJsonPreservingLargeIntegers(body)),
body,
).toEqual(parseUngated(body));
}
});
it('exercises both the fast path and the scan', () => {
const gate = /\d{16}/;
expect(CORPUS.some((body) => !gate.test(body))).toBe(true);
expect(CORPUS.some((body) => gate.test(body))).toBe(true);
});
it('rejects malformed bodies identically on both paths', () => {
for (const body of ['{"id":00}', '{"id":0001472109478688579732}']) {
const gated = toResult(() => parseJsonPreservingLargeIntegers(body));
expect(gated.ok).toBe(false);
expect(gated, body).toEqual(parseUngated(body));
}
});
it('diverges from the ungated scanner when the gate is loosened to 17 digits', () => {
const broken = CORPUS.filter((body) => {
const loosened = parseWithDigitRunGate(body, 17);
const ungated = parseUngated(body);
return JSON.stringify(loosened) !== JSON.stringify(ungated);
});
expect(broken).toContain('{"id":9007199254740992}');
expect(broken).toContain('{"id":9999999999999999}');
expect(broken).toContain('{"id":-9007199254740992}');
});
it('agrees with the ungated scanner when the gate is tightened to 15 digits', () => {
for (const body of CORPUS) {
expect(parseWithDigitRunGate(body, 15), body).toEqual(parseUngated(body));
}
});
});