Skip to content

Commit

Permalink
Render maps with all null values as ? a\n? b\n or { a, b }
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed Dec 29, 2018
1 parent 53cde39 commit 40b7a2a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 19 deletions.
22 changes: 21 additions & 1 deletion __tests__/corner-cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe('eemeli/yaml#l19', () => {
test('seq', () => {
const src = '- a: # 123'
const doc = YAML.parseDocument(src)
expect(String(doc)).toBe('- a: # 123\n null\n')
expect(String(doc)).toBe('- ? a # 123\n')
})
})

Expand Down Expand Up @@ -275,3 +275,23 @@ test('comment on single-line value in flow map', () => {
const doc = YAML.parseDocument(src)
expect(String(doc)).toBe('{\n a: 1 #c\n}\n')
})

describe('maps with no values', () => {
test('block map', () => {
const src = `a: null\n? b #c`
const doc = YAML.parseDocument(src)
expect(String(doc)).toBe(`? a\n? b #c\n`)
doc.contents.items[1].value = 'x'
expect(String(doc)).toBe(`a: null\n? b #c\n: x\n`)
})

test('flow map', () => {
const src = `{\na: null,\n? b\n}`
const doc = YAML.parseDocument(src)
expect(String(doc)).toBe(`{ a, b }\n`)
doc.contents.items[1].comment = 'c'
expect(String(doc)).toBe(`{\n a,\n b #c\n}\n`)
doc.contents.items[1].value = 'x'
expect(String(doc)).toBe(`{\n a: null,\n b: #c\n x\n}\n`)
})
})
58 changes: 45 additions & 13 deletions src/schema/Collection.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,74 @@
import addComment from '../addComment'
import Node from './Node'
import Pair from './Pair'
import Scalar from './Scalar'

export default class Collection extends Node {
static maxFlowStringSingleLineLength = 60

items = []

hasAllNullValues() {
return this.items.every(node => {
if (!(node instanceof Pair)) return false
const n = node.value
return (
n == null ||
(n instanceof Scalar &&
n.value == null &&
!n.commentBefore &&
!n.comment &&
!n.tag)
)
})
}

// overridden in implementations
toJSON() {
return null
}

toString(ctx, { blockItem, flowChars, itemIndent }, onComment, onChompKeep) {
toString(
ctx,
{ blockItem, flowChars, isMap, itemIndent },
onComment,
onChompKeep
) {
const { doc, indent } = ctx
const inFlow =
(this.type && this.type.substr(0, 4) === 'FLOW') || ctx.inFlow
if (inFlow) itemIndent += ' '
ctx = Object.assign({}, ctx, { indent: itemIndent, inFlow, type: null })
const allNullValues = isMap && this.hasAllNullValues()
ctx = Object.assign({}, ctx, {
allNullValues,
indent: itemIndent,
inFlow,
type: null
})
let chompKeep = false
let hasItemWithNewLine = false
const nodes = this.items.reduce((nodes, item, i) => {
let comment
if (item) {
if (!chompKeep && item.spaceBefore) {
hasItemWithNewLine = true
if (!chompKeep && item.spaceBefore)
nodes.push({ type: 'comment', str: '' })
}
if (item.commentBefore) {
hasItemWithNewLine = true

if (item.commentBefore)
item.commentBefore.match(/^.*$/gm).forEach(line => {
nodes.push({ type: 'comment', str: `#${line}` })
})
}
if (item.comment) {

if (item.comment) comment = item.comment

if (
inFlow &&
((!chompKeep && item.spaceBefore) ||
item.commentBefore ||
item.comment ||
(item.key && (item.key.commentBefore || item.key.comment)) ||
(item.value && (item.value.commentBefore || item.value.comment)))
)
hasItemWithNewLine = true
comment = item.comment
}
if (item.value && item.value.comment) hasItemWithNewLine = true
}
chompKeep = false
let str = doc.schema.stringify(
Expand All @@ -45,7 +77,7 @@ export default class Collection extends Node {
() => (comment = null),
() => (chompKeep = true)
)
if (!hasItemWithNewLine && str.indexOf('\n') !== -1)
if (inFlow && !hasItemWithNewLine && str.includes('\n'))
hasItemWithNewLine = true
if (inFlow && i < this.items.length - 1) str += ','
str = addComment(str, itemIndent, comment)
Expand Down
1 change: 1 addition & 0 deletions src/schema/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export default class YAMLMap extends Collection {
{
blockItem: n => n.str,
flowChars: { start: '{', end: '}' },
isMap: true,
itemIndent: ctx.indent || ''
},
onComment,
Expand Down
21 changes: 16 additions & 5 deletions src/schema/Pair.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,22 @@ export default class Pair extends Node {
implicitKey: !explicitKey,
indent: indent + ' '
})
let str = doc.schema.stringify(key, ctx, () => {
keyComment = null
})
let chompKeep = false
let str = doc.schema.stringify(
key,
ctx,
() => (keyComment = null),
() => (chompKeep = true)
)
str = addComment(str, ctx.indent, keyComment)
str = explicitKey ? `? ${str}\n${indent}:` : `${str}:` // FIXME: Allow for `? key` w/o value
if (ctx.allNullValues) {
if (this.comment) {
str = addComment(str, ctx.indent, this.comment)
if (onComment) onComment()
} else if (chompKeep && !keyComment && onChompKeep) onChompKeep()
return ctx.inFlow ? str : `? ${str}`
}
str = explicitKey ? `? ${str}\n${indent}:` : `${str}:`
if (this.comment) {
// expected (but not strictly required) to be a single-line comment
str = addComment(str, ctx.indent, this.comment)
Expand All @@ -72,7 +83,7 @@ export default class Pair extends Node {
}
ctx.implicitKey = false
let valueComment = value instanceof Node && value.comment
let chompKeep = false
chompKeep = false
const valueStr = doc.schema.stringify(
value,
ctx,
Expand Down
1 change: 1 addition & 0 deletions src/schema/Seq.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class YAMLSeq extends Collection {
{
blockItem: n => (n.type === 'comment' ? n.str : `- ${n.str}`),
flowChars: { start: '[', end: ']' },
isMap: false,
itemIndent: (ctx.indent || '') + ' '
},
onComment,
Expand Down

0 comments on commit 40b7a2a

Please sign in to comment.