mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-14 04:30:24 +01:00
Read an image alone on an alert's marker line or the lines after it as the image, as a reader panel expected; item 88 filed
This commit is contained in:
@@ -20,10 +20,12 @@ import { readBlockDirectiveNode } from './directive-nodes.ts'
|
||||
import { spellStringAttribute, unsupportedNodeShape } from '../directive-syntax.ts'
|
||||
import { spellsEmpty } from '../empty-keys.ts'
|
||||
|
||||
// A paragraph a marker opens: it shares its markdown paragraph with the marker, so no image there stands alone.
|
||||
type MarkerParagraph = { kind: 'markerParagraph'; position: SourcePosition; text: string }
|
||||
type Paragraph = Extract<Block, { kind: 'paragraph' }>
|
||||
|
||||
type ReadBlock = Block | MarkerParagraph
|
||||
// The paragraph a task marker opens: a task item holds no image, so a lone one there reads as its linked alt text.
|
||||
type TaskParagraph = { kind: 'taskParagraph'; position: SourcePosition; text: string }
|
||||
|
||||
type ReadBlock = Block | TaskParagraph
|
||||
|
||||
// `inExpand` is whether an expand holds the blocks, which makes a folded callout a nestedExpand.
|
||||
type Reading = { claims: Claims; definitions: LinkDefinitions; inExpand: boolean; memo: SpellingMemo }
|
||||
@@ -123,8 +125,6 @@ function readBlock(block: ReadBlock, reading: Reading, path: ConvertErrorPath, d
|
||||
return contentNode({ attrs: { level: block.level }, type: 'heading' }, block.text, reading, path, 'heading')
|
||||
case 'html':
|
||||
return failure('unmappable-html', `no raw HTML converts at this version: ${block.construct}`, path)
|
||||
case 'markerParagraph':
|
||||
return contentNode({ type: 'paragraph' }, block.text, reading, path, 'paragraph')
|
||||
case 'orderedList':
|
||||
return listNode({ attrs: { order: block.start }, type: 'orderedList' }, block.items, reading, path, depth)
|
||||
case 'paragraph':
|
||||
@@ -133,6 +133,8 @@ function readBlock(block: ReadBlock, reading: Reading, path: ConvertErrorPath, d
|
||||
return success({ type: 'rule' })
|
||||
case 'table':
|
||||
return tableNode(block.rows, reading, path)
|
||||
case 'taskParagraph':
|
||||
return contentNode({ type: 'paragraph' }, block.text, reading, path, 'paragraph')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +151,9 @@ function markerLine(text: string): { line: string; rest: string } {
|
||||
return { line: (hardBreak ? line.slice(0, -1) : line).replace(/^[ \t]+/, ''), rest: lineEnd === -1 ? '' : text.slice(lineEnd + 1) }
|
||||
}
|
||||
|
||||
function markerParagraphs(position: SourcePosition, ...texts: string[]): MarkerParagraph[] {
|
||||
return texts.filter((text) => text !== '').map((text) => ({ kind: 'markerParagraph', position, text }))
|
||||
// docs/decisions.md, An image reads as an image only alone in its paragraph: an alert's marker line stands apart from the lines after it.
|
||||
function paragraphsOf(position: SourcePosition, ...texts: string[]): Paragraph[] {
|
||||
return texts.filter((text) => text !== '').map((text) => ({ kind: 'paragraph', position, text }))
|
||||
}
|
||||
|
||||
function quoteNode(blocks: readonly Block[], reading: Reading, path: ConvertErrorPath, depth: number): Result<AdfNode> {
|
||||
@@ -159,12 +162,12 @@ function quoteNode(blocks: readonly Block[], reading: Reading, path: ConvertErro
|
||||
if (led === undefined) return containerNode({ type: 'blockquote' }, blocks, reading, path, depth)
|
||||
const { folded, panelType } = led.marker
|
||||
const { line, rest } = markerLine(led.text)
|
||||
if (!folded) return filledNode({ attrs: { panelType }, type: 'panel' }, readBlocks([...markerParagraphs(led.position, line, rest), ...body], reading, path, depth + 1))
|
||||
if (!folded) return filledNode({ attrs: { panelType }, type: 'panel' }, readBlocks([...paragraphsOf(led.position, line, rest), ...body], reading, path, depth + 1))
|
||||
const title = parseInlineContent(line, reading.definitions, path, 'paragraph', reading.claims)
|
||||
if (!title.ok) return title
|
||||
const text = titleText(title.value.nodes)
|
||||
const type = reading.inExpand ? 'nestedExpand' : 'expand'
|
||||
return filledNode(text === '' ? { type } : { attrs: { title: text }, type }, readBlocks([...markerParagraphs(led.position, rest), ...body], { ...reading, inExpand: true }, path, depth + 1))
|
||||
return filledNode(text === '' ? { type } : { attrs: { title: text }, type }, readBlocks([...paragraphsOf(led.position, rest), ...body], { ...reading, inExpand: true }, path, depth + 1))
|
||||
}
|
||||
|
||||
// docs/decisions.md, A callout title keeps its link targets.
|
||||
@@ -203,7 +206,9 @@ function bulletNode(items: readonly Block[][], reading: Reading, path: ConvertEr
|
||||
}
|
||||
const tasks: AdfNode[] = []
|
||||
for (const [index, { marker, others, position, text }] of led.entries()) {
|
||||
const read = readBlocks([...markerParagraphs(position, text.replace(/^(?:[ \t\n]|\\\n)+/, '')), ...others], reading, [...path, 'content', index], depth + 1)
|
||||
const body = text.replace(/^(?:[ \t\n]|\\\n)+/, '')
|
||||
const marked: TaskParagraph[] = body === '' ? [] : [{ kind: 'taskParagraph', position, text: body }]
|
||||
const read = readBlocks([...marked, ...others], reading, [...path, 'content', index], depth + 1)
|
||||
if (!read.ok) return read
|
||||
let beside = read.value.length
|
||||
while (read.value[beside - 1]?.type === 'taskList') beside -= 1
|
||||
|
||||
@@ -231,12 +231,15 @@ test('reads what CommonMark reads where no row reads, a directive and a carry fe
|
||||
assert.deepEqual(read('a !adf:carry{json="{}"} \\!adf:x\n'), [said('a !adf:carry{json="{}"} !adf:x')])
|
||||
assert.deepEqual(read('```adf:blockCard\n{}\n```\n'), [node('codeBlock', { language: 'adf:blockCard' }, text('{}'))])
|
||||
const linked = paragraph(text('a', { attrs: { href: 'u' }, type: 'link' }))
|
||||
assert.deepEqual(read('> [!tip] \n'), [panel('tip', linked)])
|
||||
assert.deepEqual(read('> [!tip]\n> \n'), [panel('tip', linked)])
|
||||
const image = node('mediaSingle', { layout: 'center' }, { attrs: { alt: 'a', type: 'external', url: 'u' }, type: 'media' })
|
||||
assert.deepEqual(read('> [!tip] \n'), [panel('tip', image)])
|
||||
assert.deepEqual(read('> [!tip]\n> \n'), [panel('tip', image)])
|
||||
assert.deepEqual(read('> [!tip]\n>\n> \n'), [panel('tip', image)])
|
||||
assert.deepEqual(read('> [!tip]\n>  b\n'), [panel('tip', paragraph(...(linked.content ?? []), text(' b')))])
|
||||
assert.deepEqual(read('> [!NOTE]- t\n> \n'), [node('expand', { title: 't' }, image)])
|
||||
assert.deepEqual(read('> [!NOTE]- \n'), [node('expand', { title: 'a (u)' }, paragraph())])
|
||||
assert.deepEqual(read('> [!NOTE]- t\n> \n'), [node('expand', { title: 't' }, linked)])
|
||||
assert.deepEqual(read('- [x] \n'), [bare('taskList', task('DONE', ...(linked.content ?? [])))])
|
||||
assert.deepEqual(read('> [!tip]\n>\n> \n'), [panel('tip', node('mediaSingle', { layout: 'center' }, { attrs: { alt: 'a', type: 'external', url: 'u' }, type: 'media' }))])
|
||||
assert.deepEqual(read('- [x]\n \n'), [bare('taskList', task('DONE', ...(linked.content ?? [])))])
|
||||
let deep = 'x\n'
|
||||
for (let level = 0; level < largestNesting; level += 1) deep = `> ${deep}`
|
||||
assert.equal(typeof read(deep), 'object')
|
||||
|
||||
Reference in New Issue
Block a user