Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace error.offset with error.pos: [number, number] #260

Merged
merged 1 commit into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/compose/compose-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { isMap, isNode, ParsedNode } from '../nodes/Node.js'
import { Scalar } from '../nodes/Scalar.js'
import type { YAMLMap } from '../nodes/YAMLMap.js'
import type { YAMLSeq } from '../nodes/YAMLSeq.js'
import type { BlockMap, BlockSequence, FlowCollection } from '../parse/cst.js'
import type {
BlockMap,
BlockSequence,
FlowCollection,
SourceToken
} from '../parse/cst.js'
import { CollectionTag } from '../schema/types.js'
import type { ComposeContext, ComposeNode } from './compose-node.js'
import type { ComposeErrorHandler } from './composer.js'
Expand All @@ -14,7 +19,7 @@ export function composeCollection(
CN: ComposeNode,
ctx: ComposeContext,
token: BlockMap | BlockSequence | FlowCollection,
tagName: string | null,
tagToken: SourceToken | null,
onError: ComposeErrorHandler
) {
let coll: YAMLMap.Parsed | YAMLSeq.Parsed
Expand All @@ -33,6 +38,10 @@ export function composeCollection(
}
}

if (!tagToken) return coll
const tagName = ctx.directives.tagName(tagToken.source, msg =>
onError(tagToken, 'TAG_RESOLVE_FAILED', msg)
)
if (!tagName) return coll

