/
stringify.js
88 lines (79 loc) · 2.66 KB
/
stringify.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { Alias } from '../ast/Alias.js'
import { Node } from '../ast/Node.js'
import { Pair } from '../ast/Pair.js'
import { Scalar } from '../ast/Scalar.js'
import { stringifyString } from './stringifyString.js'
import { stringifyTag } from './stringifyTag.js'
function getTagObject(tags, item) {
if (item instanceof Alias) return Alias
if (item.tag) {
const match = tags.filter(t => t.tag === item.tag)
if (match.length > 0)
return match.find(t => t.format === item.format) || match[0]
}
let tagObj, obj
if (item instanceof Scalar) {
obj = item.value
const match = tags.filter(t => t.identify && t.identify(obj))
tagObj =
match.find(t => t.format === item.format) || match.find(t => !t.format)
} else {
obj = item
tagObj = tags.find(t => t.nodeClass && obj instanceof t.nodeClass)
}
if (!tagObj) {
const name = obj && obj.constructor ? obj.constructor.name : typeof obj
throw new Error(`Tag not resolved for ${name} value`)
}
return tagObj
}
// needs to be called before value stringifier to allow for circular anchor refs
function stringifyProps(node, tagObj, { anchors, doc }) {
const props = []
const anchor = doc.anchors.getName(node)
if (anchor) {
anchors[anchor] = node
props.push(`&${anchor}`)
}
if (node.tag) {
props.push(stringifyTag(doc, node.tag))
} else if (!tagObj.default) {
props.push(stringifyTag(doc, tagObj.tag))
}
return props.join(' ')
}
export function stringify(item, ctx, onComment, onChompKeep) {
const { anchors, schema } = ctx.doc
let tagObj
if (!(item instanceof Node)) {
const createCtx = {
aliasNodes: [],
onTagObj: o => (tagObj = o),
prevObjects: new Map()
}
item = schema.createNode(item, true, null, createCtx)
for (const alias of createCtx.aliasNodes) {
alias.source = alias.source.node
let name = anchors.getName(alias.source)
if (!name) {
name = anchors.newName()
anchors.map[name] = alias.source
}
}
}
if (item instanceof Pair) return item.toString(ctx, onComment, onChompKeep)
if (!tagObj) tagObj = getTagObject(schema.tags, item)
const props = stringifyProps(item, tagObj, ctx)
if (props.length > 0)
ctx.indentAtStart = (ctx.indentAtStart || 0) + props.length + 1
const str =
typeof tagObj.stringify === 'function'
? tagObj.stringify(item, ctx, onComment, onChompKeep)
: item instanceof Scalar
? stringifyString(item, ctx, onComment, onChompKeep)
: item.toString(ctx, onComment, onChompKeep)
if (!props) return str
return item instanceof Scalar || str[0] === '{' || str[0] === '['
? `${props} ${str}`
: `${props}\n${ctx.indent}${str}`
}