Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parsing of minimal strings: '', '-', '?', ':' #61

Merged
merged 2 commits into from
Dec 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions __tests__/corner-cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,8 @@ test('fake node should respect setOrigRanges()', () => {
origEnd: 2
})
})

test('parse an empty string as null', () => {
const value = YAML.parse('')
expect(value).toBeNull()
})
49 changes: 49 additions & 0 deletions __tests__/cst/corner-cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,52 @@ test('eemeli/yaml#56', () => {
type: 'PLAIN'
})
})

describe('collection indicator as last char', () => {
test('seq item', () => {
const src = '-'
const doc = parse(src)[0]
expect(doc.contents[0]).toMatchObject({
type: 'SEQ',
items: [{ type: 'SEQ_ITEM', node: null }]
})
})

test('explicit map key', () => {
const src = '?'
const doc = parse(src)[0]
expect(doc.contents[0]).toMatchObject({
type: 'MAP',
items: [{ type: 'MAP_KEY', node: null }]
})
})

test('empty map value', () => {
const src = ':'
const doc = parse(src)[0]
expect(doc.contents[0]).toMatchObject({
type: 'MAP',
items: [{ type: 'MAP_VALUE', node: null }]
})
})

test('indented seq-in-seq', () => {
const src = ` -\n - - a\n -`
const doc = parse(src)[0]
expect(doc.contents[0]).toMatchObject({
items: [
{ error: null },
{ node: { items: [{ node: { type: 'PLAIN', strValue: 'a' } }] } },
{ error: null }
]
})
})
})

test('parse an empty string as an empty document', () => {
const doc = parse('')[0]
expect(doc).toMatchObject({
error: null,
contents: []
})
})
7 changes: 4 additions & 3 deletions src/cst/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,16 @@ export default class Node {
return null
}

static atBlank(src, offset) {
static atBlank(src, offset, endAsBlank) {
const ch = src[offset]
return ch === '\n' || ch === '\t' || ch === ' '
return ch === '\n' || ch === '\t' || ch === ' ' || (endAsBlank && !ch)
}

static atCollectionItem(src, offset) {
const ch = src[offset]
return (
(ch === '?' || ch === ':' || ch === '-') && Node.atBlank(src, offset + 1)
(ch === '?' || ch === ':' || ch === '-') &&
Node.atBlank(src, offset + 1, true)
)
}

Expand Down
9 changes: 5 additions & 4 deletions src/cst/ParseContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ export default class ParseContext {
case '[':
return Type.FLOW_SEQ
case '?':
return !inFlow && Node.atBlank(src, offset + 1)
return !inFlow && Node.atBlank(src, offset + 1, true)
? Type.MAP_KEY
: Type.PLAIN
case ':':
return !inFlow && Node.atBlank(src, offset + 1)
return !inFlow && Node.atBlank(src, offset + 1, true)
? Type.MAP_VALUE
: Type.PLAIN
case '-':
return !inFlow && Node.atBlank(src, offset + 1)
return !inFlow && Node.atBlank(src, offset + 1, true)
? Type.SEQ_ITEM
: Type.PLAIN
case '"':
Expand Down Expand Up @@ -146,7 +146,8 @@ export default class ParseContext {
ch = src[offset]
}
// '- &a : b' has an anchor on an empty node
if (lineHasProps && ch === ':' && Node.atBlank(src, offset + 1)) offset -= 1
if (lineHasProps && ch === ':' && Node.atBlank(src, offset + 1, true))
offset -= 1
const type = ParseContext.parseType(src, offset, inFlow)
trace: 'props', type, { props, offset }
return { props, type, valueStart: offset }
Expand Down
4 changes: 2 additions & 2 deletions src/cst/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export default function parse(src) {
const context = new ParseContext({ src })
const documents = []
let offset = 0
while (offset < src.length) {
do {
const doc = new Document()
offset = doc.parse(context, offset)
documents.push(doc)
}
} while (offset < src.length)
documents.setOrigRanges = () => {
if (cr.length === 0) return false
for (let i = 1; i < cr.length; ++i) cr[i] -= i
Expand Down