// Cast needed due to: https://github.com/Microsoft/TypeScript/issues/3841
Expand All @@ -53,7 +62,7 @@ export function composeCollection(
tag = kt
} else {
onError(
coll.range[0],
tagToken,
'TAG_RESOLVE_FAILED',
`Unresolved tag: ${tagName}`,
true
Expand All @@ -65,7 +74,7 @@ export function composeCollection(

const res = tag.resolve(
coll,
msg => onError(coll.range[0], 'TAG_RESOLVE_FAILED', msg),
msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg),
ctx.options
)
const node = isNode(res)
Expand Down
34 changes: 14 additions & 20 deletions src/compose/compose-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Directives } from '../doc/directives.js'
import { Alias } from '../nodes/Alias.js'
import type { ParsedNode } from '../nodes/Node.js'
import type { ParseOptions } from '../options.js'
import type { FlowScalar, Token } from '../parse/cst.js'
import type { FlowScalar, SourceToken, Token } from '../parse/cst.js'
import type { Schema } from '../schema/Schema.js'
import { composeCollection } from './compose-collection.js'
import { composeScalar } from './compose-scalar.js'
Expand All @@ -16,11 +16,11 @@ export interface ComposeContext {
schema: Readonly<Schema>
}

export interface Props {
interface Props {
spaceBefore: boolean
comment: string
anchor: string
tagName: string
anchor: SourceToken | null
tag: SourceToken | null
}

const CN = { composeNode, composeEmptyNode }
Expand All @@ -32,14 +32,14 @@ export function composeNode(
props: Props,
onError: ComposeErrorHandler
) {
const { spaceBefore, comment, anchor, tagName } = props
const { spaceBefore, comment, anchor, tag } = props
let node: ParsedNode
switch (token.type) {
case 'alias':
node = composeAlias(ctx, token, onError)
if (anchor || tagName)
if (anchor || tag)
onError(
token.offset,
token,
'ALIAS_PROPS',
'An alias node must not specify any properties'
)
Expand All @@ -48,18 +48,14 @@ export function composeNode(
case 'single-quoted-scalar':
case 'double-quoted-scalar':
case 'block-scalar':
node = composeScalar(ctx, token, tagName, onError)
if (anchor) {
node.anchor = anchor
}
node = composeScalar(ctx, token, tag, onError)
if (anchor) node.anchor = anchor.source.substring(1)
break
case 'block-map':
case 'block-seq':
case 'flow-collection':
node = composeCollection(CN, ctx, token, tagName, onError)
if (anchor) {
node.anchor = anchor
}
node = composeCollection(CN, ctx, token, tag, onError)
if (anchor) node.anchor = anchor.source.substring(1)
break
default:
console.log(token)
Expand All @@ -78,7 +74,7 @@ export function composeEmptyNode(
offset: number,
before: Token[] | undefined,
pos: number | null,
{ spaceBefore, comment, anchor, tagName }: Props,
{ spaceBefore, comment, anchor, tag }: Props,
onError: ComposeErrorHandler
) {
const token: FlowScalar = {
Expand All @@ -87,10 +83,8 @@ export function composeEmptyNode(
indent: -1,
source: ''
}
const node = composeScalar(ctx, token, tagName, onError)
if (anchor) {
node.anchor = anchor
}
const node = composeScalar(ctx, token, tag, onError)
if (anchor) node.anchor = anchor.source.substring(1)
if (spaceBefore) node.spaceBefore = true
if (comment) node.comment = comment
return node
Expand Down
23 changes: 15 additions & 8 deletions src/compose/compose-scalar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isScalar, SCALAR } from '../nodes/Node.js'
import { Scalar } from '../nodes/Scalar.js'
import type { BlockScalar, FlowScalar } from '../parse/cst.js'
import type { BlockScalar, FlowScalar, SourceToken } from '../parse/cst.js'
import type { Schema } from '../schema/Schema.js'
import type { ScalarTag } from '../schema/types.js'
import type { ComposeContext } from './compose-node.js'
Expand All @@ -11,28 +11,34 @@ import { resolveFlowScalar } from './resolve-flow-scalar.js'
export function composeScalar(
ctx: ComposeContext,
token: FlowScalar | BlockScalar,
tagName: string | null,
tagToken: SourceToken | null,
onError: ComposeErrorHandler
) {
const { value, type, comment, range } =
token.type === 'block-scalar'
? resolveBlockScalar(token, ctx.options.strict, onError)
: resolveFlowScalar(token, ctx.options.strict, onError)

const tag = tagName
? findScalarTagByName(ctx.schema, value, tagName, onError)
: findScalarTagByTest(ctx.schema, value, token.type === 'scalar')
const tagName = tagToken
? ctx.directives.tagName(tagToken.source, msg =>
onError(tagToken, 'TAG_RESOLVE_FAILED', msg)
)
: null
const tag =
tagToken && tagName
? findScalarTagByName(ctx.schema, value, tagName, tagToken, onError)
: findScalarTagByTest(ctx.schema, value, token.type === 'scalar')

let scalar: Scalar
try {
const res = tag.resolve(
value,
msg => onError(token.offset, 'TAG_RESOLVE_FAILED', msg),
msg => onError(tagToken || token, 'TAG_RESOLVE_FAILED', msg),
ctx.options
)
scalar = isScalar(res) ? res : new Scalar(res)
} catch (error) {
onError(token.offset, 'TAG_RESOLVE_FAILED', error.message)
onError(tagToken || token, 'TAG_RESOLVE_FAILED', error.message)
scalar = new Scalar(value)
}
scalar.range = range
Expand All @@ -49,6 +55,7 @@ function findScalarTagByName(
schema: Schema,
value: string,
tagName: string,
tagToken: SourceToken,
onError: ComposeErrorHandler
) {
if (tagName === '!') return schema[SCALAR] // non-specific tag
Expand All @@ -68,7 +75,7 @@ function findScalarTagByName(
return kt
}
onError(
0,
tagToken,
'TAG_RESOLVE_FAILED',
`Unresolved tag: ${tagName}`,
tagName !== 'tag:yaml.org,2002:str'
Expand Down
49 changes: 32 additions & 17 deletions src/compose/composer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Directives } from '../doc/directives.js'
import { Document } from '../doc/Document.js'
import { ErrorCode, YAMLParseError, YAMLWarning } from '../errors.js'
import { isCollection, isPair } from '../nodes/Node.js'
import { isCollection, isPair, Range } from '../nodes/Node.js'
import {
defaultOptions,
DocumentOptions,
Expand All @@ -12,13 +12,26 @@ import type { Token } from '../parse/cst.js'
import { composeDoc } from './compose-doc.js'
import { resolveEnd } from './resolve-end.js'

type ErrorSource =
| number
| [number, number]
| Range
| { offset: number; source?: string }

export type ComposeErrorHandler = (
offset: number,
source: ErrorSource,
code: ErrorCode,
message: string,
warning?: boolean
) => void

function getErrorPos(src: ErrorSource): [number, number] {
if (typeof src === 'number') return [src, src + 1]
if (Array.isArray(src)) return src.length === 2 ? src : [src[0], src[1]]
const { offset, source } = src
return [offset, offset + (typeof source === 'string' ? source.length : 1)]
}

function parsePrelude(prelude: string[]) {
let comment = ''
let atComment = false
Expand Down Expand Up @@ -73,14 +86,10 @@ export class Composer {
this.options = options
}

private onError = (
offset: number,
code: ErrorCode,
message: string,
warning?: boolean
) => {
if (warning) this.warnings.push(new YAMLWarning(offset, code, message))
else this.errors.push(new YAMLParseError(offset, code, message))
private onError: ComposeErrorHandler = (source, code, message, warning) => {
const pos = getErrorPos(source)
if (warning) this.warnings.push(new YAMLWarning(pos, code, message))
else this.errors.push(new YAMLParseError(pos, code, message))
}

private decorate(doc: Document.Parsed, afterDoc: boolean) {
Expand Down Expand Up @@ -146,9 +155,11 @@ export class Composer {
if (process.env.LOG_STREAM) console.dir(token, { depth: null })
switch (token.type) {
case 'directive':
this.directives.add(token.source, (offset, message, warning) =>
this.onError(offset, 'BAD_DIRECTIVE', message, warning)
)
this.directives.add(token.source, (offset, message, warning) => {
const pos = getErrorPos(token)
pos[0] += offset
this.onError(pos, 'BAD_DIRECTIVE', message, warning)
})
this.prelude.push(token.source)
this.atDirectives = true
break
Expand All @@ -161,7 +172,7 @@ export class Composer {
)
if (this.atDirectives && !doc.directives.marker)
this.onError(
token.offset,
token,
'MISSING_CHAR',
'Missing directives-end indicator line'
)
Expand All @@ -182,7 +193,11 @@ export class Composer {
const msg = token.source
? `${token.message}: ${JSON.stringify(token.source)}`
: token.message
const error = new YAMLParseError(-1, 'UNEXPECTED_TOKEN', msg)
const error = new YAMLParseError(
getErrorPos(token),
'UNEXPECTED_TOKEN',
msg
)
if (this.atDirectives || !this.doc) this.errors.push(error)
else this.doc.errors.push(error)
break
Expand All @@ -191,7 +206,7 @@ export class Composer {
if (!this.doc) {
const msg = 'Unexpected doc-end without preceding document'
this.errors.push(
new YAMLParseError(token.offset, 'UNEXPECTED_TOKEN', msg)
new YAMLParseError(getErrorPos(token), 'UNEXPECTED_TOKEN', msg)
)
break
}
Expand All @@ -212,7 +227,7 @@ export class Composer {
default:
this.errors.push(
new YAMLParseError(
-1,
getErrorPos(token),
'UNEXPECTED_TOKEN',
`Unsupported token ${token.type}`
)
Expand Down
10 changes: 5 additions & 5 deletions src/compose/resolve-block-map.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Pair } from '../nodes/Pair.js'
import { YAMLMap } from '../nodes/YAMLMap.js'
import type { BlockMap } from '../parse/cst.js'
import type { BlockMap, Token } from '../parse/cst.js'
import type { ComposeContext, ComposeNode } from './compose-node.js'
import type { ComposeErrorHandler } from './composer.js'
import { resolveProps } from './resolve-props.js'
Expand Down Expand Up @@ -38,7 +38,7 @@ export function resolveBlockMap(
else if ('indent' in key && key.indent !== bm.indent)
onError(offset, 'BAD_INDENT', startColMsg)
}
if (!keyProps.anchor && !keyProps.tagName && !sep) {
if (!keyProps.anchor && !keyProps.tag && !sep) {
// TODO: assert being at last item?
if (keyProps.comment) {
if (map.comment) map.comment += '\n' + keyProps.comment
Expand All @@ -50,7 +50,7 @@ export function resolveBlockMap(
onError(offset, 'BAD_INDENT', startColMsg)
if (implicitKey && containsNewline(key))
onError(
keyProps.start,
key as Token, // checked by containsNewline()
'MULTILINE_IMPLICIT_KEY',
'Implicit keys need to be on a single line'
)
Expand Down Expand Up @@ -84,7 +84,7 @@ export function resolveBlockMap(
keyProps.start < valueProps.found.offset - 1024
)
onError(
offset,
keyNode.range,
'KEY_OVER_1024_CHARS',
'The : indicator must be at most 1024 chars after the start of an implicit block mapping key'
)
Expand All @@ -99,7 +99,7 @@ export function resolveBlockMap(
// key with no value
if (implicitKey)
onError(
keyStart,
keyNode.range,
'MISSING_CHAR',
'Implicit map keys need to be followed by map values'
)
Expand Down
8 changes: 4 additions & 4 deletions src/compose/resolve-block-scalar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function parseBlockScalarHeader(
) {
/* istanbul ignore if should not happen */
if (props[0].type !== 'block-scalar-header') {
onError(offset, 'IMPOSSIBLE', 'Block scalar header not found')
onError(props[0], 'IMPOSSIBLE', 'Block scalar header not found')
return null
}
const { source } = props[0]
Expand Down Expand Up @@ -166,19 +166,19 @@ function parseBlockScalarHeader(
if (strict && !hasSpace) {
const message =
'Comments must be separated from other tokens by white space characters'
onError(offset + length, 'COMMENT_SPACE', message)
onError(token, 'COMMENT_SPACE', message)
}
length += token.source.length
comment = token.source.substring(1)
break
case 'error':
onError(offset + length, 'UNEXPECTED_TOKEN', token.message)
onError(token, 'UNEXPECTED_TOKEN', token.message)
length += token.source.length
break
/* istanbul ignore next should not happen */
default: {
const message = `Unexpected token in block scalar header: ${token.type}`
onError(offset + length, 'UNEXPECTED_TOKEN', message)
onError(token, 'UNEXPECTED_TOKEN', message)
const ts = (token as any).source
if (ts && typeof ts === 'string') length += ts.length
}
Expand Down
Loading