@xats-org/types
Version:
Shared TypeScript types for xats
496 lines (421 loc) • 11.7 kB
text/typescript
/**
* Rendering and presentation types for xats
*/
import type { XatsDocument } from './document.js';
/**
* Options for configuring document rendering
*/
export interface RendererOptions {
theme?: string;
cssClasses?: CssClasses;
includeTableOfContents?: boolean;
includeBibliography?: boolean;
includeIndex?: boolean;
mathRenderer?: 'mathjax' | 'katex' | 'none';
syntaxHighlighter?: 'prism' | 'highlight.js' | 'none';
locale?: string;
dir?: 'ltr' | 'rtl' | 'auto';
accessibilityMode?: boolean;
customStyles?: string;
baseUrl?: string;
fragmentOnly?: boolean;
}
/**
* CSS class mappings for rendered elements
*/
export interface CssClasses {
document?: string;
frontMatter?: string;
bodyMatter?: string;
backMatter?: string;
unit?: string;
chapter?: string;
section?: string;
paragraph?: string;
heading?: string;
list?: string;
listItem?: string;
blockquote?: string;
codeBlock?: string;
mathBlock?: string;
table?: string;
figure?: string;
emphasis?: string;
strong?: string;
citation?: string;
reference?: string;
index?: string;
keyTerm?: string;
learningObjective?: string;
pathway?: string;
resource?: string;
[key: string]: string | undefined;
}
/**
* Rendered output format
*/
export type RenderFormat =
| 'html'
| 'pdf'
| 'epub'
| 'latex'
| 'markdown'
| 'json'
| 'docx'
| 'rmarkdown';
/**
* Rendering context for tracking state during rendering
*/
export interface RenderingContext {
currentLevel: number;
headingCounter: number[];
footnotes: Array<{ id: string; content: string }>;
citations: Set<string>;
indexEntries: Map<string, string[]>;
customData?: Record<string, unknown>;
}
/**
* Rendered output result
*/
export interface RenderResult {
content: string;
metadata?: RenderMetadata;
assets?: RenderAsset[];
errors?: RenderError[];
}
/**
* Metadata about the rendering process
*/
export interface RenderMetadata {
format: RenderFormat;
renderTime: number;
wordCount?: number;
pageCount?: number;
tocGenerated?: boolean;
indexGenerated?: boolean;
bibliographyGenerated?: boolean;
}
/**
* External asset referenced in rendered output
*/
export interface RenderAsset {
type: 'stylesheet' | 'script' | 'image' | 'font' | 'other';
url: string;
integrity?: string;
crossOrigin?: string;
}
/**
* Error encountered during rendering
*/
export interface RenderError {
type: 'missing-reference' | 'invalid-content' | 'unsupported-feature' | 'other';
message: string;
path?: string;
recoverable: boolean;
}
// ============================================================================
// BIDIRECTIONAL RENDERING ARCHITECTURE (v0.5.0)
// ============================================================================
/**
* Common interface for all bidirectional renderers
* Provides both render (xats -> format) and parse (format -> xats) capabilities
*/
export interface BidirectionalRenderer<TOptions extends RendererOptions = RendererOptions> {
/** Renderer format identifier */
readonly format: RenderFormat;
/** WCAG compliance level supported by this renderer */
readonly wcagLevel: 'A' | 'AA' | 'AAA' | null;
/** Render xats document to target format */
render(document: XatsDocument, options?: TOptions): Promise<RenderResult>;
/** Parse document from target format back to xats */
parse(content: string, options?: ParseOptions): Promise<ParseResult>;
/** Test round-trip fidelity between render and parse */
testRoundTrip(document: XatsDocument, options?: RoundTripOptions): Promise<RoundTripResult>;
/** Validate format-specific content */
validate(content: string): Promise<FormatValidationResult>;
/** Get format-specific metadata */
getMetadata?(content: string): Promise<FormatMetadata>;
}
/**
* Options for parsing content back to xats format
*/
export interface ParseOptions {
/** Preserve format-specific metadata in extensions */
preserveMetadata?: boolean;
/** Strict parsing mode - fail on any ambiguity */
strictMode?: boolean;
/** Custom parsing rules for specific elements */
customParsers?: Record<string, (content: string) => unknown>;
/** Base URL for resolving relative links */
baseUrl?: string;
/** Character encoding (defaults to UTF-8) */
encoding?: string;
}
/**
* Result of parsing content to xats format
*/
export interface ParseResult {
/** Parsed xats document */
document: XatsDocument;
/** Metadata about the parsing process */
metadata?: ParseMetadata;
/** Warnings encountered during parsing */
warnings?: ParseWarning[];
/** Errors encountered during parsing */
errors?: ParseError[];
/** Format-specific data that couldn't be mapped */
unmappedData?: UnmappedData[];
}
/**
* Metadata about the parsing process
*/
export interface ParseMetadata {
/** Source format that was parsed */
sourceFormat: string;
/** Time taken to parse */
parseTime: number;
/** Number of elements successfully mapped */
mappedElements: number;
/** Number of elements that couldn't be mapped */
unmappedElements: number;
/** Fidelity score (0-1) indicating how well content was preserved */
fidelityScore: number;
}
/**
* Warning encountered during parsing
*/
export interface ParseWarning {
type: 'lossy-conversion' | 'format-specific' | 'ambiguous-mapping' | 'other';
message: string;
path?: string;
suggestion?: string;
}
/**
* Error encountered during parsing
*/
export interface ParseError {
type: 'invalid-format' | 'unsupported-feature' | 'malformed-content' | 'other';
message: string;
path?: string;
fatal: boolean;
}
/**
* Data that couldn't be mapped during parsing
*/
export interface UnmappedData {
type: 'element' | 'attribute' | 'style' | 'script' | 'other';
content: string;
context?: string;
reason: string;
}
/**
* Options for round-trip testing
*/
export interface RoundTripOptions extends RendererOptions, ParseOptions {
/** Acceptable fidelity threshold (0-1) */
fidelityThreshold?: number;
/** Compare semantic meaning rather than exact structure */
semanticComparison?: boolean;
/** Elements to ignore during comparison */
ignoreElements?: string[];
}
/**
* Result of round-trip testing
*/
export interface RoundTripResult {
/** Whether round-trip passed fidelity threshold */
success: boolean;
/** Fidelity score (0-1) */
fidelityScore: number;
/** Original document */
original: XatsDocument;
/** Document after round-trip conversion */
roundTrip: XatsDocument;
/** Differences found between documents */
differences: DocumentDifference[];
/** Performance metrics */
metrics: RoundTripMetrics;
}
/**
* Difference found between original and round-trip documents
*/
export interface DocumentDifference {
type: 'missing' | 'added' | 'changed' | 'moved';
path: string;
original?: unknown;
roundTrip?: unknown;
impact: 'critical' | 'major' | 'minor' | 'cosmetic';
}
/**
* Performance metrics for round-trip testing
*/
export interface RoundTripMetrics {
renderTime: number;
parseTime: number;
totalTime: number;
memoryUsage?: number;
documentSize: number;
outputSize: number;
}
/**
* Validation result for format-specific content
*/
export interface FormatValidationResult {
valid: boolean;
errors: FormatValidationError[];
warnings: FormatValidationWarning[];
metadata?: {
validator: string;
version: string;
validatedAt: Date;
};
}
/**
* Error from format validation
*/
export interface FormatValidationError {
code: string;
message: string;
line?: number;
column?: number;
severity: 'error' | 'warning';
}
/**
* Warning from format validation
*/
export interface FormatValidationWarning {
code: string;
message: string;
line?: number;
column?: number;
suggestion?: string;
}
/**
* Format-specific metadata
*/
export interface FormatMetadata {
format: string;
version?: string;
encoding?: string;
language?: string;
wordCount?: number;
elementCount?: number;
features?: string[];
custom?: Record<string, unknown>;
}
/**
* WCAG compliance testing interface
*/
export interface WcagCompliance {
/** Test WCAG compliance level */
testCompliance(content: string, level: 'A' | 'AA' | 'AAA'): Promise<WcagResult>;
/** Get accessibility audit report */
auditAccessibility(content: string): Promise<AccessibilityAudit>;
}
/**
* WCAG compliance test result
*/
export interface WcagResult {
level: 'A' | 'AA' | 'AAA';
compliant: boolean;
violations: WcagViolation[];
warnings: WcagWarning[];
score: number; // 0-100
}
/**
* WCAG violation found during testing
*/
export interface WcagViolation {
criterion: string; // e.g., "1.4.3"
level: 'A' | 'AA' | 'AAA';
description: string;
element?: string;
recommendation: string;
impact: 'critical' | 'serious' | 'moderate' | 'minor';
}
/**
* WCAG warning found during testing
*/
export interface WcagWarning {
criterion: string;
level: 'A' | 'AA' | 'AAA';
description: string;
element?: string;
suggestion: string;
}
/**
* Comprehensive accessibility audit
*/
export interface AccessibilityAudit {
compliant: boolean;
overallScore: number; // 0-100
levelA: WcagResult;
levelAA: WcagResult;
levelAAA: WcagResult;
recommendations: AccessibilityRecommendation[];
testedAt: Date;
}
/**
* Accessibility improvement recommendation
*/
export interface AccessibilityRecommendation {
priority: 'high' | 'medium' | 'low';
category: 'structure' | 'navigation' | 'content' | 'interaction' | 'visual';
description: string;
implementation: string;
wcagCriteria: string[];
}
/**
* Plugin system interface for extending renderers
*/
export interface RendererPlugin<TRenderer extends BidirectionalRenderer = BidirectionalRenderer> {
/** Plugin identifier */
readonly id: string;
/** Plugin name */
readonly name: string;
/** Plugin version */
readonly version: string;
/** Compatible renderer formats */
readonly compatibleFormats: RenderFormat[];
/** Initialize plugin with renderer instance */
initialize(renderer: TRenderer): Promise<void>;
/** Cleanup plugin resources */
cleanup?(): Promise<void>;
/** Extend rendering process */
beforeRender?(document: XatsDocument, options: RendererOptions): Promise<void>;
afterRender?(result: RenderResult): Promise<RenderResult>;
/** Extend parsing process */
beforeParse?(content: string, options: ParseOptions): Promise<string>;
afterParse?(result: ParseResult): Promise<ParseResult>;
}
/**
* Plugin registry for managing renderer extensions
*/
export interface PluginRegistry {
/** Register a new plugin */
register<T extends BidirectionalRenderer>(plugin: RendererPlugin<T>): void;
/** Unregister a plugin */
unregister(pluginId: string): Promise<void>;
/** Get registered plugin by ID */
getPlugin(pluginId: string): RendererPlugin | undefined;
/** List all registered plugins */
listPlugins(): RendererPlugin[];
/** Find plugins compatible with a format */
findCompatiblePlugins(format: RenderFormat): RendererPlugin[];
}
/**
* Factory interface for creating renderer instances
*/
export interface RendererFactory {
/** Create a renderer for the specified format */
createRenderer<T extends BidirectionalRenderer>(format: RenderFormat): T;
/** Get available renderer formats */
getAvailableFormats(): RenderFormat[];
/** Check if a format is supported */
supportsFormat(format: RenderFormat): boolean;
/** Register a new renderer implementation */
registerRenderer<T extends BidirectionalRenderer>(
format: RenderFormat,
rendererClass: new (...args: unknown[]) => T
): void;
}