Answer the stability pass: the strip that changed nothing, and the words the body earns
CI / gate (push) Successful in 8s
CI / gate (push) Successful in 8s
This commit is contained in:
@@ -5,7 +5,7 @@ import { holdsEntityReference } from './entity-references.ts'
|
||||
|
||||
export type LanguageSlot = { info: string; kind: 'fence' } | { kind: 'attribute' } | { kind: 'none' }
|
||||
|
||||
// spec/flavour.md, The CommonMark blocks: the one slot a codeBlock's language rides, both directions.
|
||||
// spec/flavour.md, The CommonMark blocks: the one slot a codeBlock's language rides.
|
||||
export function languageSlot(language: JsonValue | undefined): LanguageSlot {
|
||||
if (language === undefined) return { kind: 'none' }
|
||||
if (typeof language !== 'string' || language === '' || language === carryName) return { kind: 'attribute' }
|
||||
|
||||
@@ -60,7 +60,7 @@ const firstCharacterOpeners = [atxHeadingOpener, /^>/, bulletListOpener, codeFen
|
||||
const emailNameSource = "[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+"
|
||||
const emailLabelSource = '[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?'
|
||||
const emailAutolink = new RegExp(`<${emailNameSource}@${emailLabelSource}(?:\\.${emailLabelSource})*>`, 'y')
|
||||
const orderedListOpener = /^(\d{1,9})([.)])(?:[ \t]|$)/
|
||||
const orderedListOpener = /^(\d{1,9})(?:[.)])(?:[ \t]|$)/
|
||||
const setextUnderline = /^(=+|-+)[ \t]*$/
|
||||
const thematicBreak = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/
|
||||
const unicodeWhitespace = /[\t\n\f\r \p{Zs}]/u
|
||||
|
||||
@@ -6,8 +6,8 @@ import { carriesOnly, isAdfDocument } from '../../adf/document.ts'
|
||||
import { emitInlineLine } from './inline-line.ts'
|
||||
import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
||||
import { fencedCodeBlock } from '../backtick-runs.ts'
|
||||
import { languageSlot } from '../code-language.ts'
|
||||
import { holdsNullCharacter, isThematicBreak, markerInterruptsParagraph } from '../commonmark-grammar.ts'
|
||||
import { languageSlot } from '../code-language.ts'
|
||||
import { largestNesting } from '../../nesting.ts'
|
||||
import { spellDirectiveHeader } from './block-directive-spelling.ts'
|
||||
import { tryImage } from './image.ts'
|
||||
|
||||
@@ -383,7 +383,6 @@ function closeLeaf(walk: Walk): void {
|
||||
else currentBlocks(walk).push({ kind: 'code', language: leaf.kind === 'fenced-code' ? decodeTextEscapes(leaf.info) : '', text: leaf.lines.join('\n') })
|
||||
}
|
||||
|
||||
// spec/flavour.md, Tables: the delimiter row underlines the header and leaves the body its cell count.
|
||||
function pipeTableBlock(rows: readonly [string[], ...string[][]]): Block {
|
||||
const [header, delimiter, ...body] = rows
|
||||
if (delimiter !== undefined && delimiter.some(isPipeAlignment)) {
|
||||
|
||||
@@ -135,6 +135,9 @@ test('reads the codeBlock directive body as the node content, the info string it
|
||||
assert.deepEqual(content(markdownToAdf(':::codeBlock {language=""}\n```\nx\n```\n:::\n')), [
|
||||
{ attrs: { language: '' }, content: [text('x')], type: 'codeBlock' },
|
||||
])
|
||||
assert.deepEqual(content(markdownToAdf(':::codeBlock {wrap=true}\n fn()\n:::\n')), [
|
||||
{ attrs: { wrap: true }, content: [text('fn()')], type: 'codeBlock' },
|
||||
])
|
||||
// The body is a CommonMark fence, so its info string decodes escapes the way any other fence's does.
|
||||
assert.deepEqual(content(markdownToAdf(':::codeBlock {wrap=true}\n```\\#c\nx\n```\n:::\n')), [
|
||||
{ attrs: { language: '#c', wrap: true }, content: [text('x')], type: 'codeBlock' },
|
||||
@@ -305,7 +308,7 @@ test('names the argument and the body a node takes no reading for', () => {
|
||||
assert.equal(content(markdownToAdf(':::paragraph\n:::\n')), 'unsupported-node-shape: an empty paragraph takes the leaf form, ::')
|
||||
assert.equal(content(markdownToAdf(':::paragraph\nOne.\n\nTwo.\n:::\n')), 'unsupported-node-shape: paragraph takes one paragraph as its body')
|
||||
assert.equal(content(markdownToAdf(':::paragraph\n---\n:::\n')), 'unsupported-node-shape: paragraph takes one paragraph as its body')
|
||||
assert.equal(content(markdownToAdf(':::codeBlock {wrap=true}\nx\n:::\n')), 'unsupported-node-shape: codeBlock takes one fenced code block as its body')
|
||||
assert.equal(content(markdownToAdf(':::codeBlock {wrap=true}\nx\n:::\n')), 'unsupported-node-shape: codeBlock takes one code block as its body')
|
||||
assert.equal(content(markdownToAdf(':::paragraph\n\n:::\n')), 'unmappable-image: no ADF node carries an image inside a paragraph')
|
||||
assert.equal(content(markdownToAdf('Part :date[now]{timestamp=1}.\n')), 'unsupported-node-shape: date takes no content')
|
||||
assert.equal(
|
||||
@@ -392,6 +395,7 @@ test('reads a bullet list, the marker width setting the continuation', () => {
|
||||
assert.deepEqual(content(markdownToAdf('- a\n\n+ b\n')), [bulletList(item(paragraph('a')), item(paragraph('b')))])
|
||||
assert.deepEqual(content(markdownToAdf('- a\n-\n\n- c\n')), [bulletList(item(paragraph('a')), item(), item(paragraph('c')))])
|
||||
assert.deepEqual(content(markdownToAdf('- a\n1. b\n')), [bulletList(item(paragraph('a'))), orderedList(1, item(paragraph('b')))])
|
||||
assert.deepEqual(content(markdownToAdf('- a\n\n[r]: /u\n\n- b\n')), [bulletList(item(paragraph('a')), item(paragraph('b')))])
|
||||
assert.deepEqual(content(markdownToAdf('-\n\n Part.\n')), [bulletList(item()), paragraph('Part.')])
|
||||
})
|
||||
|
||||
|
||||
@@ -79,10 +79,9 @@ function directiveBody(read: BlockDirectiveNode, blocks: Block[] | undefined, de
|
||||
return inlineBodyNode(node, blocks, definitions, path)
|
||||
}
|
||||
|
||||
// spec/flavour.md, The CommonMark blocks: the language rides the one slot fenceInfo picks for it.
|
||||
function codeDirectiveNode(node: AdfNode, blocks: readonly Block[], path: ConvertErrorPath): Result<AdfNode> {
|
||||
const only = blocks.length === 1 ? blocks[0] : undefined
|
||||
if (only?.kind !== 'code') return failure('unsupported-node-shape', `${node.type} takes one fenced code block as its body`, path)
|
||||
if (only?.kind !== 'code') return failure('unsupported-node-shape', `${node.type} takes one code block as its body`, path)
|
||||
const attribute = node.attrs?.['language']
|
||||
const fromFence = only.language !== ''
|
||||
const slot = languageSlot(fromFence ? only.language : attribute)
|
||||
|
||||
@@ -19,22 +19,21 @@ export function malformedPipeTable(message: string): ConvertFault {
|
||||
// spec/flavour.md, Tables: the cells of a claimed row, the closing `|` the spelling writes optional here.
|
||||
export function pipeCells(line: string): string[] | undefined {
|
||||
if (!claimsPipeLine(line)) return undefined
|
||||
const row = line.replace(/[ \t]+$/, '')
|
||||
const cells: string[] = []
|
||||
let start = 1
|
||||
let index = 1
|
||||
while (index < row.length) {
|
||||
if (backslashEscape(row, index) !== undefined) {
|
||||
while (index < line.length) {
|
||||
if (backslashEscape(line, index) !== undefined) {
|
||||
index += 2
|
||||
continue
|
||||
}
|
||||
if (row.charAt(index) === '|') {
|
||||
cells.push(trimSpace(row.slice(start, index)))
|
||||
if (line.charAt(index) === '|') {
|
||||
cells.push(trimSpace(line.slice(start, index)))
|
||||
start = index + 1
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
cells.push(trimSpace(row.slice(start)))
|
||||
cells.push(trimSpace(line.slice(start)))
|
||||
if (cells.length > 1 && cells.at(-1) === '') cells.pop()
|
||||
return cells
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user