Environment
comark: 0.5.1
js-yaml: 5.2.2 (transitive)
- Node: 24.x
- OS: macOS (platform-independent)
Comark Version
0.5.1
Reproduction
import { parse } from 'comark'
// Empty props block (opening `---` immediately followed by closing `---`)
await parse('::page-section\n---\n---\n#title\nHello\n::')
// → throws: YAMLException: expected a document, but the input is empty
Blocks that are not empty parse correctly, at any nesting/indentation level:
await parse('::hero\n---\ntitle: x\n---\n#title\nHi\n::') // OK
await parse('::a\n ::b\n ---\n title: x\n ---\n ::\n::') // OK (nested + indented)
await parse('::hero\n---\n \n---\ncontent\n::') // throws (whitespace-only block)
- Expected: an empty (or whitespace-only) props block yields a component with no prop (equivalent to omitting the block). No throw.
- Actual:
parse() rejects with expected a document, but the input is empty.
Description
A block component whose --- fenced YAML props block is empty (or contains only whitespace) crashes the parser. Comark passes the empty block to js-yaml, which throws YAMLException: expected a document, but the input is empty, and the error propagates out of parse(), failing the entire document rather than the one empty block.
@nuxtjs/mdc (Comark's predecessor) tolerated empty props blocks and simply produced a component with no props. Real-world authored content contains empty props blocks, so this is a migration blocker.
Additional context
Root cause
The block-props rule slices the YAML between the fences and calls parseYaml unconditionally:
packages/comark/src/plugins/syntax.ts — comark_block_yaml (dist: dist/plugins/syntax.js:~245):
const yaml = state.src.slice(state.bMarks[startLine + 1], state.eMarks[lineEnd - 1])
const data = parseYaml(yaml) // yaml === '' when the block is empty
packages/comark/src/internal/yaml.ts — parseYaml (dist: dist/internal/yaml.js):
import { load, JSON_SCHEMA } from 'js-yaml'
export function parseYaml(content) {
return load(content, { schema: JSON_SCHEMA }) // js-yaml throws on empty input
}
js-yaml's load('') (and whitespace-only input) throws expected a document, but the input is empty instead of returning undefined.
Proposed fix
Guard empty/whitespace input in parseYaml so it returns undefined (Comark already handles a falsy result via data || {} at the call site):
// packages/comark/src/internal/yaml.ts
export function parseYaml(content: string) {
if (!content || content.trim() === '') {
return undefined
}
return load(content, { schema: JSON_SCHEMA })
}
Alternatively (or additionally), short-circuit in comark_block_yaml when the sliced block is blank:
const yaml = state.src.slice(state.bMarks[startLine + 1], state.eMarks[lineEnd - 1])
const data = yaml.trim() === '' ? undefined : parseYaml(yaml)
Either change makes an empty props block behave like "no props", matching @nuxtjs/mdc.
Note: the fenced ```yaml [props] props variant likely shares the same code path and should be
covered by the same guard — worth adding a test for both forms.
Suggested tests
expect((await parse('::x\n---\n---\ncontent\n::')).nodes).toBeDefined() // no throw
expect((await parse('::x\n---\n \n---\ncontent\n::')).nodes).toBeDefined() // whitespace-only
expect((await parse('::x\n```yaml [props]\n```\ncontent\n::')).nodes).toBeDefined() // empty fenced props
Logs
Environment
comark:0.5.1js-yaml:5.2.2(transitive)Comark Version
0.5.1
Reproduction
Blocks that are not empty parse correctly, at any nesting/indentation level:
parse()rejects withexpected a document, but the input is empty.Description
A block component whose
---fenced YAML props block is empty (or contains only whitespace) crashes the parser. Comark passes the empty block tojs-yaml, which throwsYAMLException: expected a document, but the input is empty, and the error propagates out ofparse(), failing the entire document rather than the one empty block.@nuxtjs/mdc(Comark's predecessor) tolerated empty props blocks and simply produced a component with no props. Real-world authored content contains empty props blocks, so this is a migration blocker.Additional context
Root cause
The block-props rule slices the YAML between the fences and calls
parseYamlunconditionally:packages/comark/src/plugins/syntax.ts—comark_block_yaml(dist:dist/plugins/syntax.js:~245):packages/comark/src/internal/yaml.ts—parseYaml(dist:dist/internal/yaml.js):js-yaml'sload('')(and whitespace-only input) throwsexpected a document, but the input is emptyinstead of returningundefined.Proposed fix
Guard empty/whitespace input in
parseYamlso it returnsundefined(Comark already handles a falsy result viadata || {}at the call site):Alternatively (or additionally), short-circuit in
comark_block_yamlwhen the sliced block is blank:Either change makes an empty props block behave like "no props", matching
@nuxtjs/mdc.Note: the fenced
```yaml [props]props variant likely shares the same code path and should becovered by the same guard — worth adding a test for both forms.
Suggested tests
Logs