Comparing version 2.0.0-5 to 2.0.0-6
@@ -15,4 +15,4 @@ import { Document } from '../doc/Document.js'; | ||
const props = resolveProps(start, { | ||
ctx, | ||
indicator: 'doc-start', | ||
next: value || (end === null || end === void 0 ? void 0 : end[0]), | ||
offset, | ||
@@ -19,0 +19,0 @@ onError, |
@@ -27,3 +27,3 @@ import { Directives } from '../doc/directives.js'; | ||
(comment === '' ? '' : afterEmptyLine ? '\n\n' : '\n') + | ||
source.substring(1); | ||
(source.substring(1) || ' '); | ||
atComment = true; | ||
@@ -30,0 +30,0 @@ afterEmptyLine = false; |
@@ -5,2 +5,3 @@ import { Pair } from '../nodes/Pair.js'; | ||
import { containsNewline } from './util-contains-newline.js'; | ||
import { mapIncludes } from './util-map-includes.js'; | ||
@@ -15,4 +16,4 @@ const startColMsg = 'All mapping items must start at the same column'; | ||
const keyProps = resolveProps(start, { | ||
ctx, | ||
indicator: 'explicit-key-ind', | ||
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]), | ||
offset, | ||
@@ -51,6 +52,8 @@ onError, | ||
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError); | ||
if (mapIncludes(ctx, map.items, keyNode)) | ||
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique'); | ||
// value properties | ||
const valueProps = resolveProps(sep || [], { | ||
ctx, | ||
indicator: 'map-value-ind', | ||
next: value, | ||
offset: keyNode.range[2], | ||
@@ -57,0 +60,0 @@ onError, |
@@ -152,3 +152,3 @@ import { Scalar } from '../nodes/Scalar.js'; | ||
const message = 'Comments must be separated from other tokens by white space characters'; | ||
onError(token, 'COMMENT_SPACE', message); | ||
onError(token, 'MISSING_CHAR', message); | ||
} | ||
@@ -155,0 +155,0 @@ length += token.source.length; |
@@ -9,4 +9,4 @@ import { YAMLSeq } from '../nodes/YAMLSeq.js'; | ||
const props = resolveProps(start, { | ||
ctx, | ||
indicator: 'seq-item-ind', | ||
next: value, | ||
offset, | ||
@@ -13,0 +13,0 @@ onError, |
@@ -14,4 +14,4 @@ function resolveEnd(end, offset, reqSpace, onError) { | ||
if (reqSpace && !hasSpace) | ||
onError(token, 'COMMENT_SPACE', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = source.substring(1); | ||
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = source.substring(1) || ' '; | ||
if (!comment) | ||
@@ -18,0 +18,0 @@ comment = cb; |
@@ -8,2 +8,3 @@ import { isPair } from '../nodes/Node.js'; | ||
import { containsNewline } from './util-contains-newline.js'; | ||
import { mapIncludes } from './util-map-includes.js'; | ||
@@ -23,5 +24,5 @@ const blockMsg = 'Block collections are not allowed within flow collections'; | ||
const props = resolveProps(start, { | ||
ctx, | ||
flow: fcName, | ||
indicator: 'explicit-key-ind', | ||
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]), | ||
offset, | ||
@@ -104,5 +105,5 @@ onError, | ||
const valueProps = resolveProps(sep || [], { | ||
ctx, | ||
flow: fcName, | ||
indicator: 'map-value-ind', | ||
next: value, | ||
offset: keyNode.range[2], | ||
@@ -150,4 +151,8 @@ onError, | ||
const pair = new Pair(keyNode, valueNode); | ||
if (isMap) | ||
coll.items.push(pair); | ||
if (isMap) { | ||
const map = coll; | ||
if (mapIncludes(ctx, map.items, keyNode)) | ||
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique'); | ||
map.items.push(pair); | ||
} | ||
else { | ||
@@ -166,3 +171,3 @@ const map = new YAMLMap(ctx.schema); | ||
if (ce && ce.source === expectedEnd) | ||
cePos += ce.source.length; | ||
cePos = ce.offset + ce.source.length; | ||
else { | ||
@@ -169,0 +174,0 @@ onError(offset + 1, 'MISSING_CHAR', `Expected ${fcName} to end with ${expectedEnd}`); |
@@ -1,2 +0,2 @@ | ||
function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNewline }) { | ||
function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnNewline }) { | ||
let spaceBefore = false; | ||
@@ -8,2 +8,3 @@ let atNewline = startOnNewline; | ||
let hasNewline = false; | ||
let reqSpace = false; | ||
let anchor = null; | ||
@@ -15,2 +16,9 @@ let tag = null; | ||
for (const token of tokens) { | ||
if (reqSpace) { | ||
if (token.type !== 'space' && | ||
token.type !== 'newline' && | ||
token.type !== 'comma') | ||
onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space'); | ||
reqSpace = false; | ||
} | ||
switch (token.type) { | ||
@@ -29,5 +37,5 @@ case 'space': | ||
case 'comment': { | ||
if (ctx.options.strict && !hasSpace) | ||
onError(token, 'COMMENT_SPACE', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = token.source.substring(1); | ||
if (!hasSpace) | ||
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = token.source.substring(1) || ' '; | ||
if (!comment) | ||
@@ -38,11 +46,17 @@ comment = cb; | ||
commentSep = ''; | ||
atNewline = false; | ||
break; | ||
} | ||
case 'newline': | ||
if (atNewline && !comment) | ||
spaceBefore = true; | ||
if (atNewline) { | ||
if (comment) | ||
comment += token.source; | ||
else | ||
spaceBefore = true; | ||
} | ||
else | ||
commentSep += token.source; | ||
atNewline = true; | ||
hasNewline = true; | ||
hasSpace = true; | ||
commentSep += token.source; | ||
break; | ||
@@ -57,2 +71,3 @@ case 'anchor': | ||
hasSpace = false; | ||
reqSpace = true; | ||
break; | ||
@@ -67,2 +82,3 @@ case 'tag': { | ||
hasSpace = false; | ||
reqSpace = true; | ||
break; | ||
@@ -96,2 +112,9 @@ } | ||
const end = last ? last.offset + last.source.length : offset; | ||
if (reqSpace && | ||
next && | ||
next.type !== 'space' && | ||
next.type !== 'newline' && | ||
next.type !== 'comma' && | ||
(next.type !== 'scalar' || next.source !== '')) | ||
onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space'); | ||
return { | ||
@@ -98,0 +121,0 @@ comma, |
@@ -13,2 +13,3 @@ /** | ||
strict: true, | ||
uniqueKeys: true, | ||
version: '1.2' | ||
@@ -15,0 +16,0 @@ }; |
@@ -23,34 +23,2 @@ import { tokenType } from './cst.js'; | ||
} | ||
function atFirstEmptyLineAfterComments(start) { | ||
let hasComment = false; | ||
for (let i = 0; i < start.length; ++i) { | ||
switch (start[i].type) { | ||
case 'space': | ||
break; | ||
case 'comment': | ||
hasComment = true; | ||
break; | ||
case 'newline': | ||
if (!hasComment) | ||
return false; | ||
break; | ||
default: | ||
return false; | ||
} | ||
} | ||
if (hasComment) { | ||
for (let i = start.length - 1; i >= 0; --i) { | ||
switch (start[i].type) { | ||
/* istanbul ignore next */ | ||
case 'space': | ||
break; | ||
case 'newline': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function isFlowToken(token) { | ||
@@ -506,12 +474,15 @@ switch (token === null || token === void 0 ? void 0 : token.type) { | ||
this.onKeyLine = false; | ||
if (!it.sep && atFirstEmptyLineAfterComments(it.start)) { | ||
const prev = map.items[map.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
it.start = [this.sourceToken]; | ||
return; | ||
} | ||
if (it.value) { | ||
const end = 'end' in it.value ? it.value.end : undefined; | ||
const last = Array.isArray(end) ? end[end.length - 1] : undefined; | ||
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment') | ||
end === null || end === void 0 ? void 0 : end.push(this.sourceToken); | ||
else | ||
map.items.push({ start: [this.sourceToken] }); | ||
} | ||
// fallthrough | ||
else if (it.sep) | ||
it.sep.push(this.sourceToken); | ||
else | ||
it.start.push(this.sourceToken); | ||
return; | ||
case 'space': | ||
@@ -523,4 +494,15 @@ case 'comment': | ||
it.sep.push(this.sourceToken); | ||
else | ||
else { | ||
if (this.atIndentedComment(it.start, map.indent)) { | ||
const prev = map.items[map.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
end.push(this.sourceToken); | ||
map.items.pop(); | ||
return; | ||
} | ||
} | ||
it.start.push(this.sourceToken); | ||
} | ||
return; | ||
@@ -630,12 +612,13 @@ } | ||
case 'newline': | ||
if (!it.value && atFirstEmptyLineAfterComments(it.start)) { | ||
const prev = seq.items[seq.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
it.start = [this.sourceToken]; | ||
return; | ||
} | ||
if (it.value) { | ||
const end = 'end' in it.value ? it.value.end : undefined; | ||
const last = Array.isArray(end) ? end[end.length - 1] : undefined; | ||
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment') | ||
end === null || end === void 0 ? void 0 : end.push(this.sourceToken); | ||
else | ||
seq.items.push({ start: [this.sourceToken] }); | ||
} | ||
// fallthrough | ||
else | ||
it.start.push(this.sourceToken); | ||
return; | ||
case 'space': | ||
@@ -645,4 +628,15 @@ case 'comment': | ||
seq.items.push({ start: [this.sourceToken] }); | ||
else | ||
else { | ||
if (this.atIndentedComment(it.start, seq.indent)) { | ||
const prev = seq.items[seq.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
end.push(this.sourceToken); | ||
seq.items.pop(); | ||
return; | ||
} | ||
} | ||
it.start.push(this.sourceToken); | ||
} | ||
return; | ||
@@ -842,2 +836,9 @@ case 'anchor': | ||
} | ||
atIndentedComment(start, indent) { | ||
if (this.type !== 'comment') | ||
return false; | ||
if (this.indent <= indent) | ||
return false; | ||
return start.every(st => st.type === 'newline' || st.type === 'space'); | ||
} | ||
*documentEnd(docEnd) { | ||
@@ -844,0 +845,0 @@ if (this.type !== 'doc-mode') { |
import { Collection } from '../nodes/Collection.js'; | ||
import { addComment } from './addComment.js'; | ||
import { isNode, isPair } from '../nodes/Node.js'; | ||
import { stringify } from './stringify.js'; | ||
import { isNode, isPair } from '../nodes/Node.js'; | ||
import { addComment, stringifyComment } from './stringifyComment.js'; | ||
@@ -19,6 +19,13 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowChars, itemIndent, onChompKeep, onComment }) { | ||
nodes.push({ comment: true, str: '' }); | ||
if (item.commentBefore) { | ||
let cb = item.commentBefore; | ||
if (cb && chompKeep) | ||
cb = cb.replace(/^\n+/, ''); | ||
if (cb) { | ||
if (/^\n+$/.test(cb)) | ||
cb = cb.substring(1); | ||
// This match will always succeed on a non-empty string | ||
for (const line of item.commentBefore.match(/^.*$/gm)) | ||
nodes.push({ comment: true, str: `#${line}` }); | ||
for (const line of cb.match(/^.*$/gm)) { | ||
const str = line === ' ' ? '#' : line ? `#${line}` : ''; | ||
nodes.push({ comment: true, str }); | ||
} | ||
} | ||
@@ -35,6 +42,13 @@ if (item.comment) { | ||
nodes.push({ comment: true, str: '' }); | ||
if (ik.commentBefore) { | ||
let cb = ik.commentBefore; | ||
if (cb && chompKeep) | ||
cb = cb.replace(/^\n+/, ''); | ||
if (cb) { | ||
if (/^\n+$/.test(cb)) | ||
cb = cb.substring(1); | ||
// This match will always succeed on a non-empty string | ||
for (const line of ik.commentBefore.match(/^.*$/gm)) | ||
nodes.push({ comment: true, str: `#${line}` }); | ||
for (const line of cb.match(/^.*$/gm)) { | ||
const str = line === ' ' ? '#' : line ? `#${line}` : ''; | ||
nodes.push({ comment: true, str }); | ||
} | ||
} | ||
@@ -101,3 +115,3 @@ if (ik.comment) | ||
if (comment) { | ||
str += '\n' + comment.replace(/^/gm, `${indent}#`); | ||
str += '\n' + stringifyComment(comment, indent); | ||
if (onComment) | ||
@@ -104,0 +118,0 @@ onComment(); |
import { isNode } from '../nodes/Node.js'; | ||
import { addComment } from './addComment.js'; | ||
import { createStringifyContext, stringify } from './stringify.js'; | ||
import { stringifyComment, addComment } from './stringifyComment.js'; | ||
@@ -22,3 +22,3 @@ function stringifyDocument(doc, options) { | ||
lines.unshift(''); | ||
lines.unshift(doc.commentBefore.replace(/^/gm, '#')); | ||
lines.unshift(stringifyComment(doc.commentBefore, '')); | ||
} | ||
@@ -33,3 +33,3 @@ const ctx = createStringifyContext(doc, options); | ||
if (doc.contents.commentBefore) | ||
lines.push(doc.contents.commentBefore.replace(/^/gm, '#')); | ||
lines.push(stringifyComment(doc.contents.commentBefore, '')); | ||
// top-level block scalars need to be indented if followed by a comment | ||
@@ -55,6 +55,9 @@ ctx.forceBlockIndent = !!doc.comment; | ||
} | ||
if (doc.comment) { | ||
let dc = doc.comment; | ||
if (dc && chompKeep) | ||
dc = dc.replace(/^\n+/, ''); | ||
if (dc) { | ||
if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '') | ||
lines.push(''); | ||
lines.push(doc.comment.replace(/^/gm, '#')); | ||
lines.push(stringifyComment(dc, '')); | ||
} | ||
@@ -61,0 +64,0 @@ return lines.join('\n') + '\n'; |
import { isCollection, isNode, isScalar, isSeq } from '../nodes/Node.js'; | ||
import { Scalar } from '../nodes/Scalar.js'; | ||
import { addComment } from './addComment.js'; | ||
import { stringify } from './stringify.js'; | ||
import { addComment, stringifyComment } from './stringifyComment.js'; | ||
@@ -62,6 +62,4 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) { | ||
vcb = '\n'; | ||
if (value.commentBefore) { | ||
const cs = value.commentBefore.replace(/^/gm, `${ctx.indent}#`); | ||
vcb += `\n${cs}`; | ||
} | ||
if (value.commentBefore) | ||
vcb += `\n${stringifyComment(value.commentBefore, ctx.indent)}`; | ||
valueComment = value.comment; | ||
@@ -68,0 +66,0 @@ } |
@@ -17,4 +17,4 @@ 'use strict'; | ||
const props = resolveProps.resolveProps(start, { | ||
ctx, | ||
indicator: 'doc-start', | ||
next: value || (end === null || end === void 0 ? void 0 : end[0]), | ||
offset, | ||
@@ -21,0 +21,0 @@ onError, |
@@ -29,3 +29,3 @@ 'use strict'; | ||
(comment === '' ? '' : afterEmptyLine ? '\n\n' : '\n') + | ||
source.substring(1); | ||
(source.substring(1) || ' '); | ||
atComment = true; | ||
@@ -32,0 +32,0 @@ afterEmptyLine = false; |
@@ -0,1 +1,2 @@ | ||
import type { ParsedNode } from '../nodes/Node.js'; | ||
import { YAMLMap } from '../nodes/YAMLMap.js'; | ||
@@ -5,2 +6,2 @@ import type { BlockMap } from '../parse/cst.js'; | ||
import type { ComposeErrorHandler } from './composer.js'; | ||
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<import("../index.js").ParsedNode, import("../index.js").ParsedNode | null>; | ||
export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<ParsedNode, ParsedNode | null>; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var utilContainsNewline = require('./util-contains-newline.js'); | ||
var utilMapIncludes = require('./util-map-includes.js'); | ||
@@ -17,4 +18,4 @@ const startColMsg = 'All mapping items must start at the same column'; | ||
const keyProps = resolveProps.resolveProps(start, { | ||
ctx, | ||
indicator: 'explicit-key-ind', | ||
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]), | ||
offset, | ||
@@ -53,6 +54,8 @@ onError, | ||
: composeEmptyNode(ctx, keyStart, start, null, keyProps, onError); | ||
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode)) | ||
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique'); | ||
// value properties | ||
const valueProps = resolveProps.resolveProps(sep || [], { | ||
ctx, | ||
indicator: 'map-value-ind', | ||
next: value, | ||
offset: keyNode.range[2], | ||
@@ -59,0 +62,0 @@ onError, |
@@ -154,3 +154,3 @@ 'use strict'; | ||
const message = 'Comments must be separated from other tokens by white space characters'; | ||
onError(token, 'COMMENT_SPACE', message); | ||
onError(token, 'MISSING_CHAR', message); | ||
} | ||
@@ -157,0 +157,0 @@ length += token.source.length; |
@@ -11,4 +11,4 @@ 'use strict'; | ||
const props = resolveProps.resolveProps(start, { | ||
ctx, | ||
indicator: 'seq-item-ind', | ||
next: value, | ||
offset, | ||
@@ -15,0 +15,0 @@ onError, |
@@ -16,4 +16,4 @@ 'use strict'; | ||
if (reqSpace && !hasSpace) | ||
onError(token, 'COMMENT_SPACE', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = source.substring(1); | ||
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = source.substring(1) || ' '; | ||
if (!comment) | ||
@@ -20,0 +20,0 @@ comment = cb; |
@@ -10,2 +10,3 @@ 'use strict'; | ||
var utilContainsNewline = require('./util-contains-newline.js'); | ||
var utilMapIncludes = require('./util-map-includes.js'); | ||
@@ -25,5 +26,5 @@ const blockMsg = 'Block collections are not allowed within flow collections'; | ||
const props = resolveProps.resolveProps(start, { | ||
ctx, | ||
flow: fcName, | ||
indicator: 'explicit-key-ind', | ||
next: key || (sep === null || sep === void 0 ? void 0 : sep[0]), | ||
offset, | ||
@@ -106,5 +107,5 @@ onError, | ||
const valueProps = resolveProps.resolveProps(sep || [], { | ||
ctx, | ||
flow: fcName, | ||
indicator: 'map-value-ind', | ||
next: value, | ||
offset: keyNode.range[2], | ||
@@ -152,4 +153,8 @@ onError, | ||
const pair = new Pair.Pair(keyNode, valueNode); | ||
if (isMap) | ||
coll.items.push(pair); | ||
if (isMap) { | ||
const map = coll; | ||
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode)) | ||
onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique'); | ||
map.items.push(pair); | ||
} | ||
else { | ||
@@ -168,3 +173,3 @@ const map = new YAMLMap.YAMLMap(ctx.schema); | ||
if (ce && ce.source === expectedEnd) | ||
cePos += ce.source.length; | ||
cePos = ce.offset + ce.source.length; | ||
else { | ||
@@ -171,0 +176,0 @@ onError(offset + 1, 'MISSING_CHAR', `Expected ${fcName} to end with ${expectedEnd}`); |
@@ -1,8 +0,7 @@ | ||
import type { SourceToken } from '../parse/cst.js'; | ||
import type { ComposeContext } from './compose-node.js'; | ||
import type { SourceToken, Token } from '../parse/cst.js'; | ||
import type { ComposeErrorHandler } from './composer.js'; | ||
export interface ResolvePropsArg { | ||
ctx: ComposeContext; | ||
flow?: string; | ||
indicator: 'doc-start' | 'explicit-key-ind' | 'map-value-ind' | 'seq-item-ind'; | ||
next: Token | null | undefined; | ||
offset: number; | ||
@@ -12,3 +11,3 @@ onError: ComposeErrorHandler; | ||
} | ||
export declare function resolveProps(tokens: SourceToken[], { ctx, flow, indicator, offset, onError, startOnNewline }: ResolvePropsArg): { | ||
export declare function resolveProps(tokens: SourceToken[], { flow, indicator, next, offset, onError, startOnNewline }: ResolvePropsArg): { | ||
comma: SourceToken | null; | ||
@@ -15,0 +14,0 @@ found: SourceToken | null; |
'use strict'; | ||
function resolveProps(tokens, { ctx, flow, indicator, offset, onError, startOnNewline }) { | ||
function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnNewline }) { | ||
let spaceBefore = false; | ||
@@ -10,2 +10,3 @@ let atNewline = startOnNewline; | ||
let hasNewline = false; | ||
let reqSpace = false; | ||
let anchor = null; | ||
@@ -17,2 +18,9 @@ let tag = null; | ||
for (const token of tokens) { | ||
if (reqSpace) { | ||
if (token.type !== 'space' && | ||
token.type !== 'newline' && | ||
token.type !== 'comma') | ||
onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space'); | ||
reqSpace = false; | ||
} | ||
switch (token.type) { | ||
@@ -31,5 +39,5 @@ case 'space': | ||
case 'comment': { | ||
if (ctx.options.strict && !hasSpace) | ||
onError(token, 'COMMENT_SPACE', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = token.source.substring(1); | ||
if (!hasSpace) | ||
onError(token, 'MISSING_CHAR', 'Comments must be separated from other tokens by white space characters'); | ||
const cb = token.source.substring(1) || ' '; | ||
if (!comment) | ||
@@ -40,11 +48,17 @@ comment = cb; | ||
commentSep = ''; | ||
atNewline = false; | ||
break; | ||
} | ||
case 'newline': | ||
if (atNewline && !comment) | ||
spaceBefore = true; | ||
if (atNewline) { | ||
if (comment) | ||
comment += token.source; | ||
else | ||
spaceBefore = true; | ||
} | ||
else | ||
commentSep += token.source; | ||
atNewline = true; | ||
hasNewline = true; | ||
hasSpace = true; | ||
commentSep += token.source; | ||
break; | ||
@@ -59,2 +73,3 @@ case 'anchor': | ||
hasSpace = false; | ||
reqSpace = true; | ||
break; | ||
@@ -69,2 +84,3 @@ case 'tag': { | ||
hasSpace = false; | ||
reqSpace = true; | ||
break; | ||
@@ -98,2 +114,9 @@ } | ||
const end = last ? last.offset + last.source.length : offset; | ||
if (reqSpace && | ||
next && | ||
next.type !== 'space' && | ||
next.type !== 'newline' && | ||
next.type !== 'comma' && | ||
(next.type !== 'scalar' || next.source !== '')) | ||
onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space'); | ||
return { | ||
@@ -100,0 +123,0 @@ comma, |
@@ -30,4 +30,6 @@ import type { YAMLError, YAMLWarning } from '../errors.js'; | ||
/** | ||
* The [start, value-end, node-end] character offsets for the part of the | ||
* source parsed into this document (undefined if not parsed). | ||
* The `[start, value-end, node-end]` character offsets for the part of the | ||
* source parsed into this document (undefined if not parsed). The `value-end` | ||
* and `node-end` positions are themselves not included in their respective | ||
* ranges. | ||
*/ | ||
@@ -34,0 +36,0 @@ range?: Range; |
import type { LineCounter } from './parse/line-counter'; | ||
export declare type ErrorCode = 'ALIAS_PROPS' | 'BAD_DIRECTIVE' | 'BAD_DQ_ESCAPE' | 'BAD_INDENT' | 'BAD_PROP_ORDER' | 'BAD_SCALAR_START' | 'BLOCK_AS_IMPLICIT_KEY' | 'BLOCK_IN_FLOW' | 'COMMENT_SPACE' | 'IMPOSSIBLE' | 'KEY_OVER_1024_CHARS' | 'MISSING_ANCHOR' | 'MISSING_CHAR' | 'MULTILINE_IMPLICIT_KEY' | 'MULTIPLE_ANCHORS' | 'MULTIPLE_DOCS' | 'MULTIPLE_TAGS' | 'TAB_AS_INDENT' | 'TAG_RESOLVE_FAILED' | 'UNEXPECTED_TOKEN'; | ||
export declare type ErrorCode = 'ALIAS_PROPS' | 'BAD_DIRECTIVE' | 'BAD_DQ_ESCAPE' | 'BAD_INDENT' | 'BAD_PROP_ORDER' | 'BAD_SCALAR_START' | 'BLOCK_AS_IMPLICIT_KEY' | 'BLOCK_IN_FLOW' | 'DUPLICATE_KEY' | 'IMPOSSIBLE' | 'KEY_OVER_1024_CHARS' | 'MISSING_ANCHOR' | 'MISSING_CHAR' | 'MULTILINE_IMPLICIT_KEY' | 'MULTIPLE_ANCHORS' | 'MULTIPLE_DOCS' | 'MULTIPLE_TAGS' | 'TAB_AS_INDENT' | 'TAG_RESOLVE_FAILED' | 'UNEXPECTED_TOKEN'; | ||
export declare type LinePos = { | ||
@@ -4,0 +4,0 @@ line: number; |
@@ -34,4 +34,6 @@ import type { Document } from '../doc/Document.js'; | ||
/** | ||
* The [start, value-end, node-end] character offsets for the part of the | ||
* source parsed into this node (undefined if not parsed). | ||
* The `[start, value-end, node-end]` character offsets for the part of the | ||
* source parsed into this node (undefined if not parsed). The `value-end` | ||
* and `node-end` positions are themselves not included in their respective | ||
* ranges. | ||
*/ | ||
@@ -38,0 +40,0 @@ range?: Range | null; |
import type { Reviver } from './doc/applyReviver.js'; | ||
import type { Directives } from './doc/directives.js'; | ||
import type { LogLevelId } from './log.js'; | ||
import type { ParsedNode } from './nodes/Node.js'; | ||
import type { Pair } from './nodes/Pair.js'; | ||
@@ -37,2 +38,15 @@ import type { Scalar } from './nodes/Scalar.js'; | ||
strict?: boolean; | ||
/** | ||
* YAML requires map keys to be unique. By default, this is checked by | ||
* comparing scalar values with `===`; deep equality is not checked for | ||
* aliases or collections. If merge keys are enabled by the schema, | ||
* multiple `<<` keys are allowed. | ||
* | ||
* Set `false` to disable, or provide your own comparator function to | ||
* customise. The comparator will be passed two `ParsedNode` values, and | ||
* is expected to return a `boolean` indicating their equality. | ||
* | ||
* Default: `true` | ||
*/ | ||
uniqueKeys?: boolean | ((a: ParsedNode, b: ParsedNode) => boolean); | ||
}; | ||
@@ -88,2 +102,3 @@ export declare type DocumentOptions = { | ||
* If `true`, sort by comparing key values with `<`. | ||
* Does not affect item order when parsing. | ||
* | ||
@@ -90,0 +105,0 @@ * Default: `false` |
@@ -15,2 +15,3 @@ 'use strict'; | ||
strict: true, | ||
uniqueKeys: true, | ||
version: '1.2' | ||
@@ -17,0 +18,0 @@ }; |
@@ -81,4 +81,5 @@ import { Token } from './cst.js'; | ||
private startBlockValue; | ||
private atIndentedComment; | ||
private documentEnd; | ||
private lineEnd; | ||
} |
@@ -25,34 +25,2 @@ 'use strict'; | ||
} | ||
function atFirstEmptyLineAfterComments(start) { | ||
let hasComment = false; | ||
for (let i = 0; i < start.length; ++i) { | ||
switch (start[i].type) { | ||
case 'space': | ||
break; | ||
case 'comment': | ||
hasComment = true; | ||
break; | ||
case 'newline': | ||
if (!hasComment) | ||
return false; | ||
break; | ||
default: | ||
return false; | ||
} | ||
} | ||
if (hasComment) { | ||
for (let i = start.length - 1; i >= 0; --i) { | ||
switch (start[i].type) { | ||
/* istanbul ignore next */ | ||
case 'space': | ||
break; | ||
case 'newline': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function isFlowToken(token) { | ||
@@ -510,12 +478,15 @@ switch (token === null || token === void 0 ? void 0 : token.type) { | ||
this.onKeyLine = false; | ||
if (!it.sep && atFirstEmptyLineAfterComments(it.start)) { | ||
const prev = map.items[map.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
it.start = [this.sourceToken]; | ||
return; | ||
} | ||
if (it.value) { | ||
const end = 'end' in it.value ? it.value.end : undefined; | ||
const last = Array.isArray(end) ? end[end.length - 1] : undefined; | ||
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment') | ||
end === null || end === void 0 ? void 0 : end.push(this.sourceToken); | ||
else | ||
map.items.push({ start: [this.sourceToken] }); | ||
} | ||
// fallthrough | ||
else if (it.sep) | ||
it.sep.push(this.sourceToken); | ||
else | ||
it.start.push(this.sourceToken); | ||
return; | ||
case 'space': | ||
@@ -527,4 +498,15 @@ case 'comment': | ||
it.sep.push(this.sourceToken); | ||
else | ||
else { | ||
if (this.atIndentedComment(it.start, map.indent)) { | ||
const prev = map.items[map.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
end.push(this.sourceToken); | ||
map.items.pop(); | ||
return; | ||
} | ||
} | ||
it.start.push(this.sourceToken); | ||
} | ||
return; | ||
@@ -634,12 +616,13 @@ } | ||
case 'newline': | ||
if (!it.value && atFirstEmptyLineAfterComments(it.start)) { | ||
const prev = seq.items[seq.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
it.start = [this.sourceToken]; | ||
return; | ||
} | ||
if (it.value) { | ||
const end = 'end' in it.value ? it.value.end : undefined; | ||
const last = Array.isArray(end) ? end[end.length - 1] : undefined; | ||
if ((last === null || last === void 0 ? void 0 : last.type) === 'comment') | ||
end === null || end === void 0 ? void 0 : end.push(this.sourceToken); | ||
else | ||
seq.items.push({ start: [this.sourceToken] }); | ||
} | ||
// fallthrough | ||
else | ||
it.start.push(this.sourceToken); | ||
return; | ||
case 'space': | ||
@@ -649,4 +632,15 @@ case 'comment': | ||
seq.items.push({ start: [this.sourceToken] }); | ||
else | ||
else { | ||
if (this.atIndentedComment(it.start, seq.indent)) { | ||
const prev = seq.items[seq.items.length - 2]; | ||
const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end; | ||
if (Array.isArray(end)) { | ||
Array.prototype.push.apply(end, it.start); | ||
end.push(this.sourceToken); | ||
seq.items.pop(); | ||
return; | ||
} | ||
} | ||
it.start.push(this.sourceToken); | ||
} | ||
return; | ||
@@ -846,2 +840,9 @@ case 'anchor': | ||
} | ||
atIndentedComment(start, indent) { | ||
if (this.type !== 'comment') | ||
return false; | ||
if (this.indent <= indent) | ||
return false; | ||
return start.every(st => st.type === 'newline' || st.type === 'space'); | ||
} | ||
*documentEnd(docEnd) { | ||
@@ -848,0 +849,0 @@ if (this.type !== 'doc-mode') { |
import { Collection } from '../nodes/Collection.js'; | ||
import { StringifyContext } from '../stringify/stringify.js'; | ||
import { StringifyContext } from './stringify.js'; | ||
declare type StringifyNode = { | ||
@@ -4,0 +4,0 @@ comment: boolean; |
'use strict'; | ||
var Collection = require('../nodes/Collection.js'); | ||
var addComment = require('./addComment.js'); | ||
var Node = require('../nodes/Node.js'); | ||
var stringify = require('./stringify.js'); | ||
var Node = require('../nodes/Node.js'); | ||
var stringifyComment = require('./stringifyComment.js'); | ||
@@ -21,6 +21,13 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowChars, itemIndent, onChompKeep, onComment }) { | ||
nodes.push({ comment: true, str: '' }); | ||
if (item.commentBefore) { | ||
let cb = item.commentBefore; | ||
if (cb && chompKeep) | ||
cb = cb.replace(/^\n+/, ''); | ||
if (cb) { | ||
if (/^\n+$/.test(cb)) | ||
cb = cb.substring(1); | ||
// This match will always succeed on a non-empty string | ||
for (const line of item.commentBefore.match(/^.*$/gm)) | ||
nodes.push({ comment: true, str: `#${line}` }); | ||
for (const line of cb.match(/^.*$/gm)) { | ||
const str = line === ' ' ? '#' : line ? `#${line}` : ''; | ||
nodes.push({ comment: true, str }); | ||
} | ||
} | ||
@@ -37,6 +44,13 @@ if (item.comment) { | ||
nodes.push({ comment: true, str: '' }); | ||
if (ik.commentBefore) { | ||
let cb = ik.commentBefore; | ||
if (cb && chompKeep) | ||
cb = cb.replace(/^\n+/, ''); | ||
if (cb) { | ||
if (/^\n+$/.test(cb)) | ||
cb = cb.substring(1); | ||
// This match will always succeed on a non-empty string | ||
for (const line of ik.commentBefore.match(/^.*$/gm)) | ||
nodes.push({ comment: true, str: `#${line}` }); | ||
for (const line of cb.match(/^.*$/gm)) { | ||
const str = line === ' ' ? '#' : line ? `#${line}` : ''; | ||
nodes.push({ comment: true, str }); | ||
} | ||
} | ||
@@ -63,3 +77,3 @@ if (ik.comment) | ||
str += ','; | ||
str = addComment.addComment(str, itemIndent, comment); | ||
str = stringifyComment.addComment(str, itemIndent, comment); | ||
if (chompKeep && (comment || inFlow)) | ||
@@ -104,3 +118,3 @@ chompKeep = false; | ||
if (comment) { | ||
str += '\n' + comment.replace(/^/gm, `${indent}#`); | ||
str += '\n' + stringifyComment.stringifyComment(comment, indent); | ||
if (onComment) | ||
@@ -107,0 +121,0 @@ onComment(); |
'use strict'; | ||
var Node = require('../nodes/Node.js'); | ||
var addComment = require('./addComment.js'); | ||
var stringify = require('./stringify.js'); | ||
var stringifyComment = require('./stringifyComment.js'); | ||
@@ -24,3 +24,3 @@ function stringifyDocument(doc, options) { | ||
lines.unshift(''); | ||
lines.unshift(doc.commentBefore.replace(/^/gm, '#')); | ||
lines.unshift(stringifyComment.stringifyComment(doc.commentBefore, '')); | ||
} | ||
@@ -35,3 +35,3 @@ const ctx = stringify.createStringifyContext(doc, options); | ||
if (doc.contents.commentBefore) | ||
lines.push(doc.contents.commentBefore.replace(/^/gm, '#')); | ||
lines.push(stringifyComment.stringifyComment(doc.contents.commentBefore, '')); | ||
// top-level block scalars need to be indented if followed by a comment | ||
@@ -44,3 +44,3 @@ ctx.forceBlockIndent = !!doc.comment; | ||
if (contentComment) | ||
body = addComment.addComment(body, '', contentComment); | ||
body = stringifyComment.addComment(body, '', contentComment); | ||
if ((body[0] === '|' || body[0] === '>') && | ||
@@ -58,6 +58,9 @@ lines[lines.length - 1] === '---') { | ||
} | ||
if (doc.comment) { | ||
let dc = doc.comment; | ||
if (dc && chompKeep) | ||
dc = dc.replace(/^\n+/, ''); | ||
if (dc) { | ||
if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '') | ||
lines.push(''); | ||
lines.push(doc.comment.replace(/^/gm, '#')); | ||
lines.push(stringifyComment.stringifyComment(dc, '')); | ||
} | ||
@@ -64,0 +67,0 @@ return lines.join('\n') + '\n'; |
@@ -5,4 +5,4 @@ 'use strict'; | ||
var Scalar = require('../nodes/Scalar.js'); | ||
var addComment = require('./addComment.js'); | ||
var stringify = require('./stringify.js'); | ||
var stringifyComment = require('./stringifyComment.js'); | ||
@@ -53,3 +53,3 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) { | ||
onChompKeep(); | ||
return addComment.addComment(`? ${str}`, ctx.indent, keyComment); | ||
return stringifyComment.addComment(`? ${str}`, ctx.indent, keyComment); | ||
} | ||
@@ -59,4 +59,4 @@ if (keyCommentDone) | ||
str = explicitKey | ||
? `? ${addComment.addComment(str, ctx.indent, keyComment)}\n${indent}:` | ||
: addComment.addComment(`${str}:`, ctx.indent, keyComment); | ||
? `? ${stringifyComment.addComment(str, ctx.indent, keyComment)}\n${indent}:` | ||
: stringifyComment.addComment(`${str}:`, ctx.indent, keyComment); | ||
let vcb = ''; | ||
@@ -67,6 +67,4 @@ let valueComment = null; | ||
vcb = '\n'; | ||
if (value.commentBefore) { | ||
const cs = value.commentBefore.replace(/^/gm, `${ctx.indent}#`); | ||
vcb += `\n${cs}`; | ||
} | ||
if (value.commentBefore) | ||
vcb += `\n${stringifyComment.stringifyComment(value.commentBefore, ctx.indent)}`; | ||
valueComment = value.comment; | ||
@@ -115,3 +113,3 @@ } | ||
onChompKeep(); | ||
return addComment.addComment(str + ws + valueStr, ctx.indent, valueComment); | ||
return stringifyComment.addComment(str + ws + valueStr, ctx.indent, valueComment); | ||
} | ||
@@ -118,0 +116,0 @@ } |
{ | ||
"name": "yaml", | ||
"version": "2.0.0-5", | ||
"version": "2.0.0-6", | ||
"license": "ISC", | ||
@@ -74,6 +74,6 @@ "author": "Eemeli Aro <eemeli@gmail.com>", | ||
"@types/jest": "^26.0.20", | ||
"@types/node": "^14.14.37", | ||
"@types/node": "^15.6.1", | ||
"@typescript-eslint/eslint-plugin": "^4.15.2", | ||
"@typescript-eslint/parser": "^4.15.2", | ||
"babel-jest": "^26.6.3", | ||
"babel-jest": "^27.0.1", | ||
"cross-env": "^7.0.3", | ||
@@ -83,3 +83,3 @@ "eslint": "^7.20.0", | ||
"fast-check": "^2.12.0", | ||
"jest": "^26.6.3", | ||
"jest": "^27.0.1", | ||
"jest-ts-webcompat-resolver": "^1.0.0", | ||
@@ -92,4 +92,4 @@ "prettier": "^2.2.1", | ||
"engines": { | ||
"node": ">= 10" | ||
"node": ">= 12" | ||
} | ||
} |
596024
222
15925