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

Answer architecture round 2: rename isBareText to isSpellableText, say which link holdsLink counts, the README names the type passed

This commit is contained in:
2026-10-05 09:32:11 +02:00
committed by Lillem4n
parent 41ac4510f5
commit a62cd39809
7 changed files with 15 additions and 16 deletions
+3 -3
View File
@@ -66,12 +66,12 @@ export function emptyKeys(held: { attrs?: AdfAttributes; content?: AdfNode[]; ma
}
// No attrs, content or empty marks; a format may spell this node as text, and anything more rides a carry.
export function isBareText(node: AdfNode): boolean {
export function isSpellableText(node: AdfNode): boolean {
return node.type === 'text' && node.attrs === undefined && node.content === undefined && node.marks?.length !== 0
}
export function isUnmarkedBareText(node: AdfNode): boolean {
return isBareText(node) && node.marks === undefined
export function isUnmarkedSpellableText(node: AdfNode): boolean {
return isSpellableText(node) && node.marks === undefined
}
export function identicalMark(left: AdfMark, right: AdfMark): boolean {
+2 -2
View File
@@ -1,5 +1,5 @@
import type { AdfNode } from '../adf/document.ts'
import { identicalMarks, isBareText, nodeMarks } from '../adf/document.ts'
import { identicalMarks, isSpellableText, nodeMarks } from '../adf/document.ts'
import { spellInlineLeafDirective } from './directive-syntax.ts'
export const textBreakName = 'textBreak'
@@ -8,5 +8,5 @@ export const textBreakSpelling = spellInlineLeafDirective(textBreakName, '')
// The lossless reader's rule: CommonMark reads the pair back as one text run (spec/flavour.md, Inline nodes).
export function joinsWhenRead(previous: AdfNode, node: AdfNode): boolean {
return isBareText(previous) && isBareText(node) && identicalMarks(nodeMarks(previous), nodeMarks(node))
return isSpellableText(previous) && isSpellableText(node) && identicalMarks(nodeMarks(previous), nodeMarks(node))
}
+2 -2
View File
@@ -1,7 +1,7 @@
import type { AdfDocument, AdfNode } from '../../adf/document.ts'
import type { BlockNodeModel } from '../../adf/block-nodes.ts'
import type { Flavour } from '../plain/conventions.ts'
import { adfDocumentFault, holdsOnlyAttributes, isUnmarkedBareText, nodeAttrs, nodeContent } from '../../adf/document.ts'
import { adfDocumentFault, holdsOnlyAttributes, isUnmarkedSpellableText, nodeAttrs, nodeContent } from '../../adf/document.ts'
import { alertMarker, foldedAlertMarker, leadingMarker, readAlertMarker, readTaskMarker, taskMarker } from '../plain/conventions.ts'
import { blockDirectiveForm, documentSpelling, listBreakSpelling } from '../block-directive.ts'
import { blockNodeModel, blockNodes } from '../../adf/block-nodes.ts'
@@ -277,7 +277,7 @@ function fencedTexts(node: AdfNode): string[] | undefined {
if (node.content === undefined) return ['']
const texts: string[] = []
for (const child of node.content) {
if (!isUnmarkedBareText(child) || typeof child.text !== 'string' || child.text === '' || /\r/.test(child.text) || holdsNullCharacter(child.text)) return undefined
if (!isUnmarkedSpellableText(child) || typeof child.text !== 'string' || child.text === '' || /\r/.test(child.text) || holdsNullCharacter(child.text)) return undefined
texts.push(child.text)
}
return texts
+4 -4
View File
@@ -9,7 +9,7 @@ import { escapeUnbalanced, spellDestination } from '../commonmark/link-syntax.ts
import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts'
import { highlightDelimiter } from '../plain/conventions.ts'
import { holdsNullCharacter, trimTrailingSpace } from '../commonmark/grammar.ts'
import { identicalMark, isBareText, nodeAttrs, nodeContent, nodeMarks } from '../../adf/document.ts'
import { identicalMark, isSpellableText, nodeAttrs, nodeContent, nodeMarks } from '../../adf/document.ts'
import { inlineNodeModel } from '../../adf/inline-nodes.ts'
import { joinsWhenRead, textBreakSpelling } from '../adjacent-text.ts'
import { largestNesting } from '../../nesting.ts'
@@ -220,7 +220,7 @@ function nodePath(context: InlineContext, index: number): ConvertErrorPath {
// Decides the text-node and slot-fault carries up front, so a line holding many of them is emitted once.
function carries(node: AdfNode, carried: ReadonlySet<number>, index: number): boolean {
if (carried.has(index)) return true
if (node.type === 'text') return !isBareText(node) || typeof node.text !== 'string' || node.text === ''
if (node.type === 'text') return !isSpellableText(node) || typeof node.text !== 'string' || node.text === ''
const model = inlineNodeModel(node.type)
if (model === undefined) return true
const slot = model.textAttribute === undefined ? undefined : nodeAttrs(node)[model.textAttribute]
@@ -265,7 +265,7 @@ function emitInlineDirective(node: AdfNode, model: InlineNodeModel, index: numbe
// CommonMark reads a raw carriage return as a line ending and a null character as U+FFFD, so neither is written raw.
function emitText(node: AdfNode, context: InlineContext, index: number): Emission {
if (!isBareText(node) || typeof node.text !== 'string' || node.text === '') return { carry: { first: index, last: index } }
if (!isSpellableText(node) || typeof node.text !== 'string' || node.text === '') return { carry: { first: index, last: index } }
const escaping: InlineEscaping = context.bracketed ? 'bracketed' : 'backslash'
const parts = node.text.split(/(\n+|\0+|\r)/).filter((part) => part !== '')
return { segments: parts.map((part) => (part === '\r' ? syntax('&#13;') : /^[\n\0]/.test(part) ? textDirectiveSegment(part) : { escaping, text: part })) }
@@ -316,7 +316,7 @@ function emitCodeSpan(nodes: readonly AdfNode[], depth: number, range: NodeRange
const spans: string[] = []
for (const node of nodes) {
const { text } = node
if (!isBareText(node) || nodeMarks(node).length !== depth + 1 || typeof text !== 'string' || text === '' || /[\n\r]/.test(text) || holdsNullCharacter(text)) return { carry: range }
if (!isSpellableText(node) || nodeMarks(node).length !== depth + 1 || typeof text !== 'string' || text === '' || /[\n\r]/.test(text) || holdsNullCharacter(text)) return { carry: range }
const fence = '`'.repeat(longestBacktickRun(text) + 1)
spans.push(`${fence}${needsPadding(text) ? ` ${text} ` : text}${fence}`)
}
+2 -2
View File
@@ -3,7 +3,7 @@ import type { BlockNodeModel } from '../../adf/block-nodes.ts'
import type { ConvertFault } from '../../result.ts'
import type { DirectiveAttributes, DirectiveValue } from '../directive-syntax.ts'
import type { Elsewhere } from './directive-attributes.ts'
import { attributeNestingMessage, isUnmarkedBareText } from '../../adf/document.ts'
import { attributeNestingMessage, isUnmarkedSpellableText } from '../../adf/document.ts'
import { attributeValue, directivePrefix, spellAttributeValue, unknownDirectiveFault } from '../directive-syntax.ts'
import { blockArgument, blockDirectiveForm, marksAttribute, readMarkValues } from '../block-directive.ts'
import { blockNodeModel } from '../../adf/block-nodes.ts'
@@ -92,7 +92,7 @@ function blockSpellingFault(name: string): ConvertFault | undefined {
function slotText(content: readonly AdfNode[]): string | undefined {
if (content.length === 0) return ''
const only = content.length === 1 ? content[0] : undefined
if (only === undefined || !isUnmarkedBareText(only) || typeof only.text !== 'string') return undefined
if (only === undefined || !isUnmarkedSpellableText(only) || typeof only.text !== 'string') return undefined
return only.text
}
+1 -2
View File
@@ -327,7 +327,6 @@ function isTextBreak(item: Inline): item is TextBreak {
return 'kind' in item && item.kind === 'textBreak'
}
// The nodes the items hold, with text breaks dropped.
function adfNodes(items: readonly Inline[]): AdfNode[] {
const nodes: AdfNode[] = []
for (const item of items) {
@@ -345,7 +344,7 @@ function holdsImage(pieces: readonly Piece[]): boolean {
return pieces.some((piece) => piece.kind === 'image')
}
// A node whose marks are its own rides its own piece, its marks restoring with it rather than riding a spelling, so the guard below answers for it.
// An `ownMarks` piece restores its link with its node, so only a link a `nodes` piece spells counts.
function holdsLink(pieces: readonly Piece[]): boolean {
return pieces.some((piece) => piece.kind === 'nodes' && marksLink(piece.nodes))
}