




















@@ -0,0 +1,143 @@
1+const MAX_SAFE_INTEGER_ABS_STR = String(Number.MAX_SAFE_INTEGER);
2+3+function isAsciiDigit(ch: string | undefined): boolean {
4+return ch !== undefined && ch >= "0" && ch <= "9";
5+}
6+7+function parseJsonNumberToken(
8+input: string,
9+start: number,
10+): { token: string; end: number; isInteger: boolean } | null {
11+let idx = start;
12+if (input[idx] === "-") {
13+idx += 1;
14+}
15+if (idx >= input.length) {
16+return null;
17+}
18+19+if (input[idx] === "0") {
20+idx += 1;
21+} else if (isAsciiDigit(input[idx]) && input[idx] !== "0") {
22+while (isAsciiDigit(input[idx])) {
23+idx += 1;
24+}
25+} else {
26+return null;
27+}
28+29+let isInteger = true;
30+if (input[idx] === ".") {
31+isInteger = false;
32+idx += 1;
33+if (!isAsciiDigit(input[idx])) {
34+return null;
35+}
36+while (isAsciiDigit(input[idx])) {
37+idx += 1;
38+}
39+}
40+41+if (input[idx] === "e" || input[idx] === "E") {
42+isInteger = false;
43+idx += 1;
44+if (input[idx] === "+" || input[idx] === "-") {
45+idx += 1;
46+}
47+if (!isAsciiDigit(input[idx])) {
48+return null;
49+}
50+while (isAsciiDigit(input[idx])) {
51+idx += 1;
52+}
53+}
54+55+return {
56+token: input.slice(start, idx),
57+end: idx,
58+ isInteger,
59+};
60+}
61+62+function isUnsafeIntegerLiteral(token: string): boolean {
63+const digits = token[0] === "-" ? token.slice(1) : token;
64+if (digits.length < MAX_SAFE_INTEGER_ABS_STR.length) {
65+return false;
66+}
67+if (digits.length > MAX_SAFE_INTEGER_ABS_STR.length) {
68+return true;
69+}
70+return digits > MAX_SAFE_INTEGER_ABS_STR;
71+}
72+73+export function quoteUnsafeIntegerLiterals(input: string): string {
74+let out = "";
75+let inString = false;
76+let escaped = false;
77+let idx = 0;
78+79+while (idx < input.length) {
80+const ch = input[idx] ?? "";
81+if (inString) {
82+out += ch;
83+if (escaped) {
84+escaped = false;
85+} else if (ch === "\\") {
86+escaped = true;
87+} else if (ch === '"') {
88+inString = false;
89+}
90+idx += 1;
91+continue;
92+}
93+94+if (ch === '"') {
95+inString = true;
96+out += ch;
97+idx += 1;
98+continue;
99+}
100+101+if (ch === "-" || isAsciiDigit(ch)) {
102+const parsed = parseJsonNumberToken(input, idx);
103+if (parsed) {
104+if (parsed.isInteger && isUnsafeIntegerLiteral(parsed.token)) {
105+out += `"${parsed.token}"`;
106+} else {
107+out += parsed.token;
108+}
109+idx = parsed.end;
110+continue;
111+}
112+}
113+114+out += ch;
115+idx += 1;
116+}
117+118+return out;
119+}
120+121+export function parseJsonPreservingUnsafeIntegers(input: string): unknown {
122+return JSON.parse(quoteUnsafeIntegerLiterals(input)) as unknown;
123+}
124+125+export function parseJsonObjectPreservingUnsafeIntegers(
126+value: unknown,
127+): Record<string, unknown> | null {
128+if (typeof value === "string") {
129+try {
130+const parsed = parseJsonPreservingUnsafeIntegers(value);
131+if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
132+return parsed as Record<string, unknown>;
133+}
134+} catch {
135+return null;
136+}
137+return null;
138+}
139+if (value && typeof value === "object" && !Array.isArray(value)) {
140+return value as Record<string, unknown>;
141+}
142+return null;
143+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。