Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
/**
* @module Generators/Shared/Types
* @description Branded types and shared interfaces for the HTML/XML/RSS
* generation bounded contexts. Branded types prevent accidental mixing of
* raw strings with already-escaped or validated output.
*
* These types are compile-time-only (erased by TypeScript) so they impose
* zero runtime cost while catching misuse like passing unsanitized input
* directly into an HTML template.
*/
import type { LanguageCode } from '../../types/index.js';
// ─── Branded-type infrastructure ────────────────────────────────────────────
/**
* Phantom brand tag. The unique symbol ensures no two branded types are
* assignable to each other even if they share the same base type.
*/
declare const __brand: unique symbol;
/**
* A branded type wraps a base primitive with a compile-time-only tag so
* TypeScript prevents accidental interchange. Runtime representation is
* identical to `Base`; the brand exists only in the type system.
*/
type Brand<Base, Tag extends string> = Base & { readonly [__brand]: Tag };
// ─── HTML-safe branded types ────────────────────────────────────────────────
/**
* A string that has been HTML-entity-escaped and is safe for interpolation
* into an HTML document. Created via {@link toSafeHtml}.
*/
export type SafeHtmlString = Brand<string, 'SafeHtml'>;
/**
* A string that has been XML-entity-escaped and is safe for interpolation
* into an XML document (sitemap.xml, rss.xml). Created via {@link toSafeXml}.
*/
export type SafeXmlString = Brand<string, 'SafeXml'>;
/**
* An absolute URL validated to start with `https://`. Prevents accidental
* injection of `javascript:` or relative paths into `href` attributes.
*/
export type AbsoluteUrl = Brand<string, 'AbsoluteUrl'>;
/**
* A POSIX-normalized relative file path (no leading slash, forward-slash
* separators). Used for article output paths and sitemap entries.
*/
export type RelativeFilePath = Brand<string, 'RelativeFilePath'>;
// ─── Shared generation interfaces ───────────────────────────────────────────
/**
* Cache-busting configuration injected into every HTML template.
* Ensures browser and CDN caches are invalidated on each deploy.
*/
export interface CacheBustConfig {
/** Short build hash appended as `?v=<hash>` to asset URLs */
readonly buildShort: string;
/** Full semantic version string (e.g. `0.8.59`) */
readonly appVersion: string;
}
/**
* Common page metadata shared by every generated HTML page (article,
* sitemap, political-intelligence, news-index).
*/
export interface PageMeta {
/** Target ISO 639-1 language code */
readonly lang: LanguageCode;
/** `<title>` element content */
readonly title: string;
/** `<meta name="description">` content */
readonly description: string;
/** Canonical URL of the page */
readonly canonicalUrl: string;
/** Text direction (`ltr` or `rtl`) */
readonly dir: 'ltr' | 'rtl';
}
/**
* Structured data (JSON-LD) payload shape shared across page types.
* Each generator builds its own specialization but the base fields
* are common.
*/
export interface BaseJsonLd {
readonly '@context': 'https://schema.org';
readonly '@type': string;
readonly name: string;
readonly url: string;
readonly inLanguage: string;
}
/**
* Options bag for any generator that produces multi-language output.
* Every bounded context that emits per-language files accepts at least
* these fields.
*/
export interface MultiLanguageGeneratorOptions {
/** Subset of languages to generate (defaults to ALL_LANGUAGES) */
readonly languages?: readonly LanguageCode[];
/** Cache-busting parameters */
readonly cacheBust: CacheBustConfig;
/** Whether to include structured data (JSON-LD) in output */
readonly includeStructuredData?: boolean;
}
|