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';