Skip to content

Commit

Permalink
fix: Improve tab handling (tests DK95 & Y79Y, #553)
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed Jun 8, 2024
1 parent d06f386 commit 4e66d72
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/compose/compose-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function composeDoc<
next: value ?? end?.[0],
offset,
onError,
parentIndent: 0,
startOnNewline: true
})
if (props.found) {
Expand Down
2 changes: 1 addition & 1 deletion src/compose/compose-scalar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function composeScalar(
) {
const { value, type, comment, range } =
token.type === 'block-scalar'
? resolveBlockScalar(token, ctx.options.strict, onError)
? resolveBlockScalar(ctx, token, onError)
: resolveFlowScalar(token, ctx.options.strict, onError)

const tagName = tagToken
Expand Down
2 changes: 2 additions & 0 deletions src/compose/resolve-block-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function resolveBlockMap(
next: key ?? sep?.[0],
offset,
onError,
parentIndent: bm.indent,
startOnNewline: true
})
const implicitKey = !keyProps.found
Expand Down Expand Up @@ -83,6 +84,7 @@ export function resolveBlockMap(
next: value,
offset: keyNode.range[2],
onError,
parentIndent: bm.indent,
startOnNewline: !key || key.type === 'block-scalar'
})
offset = valueProps.end
Expand Down
9 changes: 7 additions & 2 deletions src/compose/resolve-block-scalar.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Range } from '../nodes/Node.js'
import { Scalar } from '../nodes/Scalar.js'
import type { BlockScalar } from '../parse/cst.js'
import type { ComposeContext } from './compose-node.js'
import type { ComposeErrorHandler } from './composer.js'

export function resolveBlockScalar(
ctx: ComposeContext,
scalar: BlockScalar,
strict: boolean,
onError: ComposeErrorHandler
): {
value: string
Expand All @@ -14,7 +15,7 @@ export function resolveBlockScalar(
range: Range
} {
const start = scalar.offset
const header = parseBlockScalarHeader(scalar, strict, onError)
const header = parseBlockScalarHeader(scalar, ctx.options.strict, onError)
if (!header)
return { value: '', type: null, comment: '', range: [start, start, start] }
const type = header.mode === '>' ? Scalar.BLOCK_FOLDED : Scalar.BLOCK_LITERAL
Expand Down Expand Up @@ -56,6 +57,10 @@ export function resolveBlockScalar(
}
if (header.indent === 0) trimIndent = indent.length
contentStart = i
if (trimIndent === 0 && !ctx.atRoot) {
const message = 'Block scalar values in collections must be indented'
onError(offset, 'BAD_INDENT', message)
}
break
}
offset += indent.length + content.length + 1
Expand Down
1 change: 1 addition & 0 deletions src/compose/resolve-block-seq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function resolveBlockSeq(
next: value,
offset,
onError,
parentIndent: bs.indent,
startOnNewline: true
})
if (!props.found) {
Expand Down
2 changes: 2 additions & 0 deletions src/compose/resolve-flow-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function resolveFlowCollection(
next: key ?? sep?.[0],
offset,
onError,
parentIndent: fc.indent,
startOnNewline: false
})
if (!props.found) {
Expand Down Expand Up @@ -130,6 +131,7 @@ export function resolveFlowCollection(
next: value,
offset: keyNode.range[2],
onError,
parentIndent: fc.indent,
startOnNewline: false
})

Expand Down
27 changes: 21 additions & 6 deletions src/compose/resolve-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ export interface ResolvePropsArg {
next: Token | null | undefined
offset: number
onError: ComposeErrorHandler
parentIndent: number
startOnNewline: boolean
}

export function resolveProps(
tokens: SourceToken[],
{ flow, indicator, next, offset, onError, startOnNewline }: ResolvePropsArg
{
flow,
indicator,
next,
offset,
onError,
parentIndent,
startOnNewline
}: ResolvePropsArg
) {
let spaceBefore = false
let atNewline = startOnNewline
Expand Down Expand Up @@ -43,7 +52,7 @@ export function resolveProps(
reqSpace = false
}
if (tab) {
if (token.type !== 'comment') {
if (atNewline && token.type !== 'comment' && token.type !== 'newline') {
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation')
}
tab = null
Expand All @@ -55,9 +64,8 @@ export function resolveProps(
// In a flow collection, only the parser handles indent.
if (
!flow &&
atNewline &&
(indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
token.source[0] === '\t'
token.source.includes('\t')
) {
tab = token
}
Expand Down Expand Up @@ -132,7 +140,8 @@ export function resolveProps(
`Unexpected ${token.source} in ${flow ?? 'collection'}`
)
found = token
atNewline = false
atNewline =
indicator === 'seq-item-ind' || indicator === 'explicit-key-ind'
hasSpace = false
break
case 'comma':
Expand Down Expand Up @@ -167,7 +176,13 @@ export function resolveProps(
'Tags and anchors must be separated from the next token by white space'
)
}
if (tab) onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation')
if (
tab &&
((atNewline && tab.indent <= parentIndent) ||
next?.type === 'block-map' ||
next?.type === 'block-seq')
)
onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation')
return {
comma,
found,
Expand Down
7 changes: 6 additions & 1 deletion src/parse/cst-scalar.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ComposeContext } from '../compose/compose-node.js'
import type { ComposeErrorHandler } from '../compose/composer.js'
import { resolveBlockScalar } from '../compose/resolve-block-scalar.js'
import { resolveFlowScalar } from '../compose/resolve-flow-scalar.js'
Expand Down Expand Up @@ -55,7 +56,11 @@ export function resolveAsScalar(
case 'double-quoted-scalar':
return resolveFlowScalar(token, strict, _onError)
case 'block-scalar':
return resolveBlockScalar(token, strict, _onError)
return resolveBlockScalar(
{ options: { strict } } as ComposeContext,
token,
_onError
)
}
}
return null
Expand Down
14 changes: 12 additions & 2 deletions src/parse/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,13 +551,23 @@ export class Lexer {
nl = this.buffer.length
}
}
if (!this.blockScalarKeep) {

// Trailing insufficiently indented tabs are invalid.
// To catch that during parsing, we include them in the block scalar value.
let i = nl + 1
ch = this.buffer[i]
while (ch === ' ') ch = this.buffer[++i]
if (ch === '\t') {
while (ch === '\t' || ch === ' ' || ch === '\r' || ch === '\n')
ch = this.buffer[++i]
nl = i - 1
} else if (!this.blockScalarKeep) {
do {
let i = nl - 1
let ch = this.buffer[i]
if (ch === '\r') ch = this.buffer[--i]
const lastChar = i // Drop the line if last char not more indented
while (ch === ' ' || ch === '\t') ch = this.buffer[--i]
while (ch === ' ') ch = this.buffer[--i]
if (ch === '\n' && i >= this.pos && i + 1 + indent > lastChar) nl = i
else break
} while (true)
Expand Down
9 changes: 0 additions & 9 deletions tests/yaml-test-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ const skip: Record<string, boolean | string[]> = {
'SF5V/0': ['errors'], // allow duplicate %YAML directives

// FIXME recent upstream additions
'DK95/0': true,
'DK95/4': true,
'DK95/5': true,
'Y79Y/4': ['errors'],
'Y79Y/5': ['errors'],
'Y79Y/6': ['errors'],
'Y79Y/7': ['errors'],
'Y79Y/8': ['errors'],
'Y79Y/9': ['errors'],
'ZYU8/2': ['errors']
}

Expand Down

0 comments on commit 4e66d72

Please sign in to comment.