Skip to content

Commit d1aca82

Browse files
authored
Add trailingComma ToString option for multiline flow formatting (#670)
Disabled by default. When enabled, the last entry in a flow map or flow sequence will have a `,` after it if the collection is split across multiple lines. --------- Signed-off-by: David Thompson <davthomp@redhat.com>
1 parent 4321509 commit d1aca82

4 files changed

Lines changed: 202 additions & 3 deletions

File tree

src/options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ export type ToStringOptions = {
371371
*/
372372
singleQuote?: boolean | null
373373

374+
/**
375+
* Add a trailing comma after the last entry in a flow map or flow sequence that's split across multiple lines.
376+
*
377+
* Default: `'false'`
378+
*/
379+
trailingComma?: boolean
380+
374381
/**
375382
* String representation for `true`.
376383
* With the core schema, use `'true'`, `'True'`, or `'TRUE'`.

src/stringify/stringify.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function createStringifyContext(
5555
nullStr: 'null',
5656
simpleKeys: false,
5757
singleQuote: null,
58+
trailingComma: false,
5859
trueStr: 'true',
5960
verifyAliasOrder: true
6061
},

src/stringify/stringifyCollection.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,21 @@ function stringifyFlowCollection(
134134

135135
if (comment) reqNewline = true
136136
let str = stringify(item, itemCtx, () => (comment = null))
137-
if (i < items.length - 1) str += ','
137+
reqNewline ||= lines.length > linesAtValue || str.includes('\n')
138+
if (i < items.length - 1) {
139+
str += ','
140+
} else if (ctx.options.trailingComma) {
141+
if (ctx.options.lineWidth > 0) {
142+
reqNewline ||=
143+
lines.reduce((sum, line) => sum + line.length + 2, 2) +
144+
(str.length + 2) >
145+
ctx.options.lineWidth
146+
}
147+
if (reqNewline) {
148+
str += ','
149+
}
150+
}
138151
if (comment) str += lineComment(str, itemIndent, commentString(comment))
139-
if (!reqNewline && (lines.length > linesAtValue || str.includes('\n')))
140-
reqNewline = true
141152
lines.push(str)
142153
linesAtValue = lines.length
143154
}

tests/doc/stringify.ts

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,186 @@ z:
543543
expect(String(doc)).toBe(src)
544544
})
545545
})
546+
547+
describe('trailing comma (maps)', () => {
548+
test('no trailing comma is added when the flow map is shorter than the word wrap length', () => {
549+
const doc = YAML.parseDocument(source`
550+
{
551+
a: aaa,
552+
b: bbb,
553+
c: ccc
554+
}
555+
`)
556+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
557+
'{ a: aaa, b: bbb, c: ccc }\n'
558+
)
559+
})
560+
test('no trailing comma is added when the flow map is exactly the word wrap length', () => {
561+
const doc = YAML.parseDocument(source`
562+
{
563+
a: aaa,
564+
b: bbb,
565+
c: ccc,
566+
d: dddddd
567+
}
568+
`)
569+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
570+
'{ a: aaa, b: bbb, c: ccc, d: dddddd }\n'
571+
)
572+
})
573+
test('a trailing comma is added when the flow map is exactly one more than the word wrap length', () => {
574+
const doc = YAML.parseDocument(source`
575+
{
576+
a: aaa,
577+
b: bbb,
578+
c: ccc,
579+
d: ddddddd
580+
}
581+
`)
582+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
583+
'{\n a: aaa,\n b: bbb,\n c: ccc,\n d: ddddddd,\n}\n'
584+
)
585+
})
586+
test('no trailing comma is added when the word wrap length is 0', () => {
587+
const doc = YAML.parseDocument(source`
588+
{
589+
a: aaa,
590+
b: bbb,
591+
c: ccc
592+
}
593+
`)
594+
expect(doc.toString({ trailingComma: true, lineWidth: 0 })).toBe(
595+
'{ a: aaa, b: bbb, c: ccc }\n'
596+
)
597+
})
598+
test('a trailing comma is added when a comment is present in the flow map', () => {
599+
const doc = YAML.parseDocument(source`
600+
{
601+
a: aaa, # my cool comment
602+
b: bbb,
603+
c: ccc
604+
}
605+
`)
606+
expect(doc.toString({ trailingComma: true })).toBe(
607+
'{\n a: aaa, # my cool comment\n b: bbb,\n c: ccc,\n}\n'
608+
)
609+
})
610+
test('a trailing comma is added when a newline is present in the flow map', () => {
611+
const doc = YAML.parseDocument(source`
612+
{
613+
a: aaa,
614+
615+
b: bbb
616+
}
617+
`)
618+
expect(doc.toString({ trailingComma: true })).toBe(
619+
'{\n a: aaa,\n\n b: bbb,\n}\n'
620+
)
621+
})
622+
test('a trailing comma is added when one of the entries includes a newline', () => {
623+
const doc = YAML.parseDocument(source`
624+
{
625+
a: {
626+
a: a # a
627+
},
628+
b: bbb
629+
}
630+
`)
631+
expect(doc.toString({ trailingComma: true })).toBe(
632+
'{\n a:\n {\n a: a, # a\n },\n b: bbb,\n}\n'
633+
)
634+
})
635+
})
636+
637+
describe('trailing comma (arrays)', () => {
638+
test('no trailing comma is added when the flow array is shorter than the word wrap length', () => {
639+
const doc = YAML.parseDocument(source`
640+
[
641+
aaa,
642+
bbb,
643+
ccc
644+
]
645+
`)
646+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
647+
'[ aaa, bbb, ccc ]\n'
648+
)
649+
})
650+
test('no trailing comma is added when the flow array is exactly the word wrap length', () => {
651+
const doc = YAML.parseDocument(source`
652+
[
653+
aaaaaa,
654+
bbbbbb,
655+
cccccc,
656+
ddddddddd
657+
]
658+
`)
659+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
660+
'[ aaaaaa, bbbbbb, cccccc, ddddddddd ]\n'
661+
)
662+
})
663+
test('a trailing comma is added when the flow array is exactly one more than the word wrap length', () => {
664+
const doc = YAML.parseDocument(source`
665+
[
666+
aaaaaa,
667+
bbbbbb,
668+
cccccc,
669+
dddddddddd
670+
]
671+
`)
672+
expect(doc.toString({ trailingComma: true, lineWidth: 40 })).toBe(
673+
'[\n aaaaaa,\n bbbbbb,\n cccccc,\n dddddddddd,\n]\n'
674+
)
675+
})
676+
test('no trailing comma is added when the word wrap length is 0', () => {
677+
const doc = YAML.parseDocument(source`
678+
[
679+
aaa,
680+
bbb,
681+
ccc
682+
]
683+
`)
684+
expect(doc.toString({ trailingComma: true, lineWidth: 0 })).toBe(
685+
'[ aaa, bbb, ccc ]\n'
686+
)
687+
})
688+
test('a trailing comma is added when a comment is present in the flow array', () => {
689+
const doc = YAML.parseDocument(source`
690+
[
691+
aaa, # my cool comment
692+
bbb,
693+
ccc
694+
]
695+
`)
696+
expect(doc.toString({ trailingComma: true })).toBe(
697+
'[\n aaa, # my cool comment\n bbb,\n ccc,\n]\n'
698+
)
699+
})
700+
test('a trailing comma is added when a newline is present in the flow array', () => {
701+
const doc = YAML.parseDocument(source`
702+
[
703+
aaa,
704+
705+
bbb
706+
]
707+
`)
708+
expect(doc.toString({ trailingComma: true })).toBe(
709+
'[\n aaa,\n\n bbb,\n]\n'
710+
)
711+
})
712+
test('a trailing comma is added when one of the entries includes a newline', () => {
713+
const doc = YAML.parseDocument(source`
714+
[
715+
{
716+
a: a # a
717+
},
718+
bbb
719+
]
720+
`)
721+
expect(doc.toString({ trailingComma: true })).toBe(
722+
'[\n {\n a: a, # a\n },\n bbb,\n]\n'
723+
)
724+
})
725+
})
546726
})
547727

548728
test('Quoting colons (#43)', () => {

0 commit comments

Comments
 (0)