import type { OneOrMore, OneOrMoreIncluding, ZeroOrMore, } from './multiplicity-utils.js'; /** * A Web Annotation object. * * This is an interpretation of the Web Annotation Data Model: * * * TODO Deal more systemically with ‘relations’, i.e. values that could be * either a nested object or a URI referring to such an object. */ export interface WebAnnotation { '@context': OneOrMoreIncluding; type: OneOrMoreIncluding; id: string; target: OneOrMore; creator?: OneOrMore; created?: UtcDateTime; generator?: OneOrMore; generated?: UtcDateTime; modified?: UtcDateTime; motivation?: OneOrMore; audience?: ZeroOrMore; rights?: ZeroOrMore; canonical?: string; via?: ZeroOrMore; body?: BodyChoice | OneOrMore; bodyValue?: string; } /** * A slightly stricter type for WebAnnotation, not allowing both a body and bodyValue. */ export type WebAnnotationStrict = WebAnnotation & (WithBody | WithBodyValue | WithoutBody); interface WithBody { body: BodyChoice | OneOrMore; bodyValue?: undefined; } interface WithBodyValue { body?: undefined; bodyValue: string; } interface WithoutBody { body?: undefined; bodyValue?: undefined; } export type Body = string | BodyObject; export type BodyObject = { creator?: OneOrMore; created?: UtcDateTime; modified?: UtcDateTime; purpose?: OneOrMore; } & (TextualBody | SpecificResource | ExternalResource); export type Target = string | SpecificResource | ExternalResource; export type Agent = | string | { id?: string; type?: OneOrMore<'Person' | 'Organization' | 'Software'>; name?: OneOrMore; nickname?: OneOrMore; email?: OneOrMore; email_sha1?: OneOrMore; homepage?: OneOrMore; }; export type Audience = | string | { id?: string; type?: string; }; export interface BodyChoice { type: 'Choice'; items: Body[]; } export interface TextualBody extends Omit { id?: string; type: 'TextualBody'; value: string; } export interface SpecificResource { id?: string; type?: 'SpecificResource'; source: string; selector?: string | OneOrMore; accessibility?: AccessibilityFeatures; rights?: ZeroOrMore; canonical?: string; via?: ZeroOrMore; } export interface Selector { type?: string; refinedBy?: Selector; } export interface ExternalResource { id: string; // XXX type’s value SHOULD be one of these, “but MAY come from other vocabularies”. type?: OneOrMore<'Dataset' | 'Image' | 'Video' | 'Sound' | 'Text'>; format?: OneOrMore; language?: OneOrMore; processingLanguage?: string; textDirection?: 'ltr' | 'rtl' | 'auto'; accessibility?: AccessibilityFeatures; rights?: ZeroOrMore; canonical?: string; via?: ZeroOrMore; } export type Motivation = | 'assessing' | 'bookmarking' | 'classifying' | 'commenting' | 'describing' | 'editing' | 'highlighting' | 'identifying' | 'linking' | 'moderating' | 'questioning' | 'replying' | 'tagging'; // “The datetime MUST be a xsd:dateTime with the UTC timezone expressed as "Z".” type UtcDateTime = `${string}Z`; declare global { interface Date { toISOString(): UtcDateTime; } } // From export type AccessibilityFeatures = | ZeroOrMore | 'none' | ['none']; export type AccessibilityFeature = | 'annotations' | 'ARIA' | 'bookmarks' | 'index' | 'printPageNumbers' | 'readingOrder' | 'structuralNavigation' | 'tableOfContents' | 'taggedPDF' | 'alternativeText' | 'audioDescription' | 'captions' | 'describedMath' | 'longDescription' | 'rubyAnnotations' | 'signLanguage' | 'transcript' | 'displayTransformability' | 'synchronizedAudioText' | 'timingControl' | 'unlocked' | 'ChemML' | 'latex' | 'MathML' | 'ttsMarkup' | 'highContrastAudio' | 'highContrastDisplay' | 'largePrint' | 'braille' | 'tactileGraphic' | 'tactileObject';