mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-13 12:18:28 +01:00
Answer prose round 1: 0 🔴, 2 🟡 (0 misread); the memo's comments say what they guard, two test names say what they check, item 151 names the one walk
This commit is contained in:
@@ -18,7 +18,7 @@ test('a target nothing closes reads as none, at every `](`', () => {
|
||||
assert.deepEqual(targets('[a](b'.repeat(3)), [undefined, undefined, undefined])
|
||||
})
|
||||
|
||||
test('targets sharing a destination end share its title and its failure', () => {
|
||||
test('targets sharing a destination end share its failure', () => {
|
||||
assert.deepEqual(targets('[a](b[c](d "t" x)'), [undefined, undefined])
|
||||
assert.deepEqual(targets('[a](b[c](d "t" x'), [undefined, undefined])
|
||||
})
|
||||
@@ -28,7 +28,7 @@ test('an unbracketed destination ends at its first unmatched `)`', () => {
|
||||
assert.deepEqual(targets('[a](b\\)c)'), [{ destination: 'b)c', length: 6 }])
|
||||
})
|
||||
|
||||
test('a target reads its whitespace, a bracketed destination and a title', () => {
|
||||
test('a target reads whitespace and a title around its destination, bracketed, unbracketed or empty', () => {
|
||||
assert.deepEqual(targets('[a]( b\n "t" ) [c](<d e> \'f\') [g]()'), [
|
||||
{ destination: 'b', length: 10, title: 't' },
|
||||
{ destination: 'd e', length: 11, title: 'f' },
|
||||
|
||||
@@ -7,17 +7,17 @@ export type LinkDefinition = { destination: string; title?: string }
|
||||
|
||||
export type LinkPart = { length: number; value: string }
|
||||
|
||||
// What follows a destination ending at an index, the same for every destination ending there: the index after the `)`, and the title.
|
||||
// Every destination ending at one index shares what follows it: the title and the closing `)`.
|
||||
type Tail = { end: number; title: string | undefined }
|
||||
|
||||
// `destinationEnds[start]` is where an unbracketed destination starting there stops, for every start a target reads from: one after a `(`, a space or a control character.
|
||||
// `destinationEnds[start]` is where an unbracketed destination starting there stops, for every start a target can have: the index just after a `(`, a space or a control character.
|
||||
export type TargetMemo = { destinationEnds: Int32Array; tails: Map<number, Tail | undefined> }
|
||||
|
||||
// The lossless flavour escapes a quote alone, writing a title holding a backslash or an entity reference as a directive (spec/flavour.md, Marks); the portable flavour writes no directive, so it escapes those too, and a table cell's `|` (README, Portable markdown).
|
||||
export type TitleEscapes = 'lossless' | 'portable' | 'portable-table-cell'
|
||||
|
||||
const bracketedDestination = /<((?:[^\n<>\\]|\\[^\n])*)>/y
|
||||
// The longest text an unbracketed destination can take: it stops at a space or a control character.
|
||||
// The longest text an unbracketed destination can take.
|
||||
const destinationRun = new RegExp(`[^ ${controlCharacterRange}]*`, 'y')
|
||||
// CommonMark: a link label holds at most this many characters between its brackets, an escape counting as two.
|
||||
export const labelLimit = 999
|
||||
@@ -51,7 +51,7 @@ export function readDestination(text: string, offset: number): LinkPart | undefi
|
||||
return length === 0 ? undefined : { length, value: decodeTextEscapes(run.slice(0, length)) }
|
||||
}
|
||||
|
||||
// `offset` sits on the `(` a link text closes into. The definition is read on demand, so a target its link refuses costs no copy.
|
||||
// `offset` sits on the `(` a link text closes into. The definition is built only when called, so a link the reader then refuses never decodes its destination.
|
||||
export function readInlineTarget(text: string, offset: number, memo: TargetMemo): InlineTarget | undefined {
|
||||
const start = skipLinkWhitespace(text, offset + 1)
|
||||
const end = destinationEnd(text, start, memo)
|
||||
@@ -67,7 +67,7 @@ export function readInlineTarget(text: string, offset: number, memo: TargetMemo)
|
||||
return { definition, length: tail.end - offset }
|
||||
}
|
||||
|
||||
// Every unbracketed destination's end in one pass, with a stack of the starts still open. The text's own start is one, which `readDestination` reads.
|
||||
// Every unbracketed destination's end, in one pass. Index 0 is a start too, for `readDestination`, which reads from its text's first character.
|
||||
export function targetMemo(text: string): TargetMemo {
|
||||
const destinationEnds = new Int32Array(text.length + 1)
|
||||
const open = [0]
|
||||
@@ -123,7 +123,7 @@ export function readTitle(text: string, offset: number): LinkPart | undefined {
|
||||
// The label, the destination and the title each take at most one line ending with them.
|
||||
export function skipLinkWhitespace(text: string, offset: number): number {
|
||||
linkWhitespace.lastIndex = offset
|
||||
// The pattern matches empty, so the test always moves `lastIndex` past the whitespace.
|
||||
// The pattern matches empty, so the test never fails, which would reset `lastIndex` to 0.
|
||||
linkWhitespace.test(text)
|
||||
return linkWhitespace.lastIndex
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ type Scan = {
|
||||
pieces: Piece[]
|
||||
source: string
|
||||
spans: NestedSpans
|
||||
// Built at the first inline target the scan reads.
|
||||
targets: TargetMemo | undefined
|
||||
}
|
||||
|
||||
|
||||
@@ -72,10 +72,11 @@
|
||||
### 151. Read a link destination holding an unbalanced unescaped parenthesis as no destination, in every markdown reader.
|
||||
|
||||
CommonMark lets an unbracketed destination hold a parenthesis only escaped or in a balanced pair,
|
||||
but `[a](b(c "t")` reads as a link to `b(c` titled `t`, where cmark and commonmark.js read text.
|
||||
`readDestination` and `targetMemo` (`src/markdown/commonmark/link-syntax.ts`) stop at a space with
|
||||
parentheses still open and keep the destination. The writers escape an unbalanced parenthesis, so
|
||||
no written markdown changes. Found while shipping item 140, 2026-10-28.
|
||||
but `[a](b(c "t")` reads as a link to `b(c` titled `t`; cmark and commonmark.js read it as text.
|
||||
`targetMemo` (`src/markdown/commonmark/link-syntax.ts`), which `readDestination` reads through,
|
||||
stops at a space with parentheses still open and keeps the destination. The writers escape an
|
||||
unbalanced parenthesis, so markdown they wrote reads the same after the fix. Found while shipping
|
||||
item 140, 2026-10-28.
|
||||
|
||||
### 95. Find the code-span closers an escape forms, the mark runs a line cannot spell and the text `[` that opens link text by reading the line back, in place of `escapeClosedRuns`, `unspellableRuns` and `lastLinkClose` predicting them.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user