diff --git a/src/compose/compose-block-map.ts b/src/compose/compose-block-map.ts index b2b8f8fc..4a42ed1f 100644 --- a/src/compose/compose-block-map.ts +++ b/src/compose/compose-block-map.ts @@ -13,11 +13,10 @@ export function composeBlockMap( const start = offset const map = new YAMLMap(doc.schema) if (anchor) doc.anchors.setAnchor(map, anchor) - const onRelError = (rel: number, msg: string) => onError(offset + rel, msg) for (const { start, key, sep, value } of items) { // key properties - const keyProps = resolveProps(start, 'explicit-key-ind', onRelError) + const keyProps = resolveProps(start, 'explicit-key-ind', offset, onError) if (!keyProps.found) { // implicit key if (keyProps.anchor || keyProps.tagName || sep) { @@ -49,7 +48,7 @@ export function composeBlockMap( } // value properties - const valueProps = resolveProps(sep || [], 'map-value-ind', onRelError) + const valueProps = resolveProps(sep || [], 'map-value-ind', offset, onError) offset += valueProps.length if (valueProps.found) { diff --git a/src/compose/compose-block-seq.ts b/src/compose/compose-block-seq.ts index 7ff66f1a..b12fed17 100644 --- a/src/compose/compose-block-seq.ts +++ b/src/compose/compose-block-seq.ts @@ -14,9 +14,7 @@ export function composeBlockSeq( const seq = new YAMLSeq(doc.schema) if (anchor) doc.anchors.setAnchor(seq, anchor) for (const { start, value } of items) { - const props = resolveProps(start, 'seq-item-ind', (o, m) => - onError(offset + o, m) - ) + const props = resolveProps(start, 'seq-item-ind', offset, onError) offset += props.length if (!props.found) { if (props.anchor || props.tagName || value) { diff --git a/src/compose/compose-doc.ts b/src/compose/compose-doc.ts new file mode 100644 index 00000000..74ceb9b2 --- /dev/null +++ b/src/compose/compose-doc.ts @@ -0,0 +1,39 @@ +import { Document } from '../doc/Document.js' +import type { Options } from '../options.js' +import type * as Parser from '../parse/parser.js' +import { composeNode } from './compose-node.js' +import { resolveEnd } from './resolve-end.js' +import { resolveProps } from './resolve-props.js' +import { StreamDirectives } from './stream-directives.js' + +export function composeDoc( + options: Options | null, + directives: StreamDirectives, + { offset, start, value, end }: Parser.Document, + onError: (offset: number, message: string, warning?: boolean) => void +) { + const doc = new Document(undefined, options || undefined) as Document.Parsed + doc.version = directives.yaml.version + doc.setSchema() // FIXME: always do this in the constructor + + const props = resolveProps(start, 'doc-start', offset, onError) + if (props.found) doc.directivesEndMarker = true + + let to = offset + props.length + const token = value || { type: 'scalar', offset: to, indent: -1, source: '' } + doc.contents = composeNode(doc, token, props, onError) + if (doc.contents.range) to = doc.contents.range[1] + else { + // FIXME: remove once verified never happens + onError(to, 'Resolved child node has no range') + if (value) { + if ('offset' in value) to = value.offset + if ('source' in value && value.source) to += value.source.length + } + } + const { comment, length } = resolveEnd(end) + if (comment) doc.comment = comment + + doc.range = [offset, to + length] + return doc +} diff --git a/src/compose/parse-docs.ts b/src/compose/parse-docs.ts new file mode 100644 index 00000000..3179b42a --- /dev/null +++ b/src/compose/parse-docs.ts @@ -0,0 +1,33 @@ +import { Document } from '../doc/Document' +import { Parser } from '../parse/parser' +import { composeDoc } from './compose-doc' +import { StreamDirectives } from './stream-directives' + +export function parseDocs(source: string) { + const directives = new StreamDirectives() + const docs: Document.Parsed[] = [] + const lines: number[] = [] + + const onError = (offset: number, message: string, warning?: boolean) => { + console.error(warning ? '???' : '!!!', { offset, message }) + } + + const parser = new Parser( + token => { + switch (token.type) { + case 'directive': + directives.add(token.source, onError) + break + case 'document': + docs.push(composeDoc(null, directives, token, onError)) + break + default: + console.log('###', token) + } + }, + n => lines.push(n) + ) + parser.parse(source) + + return docs +} diff --git a/src/compose/resolve-props.ts b/src/compose/resolve-props.ts index ad1dc8b6..2e3575e5 100644 --- a/src/compose/resolve-props.ts +++ b/src/compose/resolve-props.ts @@ -11,8 +11,13 @@ export interface Props { export function resolveProps( start: SourceToken[], - indicator: 'explicit-key-ind' | 'map-value-ind' | 'seq-item-ind', - onError: (relOffset: number, message: string) => void + indicator: + | 'doc-start' + | 'explicit-key-ind' + | 'map-value-ind' + | 'seq-item-ind', + offset: number, + onError: (offset: number, message: string) => void ) { let length = 0 let spaceBefore = false @@ -50,7 +55,7 @@ export function resolveProps( found = true break default: - onError(length, `Unexpected ${token.type} token`) + onError(offset + length, `Unexpected ${token.type} token`) } if (token.source) length += token.source.length } diff --git a/src/compose/stream-directives.ts b/src/compose/stream-directives.ts index 1f089c35..35ad8335 100644 --- a/src/compose/stream-directives.ts +++ b/src/compose/stream-directives.ts @@ -1,6 +1,6 @@ export class StreamDirectives { tags: Record = { '!!': 'tag:yaml.org,2002:' } - yaml: { version: '1.1' | '1.2' } = { version: '1.2' } + yaml: { version: '1.1' | '1.2' | undefined } = { version: undefined } static from(src: StreamDirectives) { const res = new StreamDirectives()