@rathnasgala2/template 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +515 -0
  3. package/contracts/render-policy.jcs +1 -0
  4. package/contracts/theme-styling-contract.jcs +1 -0
  5. package/package.json +96 -0
  6. package/src/core/errors.js +136 -0
  7. package/src/core/index.js +758 -0
  8. package/src/core/internal/appearance/bootstrap-script.js +159 -0
  9. package/src/core/internal/appearance/contract.js +193 -0
  10. package/src/core/internal/appearance/controller-markup.js +80 -0
  11. package/src/core/internal/appearance/styling-contract.js +509 -0
  12. package/src/core/internal/canonical-jcs.js +0 -0
  13. package/src/core/internal/content-security.js +0 -0
  14. package/src/core/internal/eleventy-render.js +220 -0
  15. package/src/core/internal/feeds.js +161 -0
  16. package/src/core/internal/fs-walk.js +38 -0
  17. package/src/core/internal/media/avif-probe.js +169 -0
  18. package/src/core/internal/media/font-policy.js +56 -0
  19. package/src/core/internal/media/jpeg-codec.js +0 -0
  20. package/src/core/internal/media/limits.js +129 -0
  21. package/src/core/internal/media/pipeline.js +353 -0
  22. package/src/core/internal/media/png-codec.js +406 -0
  23. package/src/core/internal/media/resize.js +147 -0
  24. package/src/core/internal/media/sniff.js +109 -0
  25. package/src/core/internal/media/webp-probe.js +139 -0
  26. package/src/core/internal/messages.js +78 -0
  27. package/src/core/internal/page-kinds.js +709 -0
  28. package/src/core/internal/provenance.js +49 -0
  29. package/src/core/internal/render-policy-content.js +295 -0
  30. package/src/core/internal/route-labels.js +68 -0
  31. package/src/core/internal/route.js +167 -0
  32. package/src/core/internal/search-index.js +119 -0
  33. package/src/core/internal/seo.js +114 -0
  34. package/src/core/internal/sitemap.js +77 -0
  35. package/src/core/internal/skeleton.js +413 -0
  36. package/src/core/internal/source-inventory.js +145 -0
  37. package/src/core/internal/text-direction.js +59 -0
  38. package/src/core/internal/theme-assets.js +387 -0
  39. package/src/core/internal/uuid.js +51 -0
  40. package/src/core/manifest.js +0 -0
  41. package/types/eleventy-plugin-syntaxhighlight.d.ts +26 -0
  42. package/types/eleventy.d.ts +38 -0
  43. package/types/index.d.ts +347 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Minimal ambient typing for the one Eleventy surface
