Skip to content

Commit 0f1a2b0

Browse files
fix: convert YAML numbers with leading zeros to JSON strings (#108)
1 parent 76cb102 commit 0f1a2b0

File tree

2 files changed

+91
-2
lines changed

2 files changed

+91
-2
lines changed

json/json.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,25 @@ func writeJSONScalar(ctx *jsonWriteContext, node *yaml.Node) error {
362362
ctx.write(quoteJSONString(node.Value))
363363
return nil
364364

365-
case "!!int", "!!float":
366-
// Numbers - write as-is
365+
case "!!int":
366+
// Check for invalid JSON number formats (e.g., leading zeros)
367+
// In YAML, "009911" might be parsed as int, but JSON doesn't allow leading zeros
368+
// Treat such values as strings to preserve them correctly
369+
if hasInvalidJSONNumberFormat(node.Value) {
370+
ctx.write(quoteJSONString(node.Value))
371+
return nil
372+
}
373+
ctx.write(node.Value)
374+
return nil
375+
376+
case "!!float":
377+
// Check for invalid JSON number formats (e.g., leading zeros)
378+
// YAML may tag values like "009911" as float, but they're invalid in JSON
379+
// Treat such values as strings to preserve them correctly
380+
if hasInvalidJSONNumberFormat(node.Value) {
381+
ctx.write(quoteJSONString(node.Value))
382+
return nil
383+
}
367384
ctx.write(node.Value)
368385
return nil
369386

@@ -384,6 +401,31 @@ func writeJSONScalar(ctx *jsonWriteContext, node *yaml.Node) error {
384401
}
385402
}
386403

404+
// hasInvalidJSONNumberFormat checks if a numeric string would be invalid in JSON.
405+
// JSON numbers cannot have leading zeros (except for "0" itself or "0.x" floats).
406+
func hasInvalidJSONNumberFormat(value string) bool {
407+
if len(value) < 2 {
408+
return false
409+
}
410+
411+
// Handle negative numbers
412+
start := 0
413+
if value[0] == '-' || value[0] == '+' {
414+
start = 1
415+
if len(value) < 2 {
416+
return false
417+
}
418+
}
419+
420+
// Check for leading zero followed by more digits (invalid in JSON)
421+
// "0" alone is valid, "0.x" is valid, but "00", "01", "007" etc. are not
422+
if value[start] == '0' && len(value) > start+1 && value[start+1] >= '0' && value[start+1] <= '9' {
423+
return true
424+
}
425+
426+
return false
427+
}
428+
387429
// resolveMergeKeys processes YAML merge keys (<<) and returns content with merged values
388430
func resolveMergeKeys(content []*yaml.Node) []*yaml.Node {
389431
if len(content) == 0 {

json/json_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,53 @@ upperCaseBool: FALSE
228228
`,
229229
indentation: 2,
230230
},
231+
{
232+
name: "integer with leading zeros",
233+
yamlInput: `bankCode: 009911`,
234+
expectedJSON: `{
235+
"bankCode": "009911"
236+
}
237+
`,
238+
indentation: 2,
239+
},
240+
{
241+
name: "multiple integers with leading zeros",
242+
yamlInput: `identifiers:
243+
bankCode: 009911
244+
sortCode: 001234`,
245+
expectedJSON: `{
246+
"identifiers": {
247+
"bankCode": "009911",
248+
"sortCode": "001234"
249+
}
250+
}
251+
`,
252+
indentation: 2,
253+
},
254+
{
255+
name: "integers with leading zeros in array",
256+
yamlInput: `codes: [009911, 001234, 005678]`,
257+
expectedJSON: `{
258+
"codes": ["009911", "001234", "005678"]
259+
}
260+
`,
261+
indentation: 2,
262+
},
263+
{
264+
name: "octal-like integer value",
265+
yamlInput: `value: 0777`,
266+
expectedJSON: `{
267+
"value": "0777"
268+
}
269+
`,
270+
indentation: 2,
271+
},
272+
{
273+
name: "quoted string with leading zeros preserved",
274+
yamlInput: `bankCode: "009911"`,
275+
expectedJSON: `{"bankCode":"009911"}` + "\n",
276+
indentation: 0,
277+
},
231278
}
232279

233280
for _, tt := range tests {

0 commit comments

Comments
 (0)