3
0
mirror of https://github.com/larvit/adf-codec.git synced 2026-11-12 19:58:28 +01:00

Answer prose round 1: 0 🔴, 5 🟡; define the closer in place, and say the kept source is one per text

This commit is contained in:
2026-10-18 10:53:55 +02:00
committed by Lillem4n
parent 637fbc914c
commit 5e3f4c688c
5 changed files with 14 additions and 16 deletions
+4 -4
View File
@@ -16,10 +16,10 @@
table cell: `[alt](href) ([image](url))`, where it wrote `[alt](url)` and dropped the link's target.
- `losslessMarkdownToAdf` names the CommonMark spelling to write when it refuses a directive whose
node CommonMark spells, such as `[![alt](url)](href)` for a linked `!adf:mediaSingle`.
- Every reader and writer takes time linear in a text holding many `<!--`, `<?`, `<![CDATA[` or `<!`
openers without a terminator, or many unclosed backtick runs outside a directive's `[content]`,
where such a text took time quadratic in its length: 160000 characters of `<?` took seven seconds
each way, now 50 ms.
- Every reader and writer takes time linear in the text when it holds many `<!--`, `<?`,
`<![CDATA[` or `<!` openers without a terminator, or many unclosed backtick runs outside a
directive's `[content]`. Such a text took time quadratic in its length: 160000 characters of `<?`
took seven seconds each way, now 50 ms.
- The README compares the package with seven other ADF converters, each checked against its
published version.
+2 -3
View File
@@ -4,9 +4,8 @@ export function backtickRun(text: string, index: number): number {
return text.charAt(index) === '`' ? runLength(text, index) : 0
}
// As `closingBacktickRun`, for `from` past the end of an opener's run, with each run's start read once by its length.
// Readers ask with `from` rising, which keeps each length's cursor moving forward, so asking at every opener stays
// linear in the text; an ask behind the cursor restarts that length from its first run.
// Where the first run of exactly `opener` backticks at or after `from` begins, `from` never inside a run. Ask with
// `from` rising, so each length's cursor only moves forward and a walk stays linear; an earlier `from` rescans that length.
export function backtickCloser(text: string): (from: number, opener: number) => number | undefined {
const cursors = new Map<number, number>()
const starts = new Map<number, number[]>()
+1 -1
View File
@@ -9,7 +9,7 @@ import { losslessMarkdownToAdf } from './parse/markdown-to-adf.ts'
const constructs = ['<!A>', '<??>', '<![CDATA[]]>']
// CommonMark 0.31.2, Raw HTML: the terminator must start after the opener, and may start right after it.
// CommonMark 0.31.2, Raw HTML: the terminator may start right after the opener, never inside it; `<!-->` and `<!--->` are whole comments.
test('an HTML opener reads as HTML only where its terminator starts after it', () => {
const cases: [string, string][] = [...constructs.map((text): [string, string] => [text, 'html']), ['<!---->', 'html'], ['?> <? ?>', 'html'], ['?> <?', 'text'], ['<?>', 'text']]
for (const [text, kind] of cases) {
+2 -2
View File
@@ -18,10 +18,10 @@ export type InlineToken =
| { closes: boolean; kind: 'highlight'; opens: boolean; width: number }
| { construct: string; kind: 'html' }
// A text and what its openers look ahead for, read once, so a walk reading a token at every index stays linear in it.
// Build one per text and pass it to every `readInlineToken` call on that text, so a walk stays linear in the text's length.
export type InlineSource = {
readonly codeSpanCloser: (from: number, opener: number) => number | undefined
// Each HTML construct terminator's last start in the text, -1 for none, read the first time an opener asks.
// Where each HTML terminator last starts in the text, -1 for none; filled the first time an opener asks.
readonly terminators: Map<string, number>
readonly text: string
}
+5 -6
View File
@@ -25,7 +25,7 @@
| 59 | 0.3.0 | | decision | **Group the directive grammar into `src/markdown/directive/`, move `Read<T>` to `result.ts`, and move `Flavour` and `flavourClaims` to `markdown/flavour.ts`.** | 3 | 1 | 2 | 4 | 5 | 10 by 5 | 1.5 |
| 62 | 0.3.0 | | decision | **Move the portable flavour's reading out of `parse/` and its writing out of `emit/` into `markdown/portable/`, so `emit/` no longer imports `portable/`.** | 3 | 1 | 2 | 4 | 5 | 10 by 5 | 1.5 |
| 73 | 0.3.0 | 33, 59, 60, 62, 91, 92, 95, 98, 100, 102, 109, 115 | | **Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.** | 1 | 2 | 2 | 3 | 2 | 3 by 8 | 32.0 |
| 119 | 0.3.0 | | defect | **Read a directive's content holding many unclosed backtick runs in time linear in the text.** | 2 | 1 | 2 | 3 | 2 | 9 by 2 | 8.0 |
| 119 | 0.3.0 | | defect | **Read a directive's content holding many unclosed backtick runs in time linear in the markdown.** | 2 | 1 | 2 | 3 | 2 | 9 by 2 | 8.0 |
| 81 | 0.4.0 | | | **Fail the gate unless the README's error tables list exactly the codes `ConvertErrorCode` holds.** | 1 | 1 | 1 | 1 | 2 | 3 by 2 | 8.0 |
| 45 | 0.4.0 | | defect | **Replace `isAdfDocument` with a reader returning `Result<AdfDocument>`.** | 2 | 1 | 3 | 4 | 3 | 1 by 2 | 6.0 |
| 6 | 0.4.0 | | decision | **Specify the HTML dialect.** | 3 | 2 | 1 | 4 | 6 | | 0.0 |
@@ -167,16 +167,15 @@ posting, set `converter-comparison/run.sh`'s pins to each package's latest versi
its versions and its date in step with the output. We draft each post for the place it goes; the
maintainer posts them once `0.3.0` is published. Found while planning discoverability, 2026-10-04.
### 119. Read a directive's content holding many unclosed backtick runs in time linear in the text.
### 119. Read a directive's content holding many unclosed backtick runs in time linear in the markdown.
`readCodeSpanEnd` (`src/markdown/directive-syntax.ts`) calls `closingBacktickRun`, which searches
the rest of the text at every opener, so backtick runs of lengths 1 to k with no closers inside an
inline directive's `[content]` cost about k·n. Measured on 2026-10-18: 24 ms at 40k characters,
126 ms at 160k and 1004 ms at 640k, where the same runs outside a directive take 6, 18 and 63 ms.
The inline reader reads such runs through `backtickCloser`
(`src/markdown/commonmark/backtick-runs.ts`), kept once per text; the directive reader would need
them kept for the source it reads from. Delete `closingBacktickRun` once nothing calls it, so one
reader finds a closer.
The inline reader finds closers through one `backtickCloser` per text
(`src/markdown/commonmark/backtick-runs.ts`); `readCodeSpanEnd` needs one built for the source it
reads. Then delete `closingBacktickRun`, so one function finds every closer.
### 81. Fail the gate unless the README's error tables list exactly the codes `ConvertErrorCode` holds.