3
+ * `src/core/internal/eleventy-render.js` uses. `@11ty/eleventy` ships no
4
+ * published type declarations; this is deliberately narrow rather than a
5
+ * full re-authoring of its programmatic API.
6
+ */
7
+ declare module '@11ty/eleventy' {
8
+ export interface EleventyUserConfig {
9
+ setUseGitIgnore(value: boolean): void;
10
+ setLayoutsDirectory(directory: string): void;
11
+ setQuietMode(value: boolean): void;
12
+ setDataDeepMerge(value: boolean): void;
13
+ addTemplate(
14
+ virtualInputPath: string,
15
+ content: string,
16
+ data?: Record<string, unknown>,
17
+ ): void;
18
+ }
19
+
20
+ export interface EleventyConstructorOptions {
21
+ source?: 'cli' | 'script';
22
+ runMode?: 'build' | 'serve' | 'watch';
23
+ dryRun?: boolean;
24
+ quietMode?: boolean;
25
+ configPath?: string | false;
26
+ config?: (eleventyConfig: EleventyUserConfig) => void;
27
+ }
28
+
29
+ export default class Eleventy {
30
+ constructor(
31
+ input?: string,
32
+ output?: string,
33
+ options?: EleventyConstructorOptions,
34
+ );
35
+ disableLogger(): void;
36
+ write(): Promise<unknown>;
37
+ }
38
+ }
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Hand-maintained declaration surface for `@rathnasgala2/template`
3
+ * (DEC-094: JSDoc-typed JavaScript ESM, no TypeScript sources).
4
+ *
5
+ * Every `build-input:2.0.0` / `artifact-manifest:2.0.0` shape below is a
6
+ * pragmatic subset of DEC-097 section 5/6's exact schemas: it types every
7
+ * field this renderer actually reads or writes, and widens everything else
8
+ * to `unknown`/index signatures rather than re-authoring the full published
9
+ * schema as TypeScript. The `@rathnasgala2/schemas` package (JSON Schema
10
+ * plus `validateGalaDocument`) remains the single source of truth for
11
+ * validity; these types exist only so `tsc --checkJs` can check this
12
+ * package's own code.
13
+ */
14
+
15
+ /** The published npm package name for this renderer. */
16
+ export declare const TEMPLATE_PACKAGE_NAME: string;
17
+
18
+ /** The renderer's published major.minor.patch version. */
19
+ export declare const TEMPLATE_PACKAGE_VERSION: string;
20
+
21
+ /** A `packageIdentity`-shaped record: package, version, integrity, registry. */
22
+ export interface PackageIdentity {
23
+ package: string;
24
+ version: string;
25
+ integrity: string;
26
+ registry: string;
27
+ }
28
+
29
+ /** A `resolvedFile`-shaped reference: path plus source digest. */
30
+ export interface ResolvedFileRef {
31
+ path: string;
32
+ sourceDigest: string;
33
+ }
34
+
35
+ /** A `resolvedMedia`-shaped reference. */
36
+ export interface ResolvedMediaRef {
37
+ file: ResolvedFileRef;
38
+ alt: string;
39
+ role: 'informative' | 'decorative';
40
+ }
41
+
42
+ /** A `normalizedSource`-shaped discriminated reference. */
43
+ export type NormalizedSource =
44
+ | { kind: 'authored'; sourcePath: string; sourceDigest: string }
45
+ | { kind: 'built-in-default'; defaultId: string; defaultDigest: string };
46
+
47
+ /** A `renderableBody`-shaped normalized body. */
48
+ export interface RenderableBody {
49
+ sourcePath: string;
50
+ sourceDigest: string;
51
+ bodyMediaType: 'text/html';
52
+ body: string;
53
+ bodyDigest: string;
54
+ renderPolicy: { name: string; version: string; digest: string };
55
+ }
56
+
57
+ /** A `contentFrontmatterNormalized`-shaped record's fields this renderer reads. */
58
+ export interface ContentFrontmatterNormalized {
59
+ id: string;
60
+ kind: 'article' | 'page';
61
+ title: string;
62
+ description?: string;
63
+ language: string;
64
+ authorIds: string[];
65
+ tags: string[];
66
+ series?: string;
67
+ seriesOrder?: number;
68
+ status: 'published' | 'unlisted';
69
+ createdAt: string;
70
+ publishedAt: string;
71
+ updatedAt?: string;
72
+ slug: string;
73
+ route?: string;
74
+ hero?: ResolvedMediaRef;
75
+ socialImage?: ResolvedFileRef;
76
+ redirects: string[];
77
+ }
78
+
79
+ /** A `contentBuildRecord`-shaped record. */
80
+ export interface ContentBuildRecord {
81
+ frontmatter: ContentFrontmatterNormalized;
82
+ body: string;
83
+ bodyMediaType: 'text/html';
84
+ bodyDigest: string;
85
+ renderPolicy: { name: string; version: string; digest: string };
86
+ sourcePath: string;
87
+ sourceRevision: string;
88
+ sourceDigest: string;
89
+ resolvedAuthorIds: string[];
90
+ }
91
+
92
+ /** A `socialLink`-shaped reference. */
93
+ export interface SocialLink {
94
+ type:
95
+ | 'website'
96
+ | 'email'
97
+ | 'github'
98
+ | 'linkedin'
99
+ | 'mastodon'
100
+ | 'bluesky'
101
+ | 'x'
102
+ | 'youtube'
103
+ | 'other';
104
+ uri: string;
105
+ label?: string;
106
+ }
107
+
108
+ /** An `authorNormalized`-shaped record. */
109
+ export interface AuthorNormalized {
110
+ id: string;
111
+ displayName: string;
112
+ biography: string;
113
+ pronouns?: string;
114
+ avatar?: ResolvedFileRef;
115
+ links: SocialLink[];
116
+ localized: unknown[];
117
+ sourcePath: string;
118
+ sourceDigest: string;
119
+ }
120
+
121
+ /** The subset of `publicationNormalized` this renderer reads. */
122
+ export interface PublicationNormalized {
123
+ id: string;
124
+ slug: string;
125
+ title: string;
126
+ description: string;
127
+ canonicalBase: string;
128
+ defaultLanguage: string;
129
+ authorIds: string[];
130
+ contactAuthorId?: string;
131
+ socialLinks: unknown[];
132
+ defaultImage?: ResolvedFileRef;
133
+ profile?: { route: string; body: RenderableBody };
134
+ footerCard?: {
135
+ enabled: boolean;
136
+ heading: string;
137
+ body: RenderableBody;
138
+ authorIds: string[];
139
+ };
140
+ sourcePath: string;
141
+ sourceDigest: string;
142
+ }
143
+
144
+ /** A `navigationItem`/`navigationLeaf`-shaped entry (leaves never carry
145
+ * children per the `navigation:2.0.0` schema's own `maxItems: 0` on a leaf's
146
+ * `children`, but this renderer only reads `children.length`/iterates it, so
147
+ * one recursive type is sufficient here). */
148
+ export interface NavigationItem {
149
+ type: 'internal' | 'external';
150
+ label: string;
151
+ route?: string;
152
+ url?: string;
153
+ children: NavigationItem[];
154
+ }
155
+
156
+ /** The subset of `navigationNormalized` this renderer reads. */
157
+ export interface NavigationNormalized {
158
+ items: NavigationItem[];
159
+ footerItems: NavigationItem[];
160
+ source: NormalizedSource;
161
+ }
162
+
163
+ /** The subset of `appearanceNormalized` this renderer reads. */
164
+ export interface AppearanceNormalized {
165
+ theme: string;
166
+ colorMode: unknown;
167
+ brandMark?: ResolvedFileRef;
168
+ wordmark?: ResolvedFileRef;
169
+ headerComposition: string;
170
+ footerComposition: string;
171
+ typeScale: string;
172
+ fontAssets: ResolvedFileRef[];
173
+ tokens: Record<string, never>;
174
+ source: NormalizedSource;
175
+ }
176
+
177
+ /** The subset of `build-input:2.0.0` this renderer reads. */
178
+ export interface NormalizedBuildInput {
179
+ schemaId: string;
180
+ schemaVersion: string;
181
+ contractVersion: string;
182
+ repository: {
183
+ repositoryId: string;
184
+ repositoryOwnerId: string;
185
+ sourceRevision: string;
186
+ rootDigest: string;
187
+ };
188
+ sourceRevision: string;
189
+ packages: {
190
+ schemas: PackageIdentity;
191
+ template: PackageIdentity;
192
+ theme: PackageIdentity;
193
+ publisher: PackageIdentity[];
194
+ dependencies: PackageIdentity[];
195
+ };
196
+ publication: PublicationNormalized;
197
+ authors: AuthorNormalized[];
198
+ content: ContentBuildRecord[];
199
+ navigation: NavigationNormalized;
200
+ appearance: AppearanceNormalized;
201
+ modules: Record<string, never>;
202
+ buildEpoch: string;
203
+ baseUrl: string;
204
+ basePath: string;
205
+ destinationCapabilities: unknown;
206
+ placements: never[];
207
+ inputDigest: string;
208
+ }
209
+
210
+ /** A `buildToolIdentity`-shaped entry. */
211
+ export type BuildToolIdentity =
212
+ | { kind: 'runtime'; name: 'node' | 'npm'; version: string; digest: string }
213
+ | { kind: 'package'; package: string; version: string; digest: string };
214
+
215
+ /** A `manifestRoute`-shaped entry this renderer emits. */
216
+ export interface ManifestRouteEntry {
217
+ path: string;
218
+ mediaType: string;
219
+ byteLength: string;
220
+ sha256: string;
221
+ routeClass: 'html' | 'feed' | 'sitemap' | 'asset' | 'error';
222
+ interactionBearing: false;
223
+ }
224
+
225
+ /** A `manifestAsset`-shaped entry (S2-T05's media pipeline emits one per generated file). */
226
+ export interface ManifestAssetEntry {
227
+ path: string;
228
+ mediaType: string;
229
+ byteLength: string;
230
+ sha256: string;
231
+ immutable: boolean;
232
+ }
233
+
234
+ /** A `manifestRedirect`-shaped entry. */
235
+ export interface ManifestRedirectEntry {
236
+ sourceRoute: string;
237
+ targetRoute: string;
238
+ status: 200;
239
+ backingPath: string;
240
+ sha256: string;
241
+ }
242
+
243
+ /** A `manifestIncludedSource`-shaped entry. */
244
+ export interface ManifestIncludedSourceEntry {
245
+ path: string;
246
+ sha256: string;
247
+ sourceRevision: string;
248
+ role:
249
+ | 'publication'
250
+ | 'author'
251
+ | 'content'
252
+ | 'navigation'
253
+ | 'appearance'
254
+ | 'asset';
255
+ }
256
+
257
+ /** A `manifestExcludedInput`-shaped entry. */
258
+ export interface ManifestExcludedInputEntry {
259
+ path: string;
260
+ sha256: string;
261
+ ruleId: string;
262
+ reason:
263
+ | 'not-referenced-by-build-input'
264
+ | 'deferred-capability-absent'
265
+ | 'non-artifact-source'
266
+ | 'policy-excluded';
267
+ }
268
+
269
+ /**
270
+ * Provenance facts the renderer cannot derive from `build-input` alone (see
271
+ * `src/core/manifest.js` module documentation). Supplied by the caller
272
+ * (eventually `publish-kernel`/`publish-action`, S2-T15 through S2-T20).
273
+ */
274
+ export interface RenderProvenance {
275
+ builder: PackageIdentity;
276
+ repositoryCoordinate: string;
277
+ workflowIdentity: string;
278
+ buildToolVersions: BuildToolIdentity[];
279
+ additionalExcludedInputs?: ManifestExcludedInputEntry[];
280
+ }
281
+
282
+ /** Options accepted by `renderPublication`. */
283
+ export interface RenderOptions {
284
+ outputDirectory: string;
285
+ workDirectory: string;
286
+ /**
287
+ * The caller-mounted, read-only repository source tree that
288
+ * `build-input`'s `resolvedFile` references (images, fonts) point into
289
+ * (S2-T05). Must be distinct from `outputDirectory` and `workDirectory`.
290
+ */
291
+ sourceDirectory: string;
292
+ /**
293
+ * An optional caller-mounted, read-only extracted theme package directory
294
+ * (S2-T12: `internal/theme-assets.js`). When supplied, its `theme.json`
295
+ * declared stylesheets (and any declared passive assets) are copied into
296
+ * `assets/theme/` and linked from every generated page. Must be distinct
297
+ * from `outputDirectory`, `workDirectory` and `sourceDirectory`.
298
+ */
299
+ themeDirectory?: string;
300
+ routeNormalizationProfile?: 'directory-index' | 'explicit-file';
301
+ provenance: RenderProvenance;
302
+ }
303
+
304
+ export declare function renderPublication(
305
+ buildInput: unknown,
306
+ options: RenderOptions,
307
+ ): Promise<{ outputDirectory: string; manifest: Record<string, unknown> }>;
308
+
309
+ export declare class BuildInputValidationError extends Error {
310
+ diagnostics: ReadonlyArray<Record<string, unknown>>;
311
+ constructor(diagnostics: ReadonlyArray<Record<string, unknown>>);
312
+ }
313
+
314
+ export declare class RenderOptionsError extends Error {
315
+ constructor(message: string);
316
+ }
317
+
318
+ export declare class ArtifactManifestValidationError extends Error {
319
+ diagnostics: ReadonlyArray<Record<string, unknown>>;
320
+ constructor(diagnostics: ReadonlyArray<Record<string, unknown>>);
321
+ }
322
+
323
+ export declare class MediaPipelineError extends Error {
324
+ reasonCode: string;
325
+ referencePath: string;
326
+ constructor(reasonCode: string, message: string, referencePath: string);
327
+ }
328
+
329
+ export declare class RenderPolicyViolationError extends Error {
330
+ constructor(message: string);
331
+ }
332
+
333
+ /**
334
+ * The upstream normalization step: run one authored Markdown source string
335
+ * through the render-policy pipeline (markdown-it -> sanitize-html ->
336
+ * highlighter) and return the exact `renderableBody.body`/`bodyDigest` pair
337
+ * a `build-input:2.0.0` producer places into a `renderableBody`.
338
+ * `renderPublication` never calls this itself; see
339
+ * `src/core/internal/content-security.js`'s module documentation.
340
+ */
341
+ export declare function normalizeAuthoredMarkdown(markdownSource: string): {
342
+ html: string;
343
+ bodyDigest: string;
344
+ };
345
+
346
+ /** A plain (not domain-separated) tagged SHA-256 digest of a body's exact UTF-8 bytes. */
347
+ export declare function computeBodyDigest(html: string): string;