123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import { anchorIsValid } from '../doc/anchors.js';
- import { isPair, isAlias, isNode, isScalar, isCollection } from '../nodes/identity.js';
- import { stringifyComment } from './stringifyComment.js';
- import { stringifyString } from './stringifyString.js';
- function createStringifyContext(doc, options) {
- const opt = Object.assign({
- blockQuote: true,
- commentString: stringifyComment,
- defaultKeyType: null,
- defaultStringType: 'PLAIN',
- directives: null,
- doubleQuotedAsJSON: false,
- doubleQuotedMinMultiLineLength: 40,
- falseStr: 'false',
- flowCollectionPadding: true,
- indentSeq: true,
- lineWidth: 80,
- minContentWidth: 20,
- nullStr: 'null',
- simpleKeys: false,
- singleQuote: null,
- trueStr: 'true',
- verifyAliasOrder: true
- }, doc.schema.toStringOptions, options);
- let inFlow;
- switch (opt.collectionStyle) {
- case 'block':
- inFlow = false;
- break;
- case 'flow':
- inFlow = true;
- break;
- default:
- inFlow = null;
- }
- return {
- anchors: new Set(),
- doc,
- flowCollectionPadding: opt.flowCollectionPadding ? ' ' : '',
- indent: '',
- indentStep: typeof opt.indent === 'number' ? ' '.repeat(opt.indent) : ' ',
- inFlow,
- options: opt
- };
- }
- function getTagObject(tags, item) {
- 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 = undefined;
- let obj;
- if (isScalar(item)) {
- obj = item.value;
- let match = tags.filter(t => t.identify?.(obj));
- if (match.length > 1) {
- const testMatch = match.filter(t => t.test);
- if (testMatch.length > 0)
- match = testMatch;
- }
- 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?.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 }) {
- if (!doc.directives)
- return '';
- const props = [];
- const anchor = (isScalar(node) || isCollection(node)) && node.anchor;
- if (anchor && anchorIsValid(anchor)) {
- anchors.add(anchor);
- props.push(`&${anchor}`);
- }
- const tag = node.tag ? node.tag : tagObj.default ? null : tagObj.tag;
- if (tag)
- props.push(doc.directives.tagString(tag));
- return props.join(' ');
- }
- function stringify(item, ctx, onComment, onChompKeep) {
- if (isPair(item))
- return item.toString(ctx, onComment, onChompKeep);
- if (isAlias(item)) {
- if (ctx.doc.directives)
- return item.toString(ctx);
- if (ctx.resolvedAliases?.has(item)) {
- throw new TypeError(`Cannot stringify circular structure without alias nodes`);
- }
- else {
- if (ctx.resolvedAliases)
- ctx.resolvedAliases.add(item);
- else
- ctx.resolvedAliases = new Set([item]);
- item = item.resolve(ctx.doc);
- }
- }
- let tagObj = undefined;
- const node = isNode(item)
- ? item
- : ctx.doc.createNode(item, { onTagObj: o => (tagObj = o) });
- if (!tagObj)
- tagObj = getTagObject(ctx.doc.schema.tags, node);
- const props = stringifyProps(node, tagObj, ctx);
- if (props.length > 0)
- ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
- const str = typeof tagObj.stringify === 'function'
- ? tagObj.stringify(node, ctx, onComment, onChompKeep)
- : isScalar(node)
- ? stringifyString(node, ctx, onComment, onChompKeep)
- : node.toString(ctx, onComment, onChompKeep);
- if (!props)
- return str;
- return isScalar(node) || str[0] === '{' || str[0] === '['
- ? `${props} ${str}`
- : `${props}\n${ctx.indent}${str}`;
- }
- export { createStringifyContext, stringify };
|