48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import type { JsonValue } from '../json-value.ts'
|
|
import type { VocabularyPair } from '../adf/attribute-vocabulary.ts'
|
|
import { serializeCanonicalJson } from '../canonical-json.ts'
|
|
|
|
const bareToken = /^[A-Za-z0-9_-]+$/
|
|
const inlineDirectiveOpener = /:[a-z][A-Za-z0-9]*[[{]/y
|
|
|
|
// spec/flavour.md, Attributes.
|
|
const quotedEscapes = /[&<`|]/g
|
|
|
|
export function isBareToken(text: string): boolean {
|
|
return bareToken.test(text)
|
|
}
|
|
|
|
export function opensInlineDirective(text: string, index: number): boolean {
|
|
inlineDirectiveOpener.lastIndex = index
|
|
return inlineDirectiveOpener.test(text)
|
|
}
|
|
|
|
export function spellAttributes(pairs: readonly (readonly [string, string])[]): string {
|
|
if (pairs.length === 0) return ''
|
|
const spelled = [...pairs].sort(([left], [right]) => (left < right ? -1 : 1)).map(([key, value]) => `${key}=${value}`)
|
|
return `{${spelled.join(' ')}}`
|
|
}
|
|
|
|
export function spellVocabulary(pairs: readonly VocabularyPair[]): [string, string][] {
|
|
return pairs.map((pair): [string, string] => [pair.key, spellAttributeValue(pair)])
|
|
}
|
|
|
|
export function spellJsonAttribute(value: JsonValue): string {
|
|
return quote(serializeCanonicalJson(value, 'compact'))
|
|
}
|
|
|
|
export function spellStringAttribute(text: string): string {
|
|
return isBareToken(text) ? text : quote(text)
|
|
}
|
|
|
|
function spellAttributeValue(pair: VocabularyPair): string {
|
|
if (pair.kind === 'boolean') return `${pair.value}`
|
|
if (pair.kind === 'json') return spellJsonAttribute(pair.value)
|
|
if (pair.kind === 'number') return spellStringAttribute(JSON.stringify(pair.value))
|
|
return spellStringAttribute(pair.value)
|
|
}
|
|
|
|
function quote(text: string): string {
|
|
return JSON.stringify(text).replace(quotedEscapes, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`)
|
|
}
|