Skip to content

Commit ec0ea49

Browse files
sserrataclaude
andcommitted
fix(theme): preserve large integer precision in response panel (#1208)
The response pretty-printer round-tripped the body through JSON.parse/JSON.stringify, which silently truncated integers beyond Number.MAX_SAFE_INTEGER (e.g. 19-digit IDs like 1945044589271781376 became 1945044589271781400). Replace the round trip with a small string-level pretty-printer that re-indents structural tokens only, so number literals pass through verbatim. JSON.parse is kept solely as a validity check so malformed bodies still fall through to the XML/raw branch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 6647aa0 commit ec0ea49

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

  • packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Response

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Response/index.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,57 @@ import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
2222

2323
import { clearResponse, clearCode, clearHeaders } from "./slice";
2424

25+
// Pretty-print a JSON string by re-indenting structural tokens only.
26+
// Numbers pass through verbatim, so values beyond Number.MAX_SAFE_INTEGER
27+
// (e.g. 19-digit IDs) keep their exact digits. Issue #1208.
28+
function prettyPrintJson(raw: string, indent = 2): string {
29+
const pad = " ".repeat(indent);
30+
let out = "";
31+
let depth = 0;
32+
let inString = false;
33+
let escape = false;
34+
35+
for (let i = 0; i < raw.length; i++) {
36+
const ch = raw[i];
37+
38+
if (inString) {
39+
out += ch;
40+
if (escape) escape = false;
41+
else if (ch === "\\") escape = true;
42+
else if (ch === '"') inString = false;
43+
continue;
44+
}
45+
46+
if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r") continue;
47+
48+
if (ch === '"') {
49+
out += ch;
50+
inString = true;
51+
} else if (ch === "{" || ch === "[") {
52+
let j = i + 1;
53+
while (j < raw.length && /\s/.test(raw[j])) j++;
54+
if (raw[j] === "}" || raw[j] === "]") {
55+
out += ch + raw[j];
56+
i = j;
57+
} else {
58+
depth++;
59+
out += ch + "\n" + pad.repeat(depth);
60+
}
61+
} else if (ch === "}" || ch === "]") {
62+
depth--;
63+
out += "\n" + pad.repeat(depth) + ch;
64+
} else if (ch === ",") {
65+
out += ",\n" + pad.repeat(depth);
66+
} else if (ch === ":") {
67+
out += ": ";
68+
} else {
69+
out += ch;
70+
}
71+
}
72+
73+
return out;
74+
}
75+
2576
// TODO: We probably shouldn't attempt to format XML...
2677
function formatXml(xml: string) {
2778
const tab = " ";
@@ -70,7 +121,8 @@ function Response({ item }: { item: ApiItem }) {
70121

71122
if (prettyResponse) {
72123
try {
73-
prettyResponse = JSON.stringify(JSON.parse(response), null, 2);
124+
JSON.parse(response);
125+
prettyResponse = prettyPrintJson(response);
74126
} catch {
75127
if (response.startsWith("<")) {
76128
prettyResponse = formatXml(response);

0 commit comments

Comments
 (0)