You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
5.2 KiB
151 lines
5.2 KiB
import { Collection } from '../nodes/Collection.js'; |
|
import { isNode, isPair } from '../nodes/Node.js'; |
|
import { stringify } from './stringify.js'; |
|
import { lineComment, indentComment } from './stringifyComment.js'; |
|
|
|
function stringifyCollection(collection, ctx, options) { |
|
const flow = ctx.inFlow ?? collection.flow; |
|
const stringify = flow ? stringifyFlowCollection : stringifyBlockCollection; |
|
return stringify(collection, ctx, options); |
|
} |
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) { |
|
const { indent, options: { commentString } } = ctx; |
|
const itemCtx = Object.assign({}, ctx, { indent: itemIndent, type: null }); |
|
let chompKeep = false; // flag for the preceding node's status |
|
const lines = []; |
|
for (let i = 0; i < items.length; ++i) { |
|
const item = items[i]; |
|
let comment = null; |
|
if (isNode(item)) { |
|
if (!chompKeep && item.spaceBefore) |
|
lines.push(''); |
|
addCommentBefore(ctx, lines, item.commentBefore, chompKeep); |
|
if (item.comment) |
|
comment = item.comment; |
|
} |
|
else if (isPair(item)) { |
|
const ik = isNode(item.key) ? item.key : null; |
|
if (ik) { |
|
if (!chompKeep && ik.spaceBefore) |
|
lines.push(''); |
|
addCommentBefore(ctx, lines, ik.commentBefore, chompKeep); |
|
} |
|
} |
|
chompKeep = false; |
|
let str = stringify(item, itemCtx, () => (comment = null), () => (chompKeep = true)); |
|
if (comment) |
|
str += lineComment(str, itemIndent, commentString(comment)); |
|
if (chompKeep && comment) |
|
chompKeep = false; |
|
lines.push(blockItemPrefix + str); |
|
} |
|
let str; |
|
if (lines.length === 0) { |
|
str = flowChars.start + flowChars.end; |
|
} |
|
else { |
|
str = lines[0]; |
|
for (let i = 1; i < lines.length; ++i) { |
|
const line = lines[i]; |
|
str += line ? `\n${indent}${line}` : '\n'; |
|
} |
|
} |
|
if (comment) { |
|
str += '\n' + indentComment(commentString(comment), indent); |
|
if (onComment) |
|
onComment(); |
|
} |
|
else if (chompKeep && onChompKeep) |
|
onChompKeep(); |
|
return str; |
|
} |
|
function stringifyFlowCollection({ comment, items }, ctx, { flowChars, itemIndent, onComment }) { |
|
const { indent, indentStep, options: { commentString } } = ctx; |
|
itemIndent += indentStep; |
|
const itemCtx = Object.assign({}, ctx, { |
|
indent: itemIndent, |
|
inFlow: true, |
|
type: null |
|
}); |
|
let reqNewline = false; |
|
let linesAtValue = 0; |
|
const lines = []; |
|
for (let i = 0; i < items.length; ++i) { |
|
const item = items[i]; |
|
let comment = null; |
|
if (isNode(item)) { |
|
if (item.spaceBefore) |
|
lines.push(''); |
|
addCommentBefore(ctx, lines, item.commentBefore, false); |
|
if (item.comment) |
|
comment = item.comment; |
|
} |
|
else if (isPair(item)) { |
|
const ik = isNode(item.key) ? item.key : null; |
|
if (ik) { |
|
if (ik.spaceBefore) |
|
lines.push(''); |
|
addCommentBefore(ctx, lines, ik.commentBefore, false); |
|
if (ik.comment) |
|
reqNewline = true; |
|
} |
|
const iv = isNode(item.value) ? item.value : null; |
|
if (iv) { |
|
if (iv.comment) |
|
comment = iv.comment; |
|
if (iv.commentBefore) |
|
reqNewline = true; |
|
} |
|
else if (item.value == null && ik && ik.comment) { |
|
comment = ik.comment; |
|
} |
|
} |
|
if (comment) |
|
reqNewline = true; |
|
let str = stringify(item, itemCtx, () => (comment = null)); |
|
if (i < items.length - 1) |
|
str += ','; |
|
if (comment) |
|
str += lineComment(str, itemIndent, commentString(comment)); |
|
if (!reqNewline && (lines.length > linesAtValue || str.includes('\n'))) |
|
reqNewline = true; |
|
lines.push(str); |
|
linesAtValue = lines.length; |
|
} |
|
let str; |
|
const { start, end } = flowChars; |
|
if (lines.length === 0) { |
|
str = start + end; |
|
} |
|
else { |
|
if (!reqNewline) { |
|
const len = lines.reduce((sum, line) => sum + line.length + 2, 2); |
|
reqNewline = len > Collection.maxFlowStringSingleLineLength; |
|
} |
|
if (reqNewline) { |
|
str = start; |
|
for (const line of lines) |
|
str += line ? `\n${indentStep}${indent}${line}` : '\n'; |
|
str += `\n${indent}${end}`; |
|
} |
|
else { |
|
str = `${start} ${lines.join(' ')} ${end}`; |
|
} |
|
} |
|
if (comment) { |
|
str += lineComment(str, commentString(comment), indent); |
|
if (onComment) |
|
onComment(); |
|
} |
|
return str; |
|
} |
|
function addCommentBefore({ indent, options: { commentString } }, lines, comment, chompKeep) { |
|
if (comment && chompKeep) |
|
comment = comment.replace(/^\n+/, ''); |
|
if (comment) { |
|
const ic = indentComment(commentString(comment), indent); |
|
lines.push(ic.trimStart()); // Avoid double indent on first line |
|
} |
|
} |
|
|
|
export { stringifyCollection };
|
|
|