Skip to content

Commit

Permalink
Add initial flow collection composition
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed Dec 5, 2020
1 parent b62055f commit 9c431c2
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 3 deletions.
151 changes: 151 additions & 0 deletions src/compose/compose-flow-collection.ts
@@ -0,0 +1,151 @@
import { Node, Pair, YAMLMap, YAMLSeq } from '../ast/index.js'
import type { Document } from '../doc/Document.js'
import type { FlowCollection, SourceToken } from '../parse/parser.js'
import { composeNode } from './compose-node.js'

export function composeFlowCollection(
doc: Document.Parsed,
fc: FlowCollection,
_anchor: string | null,
onError: (offset: number, message: string, warning?: boolean) => void
) {
let offset = fc.offset
const isMap = fc.start.source === '{'
const coll = isMap ? new YAMLMap(doc.schema) : new YAMLSeq(doc.schema)
if (_anchor) doc.anchors.setAnchor(coll, _anchor)

let key: Node | null = null
let value: Node | null = null

let spaceBefore = false
let comment = ''
let hasComment = false
let newlines = ''
let anchor = ''
let tagName = ''

// let atExplicitKey = false
let atValueEnd = false

function resetProps() {
spaceBefore = false
comment = ''
hasComment = false
newlines = ''
anchor = ''
tagName = ''
// atExplicitKey = false
atValueEnd = false
}

function addItem() {
if (value) {
if (hasComment) value.comment = comment
} else {
const props = { spaceBefore, comment, anchor, tagName }
value = composeNode(doc, offset, props, onError)
}
if (isMap) {
const pair = key ? new Pair(key, value) : new Pair(value)
coll.items.push(pair)
} else {
const seq = coll as YAMLSeq
if (key) {
const map = new YAMLMap(doc.schema)
map.items.push(new Pair(key, value))
seq.items.push(map)
} else seq.items.push(value)
}
resetProps()
}

for (const token of fc.items) {
let isSourceToken = true
switch (token.type) {
case 'space':
break
case 'comment':
const cb = token.source.substring(1)
if (!hasComment) {
if (newlines) spaceBefore = true
comment = cb
} else comment += newlines + cb
hasComment = true
newlines = ''
break
case 'newline':
if (atValueEnd) {
if (hasComment) {
let node = coll.items[coll.items.length - 1]
if (node instanceof Pair) node = node.value || node.key
if (node instanceof Node) node.comment = comment
else onError(offset, 'Error adding trailing comment to node')
comment = ''
hasComment = false
}
atValueEnd = false
} else newlines += token.source
break
case 'anchor':
if (anchor) onError(offset, 'A node can have at most one anchor')
anchor = token.source.substring(1)
break
case 'tag':
if (tagName) onError(offset, 'A node can have at most one tag')
tagName = token.source // FIXME
break
case 'explicit-key-ind':
// atExplicitKey = true
if (anchor || tagName)
onError(offset, 'Anchors and tags must be after the ? indicator')
break
case 'map-value-ind': {
if (key) {
if (value) {
onError(offset, 'Missing {} around pair used as mapping key')
const map = new YAMLMap(doc.schema)
map.items.push(new Pair(key, value))
key = map
value = null
} // else explicit key
} else if (value) {
key = value
value = null
} else {
const props = { spaceBefore, comment, anchor, tagName }
key = composeNode(doc, offset, props, onError) // empty node
resetProps()
}
if (hasComment) {
key.comment = comment
comment = ''
hasComment = false
}
break
}
case 'comma':
addItem()
atValueEnd = true
key = null
value = null
break
default: {
if (value) onError(offset, 'Missing , between flow collection items')
const props = { spaceBefore, comment, anchor, tagName }
value = composeNode(doc, token, props, onError)
if (value.range) offset = value.range[1]
else {
// FIXME: remove once verified never happens
onError(offset, 'Resolved child node has no range')
if ('offset' in token) offset = token.offset
if ('source' in token && token.source) offset += token.source.length
}
isSourceToken = false
}
}
if (isSourceToken) offset += (token as SourceToken).source.length
}
if (key || value) addItem()
coll.range = [fc.offset, offset]
return coll
}
4 changes: 4 additions & 0 deletions src/compose/compose-node.ts
Expand Up @@ -3,6 +3,7 @@ import type { Document } from '../doc/Document.js'
import type { FlowScalar, Token } from '../parse/parser.js'
import { composeBlockMap } from './compose-block-map.js'
import { composeBlockSeq } from './compose-block-seq.js'
import { composeFlowCollection } from './compose-flow-collection.js'
import { composeScalar } from './compose-scalar.js'
import { resolveEnd } from './resolve-end.js'

Expand Down Expand Up @@ -42,6 +43,9 @@ export function composeNode(
case 'block-seq':
node = composeBlockSeq(doc, token, anchor, onError)
break
case 'flow-collection':
node = composeFlowCollection(doc, token, anchor, onError)
break
default:
onError(
'offset' in token ? token.offset : -1,
Expand Down
6 changes: 3 additions & 3 deletions src/parse/parser.ts
Expand Up @@ -68,9 +68,9 @@ export interface FlowCollection {
type: 'flow-collection'
offset: number
indent: number
start: Token
items: Token[]
end?: Token
start: SourceToken
items: Array<Token>
end?: SourceToken
}

export type Token =
Expand Down

0 comments on commit 9c431c2

Please sign in to comment.