diff --git a/src/options.ts b/src/options.ts index 2b8a0585..7a48af2b 100644 --- a/src/options.ts +++ b/src/options.ts @@ -329,6 +329,15 @@ export type ToStringOptions = { */ indentSeq?: boolean + /** + * Whether indentation in srcToken should be preserved. + * + * For this to work, you need to have parsed the yaml document with keepSourceTokens: true + * + * Default: `false` + */ + keepIndent?: boolean + /** * Maximum line width (set to `0` to disable folding). * @@ -387,4 +396,4 @@ export type ToStringOptions = { * Default: `'true'` */ verifyAliasOrder?: boolean -} +} \ No newline at end of file diff --git a/src/stringify/stringify.ts b/src/stringify/stringify.ts index 533f5ff7..2ad90408 100644 --- a/src/stringify/stringify.ts +++ b/src/stringify/stringify.ts @@ -50,6 +50,7 @@ export function createStringifyContext( falseStr: 'false', flowCollectionPadding: true, indentSeq: true, + keepIndent: false, lineWidth: 80, minContentWidth: 20, nullStr: 'null', @@ -175,4 +176,4 @@ export function stringify( return isScalar(node) || str[0] === '{' || str[0] === '[' ? `${props} ${str}` : `${props}\n${ctx.indent}${str}` -} +} \ No newline at end of file diff --git a/src/stringify/stringifyPair.ts b/src/stringify/stringifyPair.ts index 5de8e874..de4f61bc 100644 --- a/src/stringify/stringifyPair.ts +++ b/src/stringify/stringifyPair.ts @@ -15,9 +15,9 @@ export function stringifyPair( allNullValues, doc, indent, - indentStep, - options: { commentString, indentSeq, simpleKeys } + options: { commentString, indentSeq, keepIndent, simpleKeys } } = ctx + let keyComment = (isNode(key) && key.comment) || null if (simpleKeys) { if (keyComment) { @@ -37,6 +37,17 @@ export function stringifyPair( ? key.type === Scalar.BLOCK_FOLDED || key.type === Scalar.BLOCK_LITERAL : typeof key === 'object')) + let indentStep = ctx.indentStep + if ( + keepIndent && + isNode(value) && + value.srcToken && + 'indent' in value.srcToken + ) { + const diff = value.srcToken.indent - indent.length + indentStep = ' '.repeat(diff) + } + ctx = Object.assign({}, ctx, { allNullValues: false, implicitKey: !explicitKey && (simpleKeys || !allNullValues), @@ -150,7 +161,8 @@ export function stringifyPair( } if (sp0 === -1 || nl0 < sp0) hasPropsLine = true } - if (!hasPropsLine) ws = `\n${ctx.indent}` + if (!hasPropsLine && (indentStep.length > 0 || !value.flow)) + ws = `\n${ctx.indent}` } } else if (valueStr === '' || valueStr[0] === '\n') { ws = '' diff --git a/tests/doc/stringify.ts b/tests/doc/stringify.ts index 4aba165f..2f996f76 100644 --- a/tests/doc/stringify.ts +++ b/tests/doc/stringify.ts @@ -871,6 +871,128 @@ describe('custom indent', () => { }) }) +describe('keepIndent: true', () => { + test('keep object indentation', () => { + const src = source` + key: + super: indented + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('keep array indentation', () => { + const src = source` + key: + - name: foo + - name: bar + - name: bam + - name: baz + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('keep complex indentation', () => { + const src = source` + key: + super: + - name: foo + - name: bar + - name: bam + - name: baz + metadata: + foo: why + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('handles multiline seq flow on same line', () => { + const src = source` + key: [ + aaaaaaaa, + bbbbbbbb, + cccccccc, + dddddddd, + eeeeeeee, + ffffffff, + gggggggg, + hhhhhhhh + ] + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + test('handles multiline flow on same line', () => { + const src = source` + key: !tag { + one: aaaaaaaa, + two: bbbbbbbb, + three: cccccccc, + four: dddddddd, + five: eeeeeeee + } + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('handles multiline flow on next line', () => { + const src = source` + key: + !tag { + one: aaaaaaaa, + two: bbbbbbbb, + three: cccccccc, + four: dddddddd, + five: eeeeeeee + } + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('handles multiline flow on next line', () => { + const src = source` + key: + !tag { + one: aaaaaaaa, + two: bbbbbbbb, + three: cccccccc, + four: dddddddd, + five: eeeeeeee + } + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('handles explicit key map with no indent', () => { + const src = source` + foo: + ? [ key ] + : !tag + - foo + - bar + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) + + test('handles explicit key map with indent', () => { + const src = source` + foo: + ? [ key ] + : !tag + - foo + - bar + ` + const doc = YAML.parseDocument(src, { keepSourceTokens: true }) + expect(doc.toString({ keepIndent: true })).toBe(src) + }) +}) + describe('indentSeq: false', () => { let obj: unknown beforeEach(() => {