4.3: a paragraph line reading as a link reference definition escapes its opening bracket
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "[",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"timestamp": "]:a"
|
||||
},
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"type": "paragraph"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "[",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"marks": [
|
||||
{
|
||||
"type": "code"
|
||||
}
|
||||
],
|
||||
"text": "]: a",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"type": "paragraph"
|
||||
}
|
||||
],
|
||||
"type": "blockquote"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "[",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"timestamp": "]:a"
|
||||
},
|
||||
"type": "date"
|
||||
},
|
||||
{
|
||||
"type": "hardBreak"
|
||||
},
|
||||
{
|
||||
"text": "b",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"type": "paragraph"
|
||||
}
|
||||
],
|
||||
"type": "listItem"
|
||||
}
|
||||
],
|
||||
"type": "bulletList"
|
||||
}
|
||||
],
|
||||
"type": "doc",
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
\[:date{timestamp="]:a"}
|
||||
|
||||
> \[`]: a`
|
||||
|
||||
- \[:date{timestamp="]:a"}\
|
||||
b
|
||||
@@ -54,6 +54,8 @@ normalizes to it through the round-trip.
|
||||
- Entity references in input decode to their characters; output backslash-escapes only where text
|
||||
would otherwise parse as syntax, scanning the assembled line rather than each text node: escape
|
||||
the leading delimiter of a construct that would otherwise open, re-scan from there, and repeat.
|
||||
A paragraph's opening `[` escapes wherever its line reads as a link reference definition, which
|
||||
resolves before any inline construct binds: a `]` inside a code span or `{attrs}` counts.
|
||||
An emphasis delimiter run in text escapes where CommonMark can open **or** close with it, so
|
||||
`*not emphasis*` is `\*not emphasis\*` — no delimiter the emitter did not write reaches the
|
||||
matching below, which is what lets the emitter decide its own pairings.
|
||||
|
||||
@@ -3,6 +3,7 @@ import { delimiterFlags, isWordCharacter, matchEmphasis, runLength } from '../em
|
||||
import { backslashEscape, escapesLineClaim, inlineHtmlConstruct, opensBracketedAutolink, opensEmailAutolink, type LinePosition } from '../commonmark-grammar.ts'
|
||||
import { isBareDelimiterRow } from '../pipe-table-syntax.ts'
|
||||
import { opensInlineDirective } from '../directive-syntax.ts'
|
||||
import { opensLinkDefinition } from '../link-reference-definitions.ts'
|
||||
import { readEntityReference } from '../entity-references.ts'
|
||||
|
||||
export type EmphasisRole = 'close' | 'open'
|
||||
@@ -27,8 +28,7 @@ type EmittedRun = { canClose: boolean; canOpen: boolean; character: string; deli
|
||||
|
||||
const delimiters = ['*', '_', '`', '~']
|
||||
|
||||
// The `:` keeps a `[label]: url` line escaped: unescaped, the parser swallows it as a link reference definition.
|
||||
const followsLinkText = /[([:]/
|
||||
const followsLinkText = /[([]/
|
||||
|
||||
export function assembleInlineLine(segments: readonly InlineSegment[], container: LineContainer): AssembledLine {
|
||||
return escape(resolveEmphasis(segments), container)
|
||||
@@ -90,7 +90,8 @@ function escape(segments: readonly InlineSegment[], container: LineContainer): A
|
||||
placements.push(output.length)
|
||||
output += scan.charAt(index)
|
||||
}
|
||||
return { line: output, unspellableRun: unspellableRun(segments, output, placements) }
|
||||
const spelled = container === 'paragraph' && opensLinkDefinition(output) ? `\\${output}` : output
|
||||
return { line: spelled, unspellableRun: unspellableRun(segments, output, placements) }
|
||||
}
|
||||
|
||||
function unspellableRun(segments: readonly InlineSegment[], output: string, placements: readonly number[]): NodeRange | undefined {
|
||||
|
||||
+6
-2
@@ -1,10 +1,14 @@
|
||||
import type { LinkDefinition, LinkPart } from '../link-syntax.ts'
|
||||
import { normalizeLabel, readDestination, readLabel, readTitle, skipLinkWhitespace } from '../link-syntax.ts'
|
||||
import type { LinkDefinition, LinkPart } from './link-syntax.ts'
|
||||
import { normalizeLabel, readDestination, readLabel, readTitle, skipLinkWhitespace } from './link-syntax.ts'
|
||||
|
||||
type ReadDefinition = { definition: LinkDefinition; label: string; length: number }
|
||||
|
||||
const restOfLine = /^[ \t]*(?:\n|$)/
|
||||
|
||||
export function opensLinkDefinition(text: string): boolean {
|
||||
return readDefinition(text) !== undefined
|
||||
}
|
||||
|
||||
export function readLinkDefinitions(definitions: Map<string, LinkDefinition>, text: string): string {
|
||||
let rest = text
|
||||
let read = readDefinition(rest)
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '../commonmark-grammar.ts'
|
||||
import { directiveLineEscape, malformedDirective, readDirectiveLine } from '../directive-syntax.ts'
|
||||
import { barePipeCells, isDelimiterRow, isPipeAlignment, isPipeDelimiter, malformedPipeTable, pipeCells } from '../pipe-table-syntax.ts'
|
||||
import { readLinkDefinitions } from './link-reference-definitions.ts'
|
||||
import { readLinkDefinitions } from '../link-reference-definitions.ts'
|
||||
|
||||
export type Block = { position: SourcePosition } & (
|
||||
| { argument: string | undefined; attributes: DirectiveAttributes; blocks: Block[] | undefined; kind: 'directive'; name: string }
|
||||
|
||||
Reference in New Issue
Block a user