mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-12 11:48:29 +01:00
Answer prose round 1: 0 🔴, 7 🟡 (0 misread); the bound test's block count is 53, comments name their referents
This commit is contained in:
@@ -203,7 +203,7 @@ export function holdsThematicBreak(tail: ThematicBreakTail | undefined, text: st
|
||||
return text.length >= tail.shortest && text.length <= tail.longest && text.charAt(0) === tail.marker
|
||||
}
|
||||
|
||||
// True of every line isThematicBreak takes, and kept for a prefixed line from its parts without reading it.
|
||||
// Every line isThematicBreak accepts passes this, and a joined line passes exactly when each part does, so BlockText derives it from a prefix and its body.
|
||||
export function holdsOnlyRuleCharacters(text: string): boolean {
|
||||
for (let index = 0; index < text.length; index += 1) {
|
||||
const character = text.charAt(index)
|
||||
|
||||
@@ -76,7 +76,7 @@ test('refuses a quote whose prefixed lines would pass V8\'s longest string', ()
|
||||
assert.equal(pastTheBound(adfToLosslessMarkdown(document({ content: [code, code], type: 'blockquote' }))), true)
|
||||
})
|
||||
|
||||
// A code block spelled in 55 characters around its text; the blocks between them take a blank line, and the markdown a closing line break.
|
||||
// A code block written as its text plus 53 characters; a blank line parts two blocks, and the markdown ends with a line break.
|
||||
function codeBlockOf(textLength: number): AdfNode {
|
||||
return { attrs: {}, content: [{ text: `${'a'.repeat(textLength - 1)}\n`, type: 'text' }], type: 'codeBlock' }
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export function walkBlocks(nodes: readonly AdfNode[], path: ConvertErrorPath, de
|
||||
for (const [index, node] of nodes.entries()) {
|
||||
const block = emitBlock(node, [...path, 'content', index], depth, writing)
|
||||
if (!block.ok) return block
|
||||
// Refused on the measure, before any text is written, so every engine stops at the first block past the bound.
|
||||
// Refused on the measure, before any text is written, so every engine stops at the first block past V8's longest string.
|
||||
const fits = withinLongest(block.value.text.length, block.value)
|
||||
if (!fits.ok) return fits
|
||||
headroom = Math.min(headroom, block.value.headroom)
|
||||
|
||||
@@ -8,7 +8,7 @@ type Lines =
|
||||
| { kind: 'joined'; parts: readonly BlockText[] }
|
||||
| { kind: 'text'; lines: readonly string[] }
|
||||
type Prefix = Lines & { kind: 'prefixed' | 'quoted' }
|
||||
// The written text's measures; the flags answer for the first line unread, since reading a concatenated string copies it whole, at every level it nests.
|
||||
// Measures of the written text. The flags describe `first` so no caller reads it: reading a concatenated string copies it whole, once per nesting level.
|
||||
type Shape = { blankRest: number; emptyRest: number; first: string; firstBlank: boolean; firstCharacter: string; firstRuleCharacters: boolean; length: number; lineCount: number }
|
||||
|
||||
export const emptyLine = blockText('')
|
||||
@@ -20,7 +20,6 @@ export function blockText(text: string): BlockText {
|
||||
return { ...firstShape, blankRest, emptyRest: rest.filter((line) => line === '').length, kind: 'text', length: text.length, lineCount: rest.length + 1, lines: [first, ...rest] }
|
||||
}
|
||||
|
||||
// The parts' lines one after another.
|
||||
export function joinedText(parts: readonly BlockText[]): BlockText {
|
||||
const [first, ...others] = parts
|
||||
if (first === undefined) return emptyLine
|
||||
@@ -35,7 +34,7 @@ export function joinedText(parts: readonly BlockText[]): BlockText {
|
||||
return { blankRest, emptyRest, first: first.first, firstBlank, firstCharacter, firstRuleCharacters, kind: 'joined', length, lineCount, parts }
|
||||
}
|
||||
|
||||
// head, never blank, leads the first line, and indent, spaces alone, every later line holding text.
|
||||
// head, never blank, leads the first line; indent, spaces alone, leads every later line holding text.
|
||||
export function prefixedText(head: string, indent: string, body: BlockText): BlockText {
|
||||
const first = `${head}${body.first}`
|
||||
const length = body.length + head.length + indent.length * (body.lineCount - 1 - body.emptyRest)
|
||||
|
||||
@@ -27,7 +27,7 @@ type Emission = { carries: [NodeRange, ...NodeRange[]]; segments?: undefined } |
|
||||
|
||||
type Fallback = [NodeRange, ...NodeRange[]] | 'opening-link'
|
||||
|
||||
// How many of a pass's fallbacks it takes: `every`, or the `first` alone, which a property holds to the same line.
|
||||
// How many fallbacks one pass applies: `every`, or the `first` alone; a property checks that both write the same line.
|
||||
export type FallbacksPerPass = 'every' | 'first'
|
||||
|
||||
type InlineContext = {
|
||||
|
||||
@@ -270,7 +270,7 @@ function claimsCharacter({ container, escapings, headingCloser, inline: { text:
|
||||
}
|
||||
}
|
||||
|
||||
// Of the runs the line does not read back as written, the first emphasis run to close and every later one that gives up with it, else every highlight run: one misread emphasis pair can re-pair the delimiters after it.
|
||||
// The runs the line does not read back as written: the first emphasis run to close and each later one that gives up with it, else every misflanked highlight run. One misread emphasis pair can re-pair the delimiters after it.
|
||||
function unspellableRuns(placed: readonly PlacedSegment[], reading: InlineReading, output: string): MarkRun[] {
|
||||
const misread: MarkRun[] = []
|
||||
const misflanked: MarkRun[] = []
|
||||
@@ -287,7 +287,7 @@ function unspellableRuns(placed: readonly PlacedSegment[], reading: InlineReadin
|
||||
return misread.length > 0 ? misread : misflanked
|
||||
}
|
||||
|
||||
// The first run gives up where the reading pairs its delimiters otherwise; a later one, with the earlier ones, where it holds none of them, so their fallbacks leave its range, and a delimiter of it cannot flank.
|
||||
// The first run gives up where the reading pairs its delimiters otherwise. A later run gives up where it holds none of the earlier runs, so dropping them leaves its range alone, and one of its delimiters cannot flank.
|
||||
function givesUp(pair: EmphasisPair, latest: MarkRun | undefined, reading: InlineReading, output: string): boolean {
|
||||
if (latest === undefined) return !readAsWritten(reading, pair.opener, pair.closer, pair.delimiter.length)
|
||||
// Runs close in order, so a run holding any earlier one holds the latest.
|
||||
@@ -295,7 +295,7 @@ function givesUp(pair: EmphasisPair, latest: MarkRun | undefined, reading: Inlin
|
||||
return !mayFlank(output, pair.opener, pair.delimiter, 'open') || !mayFlank(output, pair.closer, pair.delimiter, 'close')
|
||||
}
|
||||
|
||||
// Whether the delimiter flanks once earlier runs fall back: a delimiter character beside it may fall back, while text or its own hard break stays.
|
||||
// Whether the delimiter flanks once earlier runs fall back: a delimiter character beside it may fall back, while text or the run's own hard break stays.
|
||||
function mayFlank(output: string, start: number, delimiter: string, role: DelimiterRole): boolean {
|
||||
const before = output.charAt(start - 1)
|
||||
const after = output.charAt(start + delimiter.length)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
type AlertMarker = { folded: boolean; length: number; panelType: string }
|
||||
|
||||
export const foldedAlertMarker = '[!NOTE]-'
|
||||
// Task and alert markers open with it, so a writer tests a block's first character before reading its first line, which flattens that line at every level it nests.
|
||||
// Task and alert markers open with it, so a block whose first character differs holds neither.
|
||||
export const markerOpening = '['
|
||||
|
||||
const alertWords: Readonly<Record<string, string>> = {
|
||||
|
||||
@@ -250,7 +250,7 @@ function withoutMarks(leaves: readonly AdfNode[], runs: readonly MarkRun[]): Adf
|
||||
})
|
||||
}
|
||||
|
||||
// Every misflanked highlight drops with the first run; taking `every`, so does a later emphasis run whose drop merges no run and moves no edge.
|
||||
// Every misflanked highlight drops with the first run; with `every`, so does a later emphasis run whose drop merges no run and moves no edge.
|
||||
function droppedRuns(leaves: readonly AdfNode[], [first, ...others]: readonly [MarkRun, ...MarkRun[]], perPass: FallbacksPerPass): MarkRun[] {
|
||||
return [first, ...others.filter((run) => nodeMarks(leaves[run.first] ?? {})[run.depth]?.type === highlight || (perPass === 'every' && dropsAlone(leaves, run)))]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user