import type { DirectiveAttributes, DirectiveValue, Read } from './directive-syntax.ts' import type { EmptyKey } from '../adf/document.ts' import { emptyKeys } from '../adf/document.ts' import { unsupportedNodeShape } from './directive-syntax.ts' type EmptyKeysRead = { empty: ReadonlySet; rest: Map } const emptyValue = 'empty' // spec/flavour.md, Attributes: no attribute value spells an empty object or array. export function spellEmptyKeys(held: Parameters[0]): [string, string][] { return emptyKeys(held).map((key) => [key, emptyValue]) } export function spellsEmpty(value: DirectiveValue | undefined): boolean { return value?.spelling === emptyValue } // `held` is whether the directive spells an attribute outside {attrs}: an argument or a content slot. export function readEmptyKeys(type: string, attributes: DirectiveAttributes, keys: readonly EmptyKey[], held: boolean): Read { const rest = new Map(attributes) const empty = new Set() for (const key of keys) { const spelled = rest.get(key) if (spelled === undefined) continue if (!spellsEmpty(spelled)) return { fault: unsupportedNodeShape(`the reserved key ${key} reads ${key}=${emptyValue} alone: this one spells ${key}=${spelled.spelling}`) } empty.add(key) rest.delete(key) } if (empty.has('attrs') && (held || [...rest.keys()].some((key) => key !== 'marks'))) return { fault: unsupportedNodeShape(`${type} spells attrs=empty beside an attribute it holds`) } return { value: { empty, rest } } }