Answer the architecture pass: the seam attribute reading names, and the speller a third file copied
CI / gate (push) Successful in 8s
CI / gate (push) Successful in 8s
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import type { AdfAttributes } from '../../adf/document.ts'
|
||||
import type { AttributeVocabulary } from '../../adf/attribute-vocabulary.ts'
|
||||
import type { DirectiveAttributes } from '../directive-syntax.ts'
|
||||
import { attributeValue, spellAttributeValue } from '../directive-syntax.ts'
|
||||
import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
||||
|
||||
export type Elsewhere = { key: string; slot: 'argument' | 'content' }
|
||||
|
||||
export function readVocabulary(
|
||||
type: string,
|
||||
attributes: DirectiveAttributes,
|
||||
vocabulary: AttributeVocabulary,
|
||||
elsewhere: Elsewhere | undefined,
|
||||
path: ConvertErrorPath,
|
||||
): Result<AdfAttributes> {
|
||||
const attrs: AdfAttributes = {}
|
||||
for (const [key, spelled] of attributes) {
|
||||
if (key === elsewhere?.key) {
|
||||
const place = elsewhere.slot === 'argument' ? 'as the directive argument' : 'in the content slot'
|
||||
return failure('unsupported-node-shape', `${type} spells its ${key} attribute ${place}`, path)
|
||||
}
|
||||
const kind = Object.hasOwn(vocabulary, key) ? vocabulary[key] : undefined
|
||||
if (kind === undefined) return failure('unsupported-node-shape', `${type} holds no ${key} attribute`, path)
|
||||
const read = attributeValue(spelled.decoded, kind)
|
||||
if (read === undefined) return failure('unsupported-node-shape', `the ${key} attribute of ${type} is no ${kind}`, path)
|
||||
const spelling = spellAttributeValue(read)
|
||||
if (spelling !== spelled.spelling) return failure('unsupported-node-shape', `${type} spells its ${key} attribute as ${key}=${spelling}`, path)
|
||||
attrs[key] = read.value
|
||||
}
|
||||
return success(attrs)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import type { DirectiveAttributes } from '../directive-syntax.ts'
|
||||
import type { MarkSpelling } from '../mark-spellings.ts'
|
||||
import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
||||
import { markSpelling } from '../mark-spellings.ts'
|
||||
import { readVocabulary } from './directive-nodes.ts'
|
||||
import { readVocabulary } from './directive-attributes.ts'
|
||||
|
||||
export function readDirectiveMark(name: string, attributes: DirectiveAttributes, path: ConvertErrorPath): Result<AdfMark> | undefined {
|
||||
const spelling = markSpelling(name)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AdfAttributes, AdfMark, AdfNode } from '../../adf/document.ts'
|
||||
import type { AttributeVocabulary } from '../../adf/attribute-vocabulary.ts'
|
||||
import type { BlockDirective } from '../../adf/block-directives.ts'
|
||||
import type { DirectiveAttributes, DirectiveValue } from '../directive-syntax.ts'
|
||||
import type { Elsewhere } from './directive-attributes.ts'
|
||||
import { attributeValue, spellAttributeValue, unknownDirectiveFault } from '../directive-syntax.ts'
|
||||
import { blockArgument } from '../block-directive-arguments.ts'
|
||||
import { blockDirective } from '../../adf/block-directives.ts'
|
||||
@@ -9,11 +9,10 @@ import { carryName } from '../opaque-carry.ts'
|
||||
import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
||||
import { inlineDirective } from '../../adf/inline-directives.ts'
|
||||
import { marksAttribute, readMarkValues } from '../block-directive-marks.ts'
|
||||
import { readVocabulary } from './directive-attributes.ts'
|
||||
|
||||
export type BlockDirectiveNode = { contentModel: BlockDirective['contentModel']; node: AdfNode }
|
||||
|
||||
type Elsewhere = { key: string; slot: 'argument' | 'content' }
|
||||
|
||||
export function readBlockDirectiveNode(
|
||||
name: string,
|
||||
argument: string | undefined,
|
||||
@@ -70,30 +69,6 @@ function slotText(content: readonly AdfNode[]): string | undefined {
|
||||
return only.text
|
||||
}
|
||||
|
||||
export function readVocabulary(
|
||||
type: string,
|
||||
attributes: DirectiveAttributes,
|
||||
vocabulary: AttributeVocabulary,
|
||||
elsewhere: Elsewhere | undefined,
|
||||
path: ConvertErrorPath,
|
||||
): Result<AdfAttributes> {
|
||||
const attrs: AdfAttributes = {}
|
||||
for (const [key, spelled] of attributes) {
|
||||
if (key === elsewhere?.key) {
|
||||
const place = elsewhere.slot === 'argument' ? 'as the directive argument' : 'in the content slot'
|
||||
return failure('unsupported-node-shape', `${type} spells its ${key} attribute ${place}`, path)
|
||||
}
|
||||
const kind = Object.hasOwn(vocabulary, key) ? vocabulary[key] : undefined
|
||||
if (kind === undefined) return failure('unsupported-node-shape', `${type} holds no ${key} attribute`, path)
|
||||
const read = attributeValue(spelled.decoded, kind)
|
||||
if (read === undefined) return failure('unsupported-node-shape', `the ${key} attribute of ${type} is no ${kind}`, path)
|
||||
const spelling = spellAttributeValue(read)
|
||||
if (spelling !== spelled.spelling) return failure('unsupported-node-shape', `${type} spells its ${key} attribute as ${key}=${spelling}`, path)
|
||||
attrs[key] = read.value
|
||||
}
|
||||
return success(attrs)
|
||||
}
|
||||
|
||||
function readMarks(type: string, spelled: DirectiveValue, path: ConvertErrorPath): Result<AdfMark[]> {
|
||||
const read = attributeValue(spelled.decoded, 'json')
|
||||
const marks = read === undefined || spellAttributeValue(read) !== spelled.spelling ? undefined : readMarkValues(read.value)
|
||||
|
||||
@@ -697,6 +697,9 @@ test('names the content slot no one unmarked text node reads back from', () => {
|
||||
assert.equal(code(markdownToAdf(':status[:date{timestamp=1}]{color=yellow}\n')), 'unsupported-node-shape')
|
||||
assert.equal(content(markdownToAdf(':status[]{color=yellow}\n')), 'unmappable-image: an image fits only as a paragraph of its own')
|
||||
assert.equal(code(markdownToAdf(':status[<div>]{color=yellow}\n')), 'unmappable-html')
|
||||
// The slot parses before the name's table is consulted, so a doubly-broken span reports its inner error.
|
||||
assert.equal(code(markdownToAdf(':date[<div>]{timestamp=1}\n')), 'unmappable-html')
|
||||
assert.equal(code(markdownToAdf(':widget[<div>]\n')), 'unmappable-html')
|
||||
assert.equal(content(markdownToAdf('Part :mention{id=b1c2 text=A}.\n')), 'unsupported-node-shape: mention spells its text attribute in the content slot')
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user