@usecds/server 0.0.0-stage → 0.1.1

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 (72) hide show
  1. package/LICENSE +201 -0
  2. package/dist/core/content-report.d.ts +37 -0
  3. package/dist/core/content-report.js +306 -0
  4. package/dist/core/content-report.js.map +1 -0
  5. package/dist/core/content-types.d.ts +40 -0
  6. package/dist/core/content-types.js +27 -0
  7. package/dist/core/content-types.js.map +1 -0
  8. package/dist/core/jsonld.d.ts +33 -0
  9. package/dist/core/jsonld.js +94 -0
  10. package/dist/core/jsonld.js.map +1 -0
  11. package/dist/core/media-metadata.d.ts +20 -0
  12. package/dist/core/media-metadata.js +53 -0
  13. package/dist/core/media-metadata.js.map +1 -0
  14. package/dist/core/media-names.d.ts +9 -0
  15. package/dist/core/media-names.js +58 -0
  16. package/dist/core/media-names.js.map +1 -0
  17. package/dist/core/menu.d.ts +33 -0
  18. package/dist/core/menu.js +89 -0
  19. package/dist/core/menu.js.map +1 -0
  20. package/dist/core/publisher.d.ts +77 -0
  21. package/dist/core/publisher.js +263 -0
  22. package/dist/core/publisher.js.map +1 -0
  23. package/dist/core/report.d.ts +54 -0
  24. package/dist/core/report.js +132 -0
  25. package/dist/core/report.js.map +1 -0
  26. package/dist/core/settings.d.ts +12 -0
  27. package/dist/core/settings.js +40 -0
  28. package/dist/core/settings.js.map +1 -0
  29. package/dist/core/site.d.ts +37 -0
  30. package/dist/core/site.js +96 -0
  31. package/dist/core/site.js.map +1 -0
  32. package/dist/core/storage-report.d.ts +44 -0
  33. package/dist/core/storage-report.js +112 -0
  34. package/dist/core/storage-report.js.map +1 -0
  35. package/dist/core/targets.d.ts +63 -0
  36. package/dist/core/targets.js +213 -0
  37. package/dist/core/targets.js.map +1 -0
  38. package/dist/core/translations.d.ts +41 -0
  39. package/dist/core/translations.js +125 -0
  40. package/dist/core/translations.js.map +1 -0
  41. package/dist/index.d.ts +18 -0
  42. package/dist/index.js +19 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/sources/fixture.d.ts +9 -0
  45. package/dist/sources/fixture.js +79 -0
  46. package/dist/sources/fixture.js.map +1 -0
  47. package/dist/storage/filesystem.d.ts +23 -0
  48. package/dist/storage/filesystem.js +125 -0
  49. package/dist/storage/filesystem.js.map +1 -0
  50. package/dist/types.d.ts +223 -0
  51. package/dist/types.js +2 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/utils.d.ts +2 -0
  54. package/dist/utils.js +17 -0
  55. package/dist/utils.js.map +1 -0
  56. package/dist/validation.d.ts +23 -0
  57. package/dist/validation.js +102 -0
  58. package/dist/validation.js.map +1 -0
  59. package/package.json +28 -3
  60. package/schemas/v1/block.json +31 -0
  61. package/schemas/v1/channel-manifest.json +23 -0
  62. package/schemas/v1/collection.json +89 -0
  63. package/schemas/v1/jsonld.json +19 -0
  64. package/schemas/v1/language.json +12 -0
  65. package/schemas/v1/media-metadata.json +41 -0
  66. package/schemas/v1/menu.json +21 -0
  67. package/schemas/v1/page.json +12 -0
  68. package/schemas/v1/release-manifest.json +82 -0
  69. package/schemas/v1/route.json +24 -0
  70. package/schemas/v1/site.json +21 -0
  71. package/schemas/v1/target.json +98 -0
  72. package/README.md +0 -3
@@ -0,0 +1,96 @@
1
+ import { validateBlockItem, validatePageItem, validateRouteItem } from "../validation.js";
2
+ // Optional, typed reserved collections describing site structure
3
+ export const ROUTES_COLLECTION = "_routes";
4
+ export const PAGES_COLLECTION = "_pages";
5
+ export const BLOCKS_COLLECTION = "_blocks";
6
+ const byId = (items) => new Map((items ?? []).map((i) => [i.id, i]));
7
+ /**
8
+ * Checks _routes, _pages and _blocks (each only if present). Throws on the first problem:
9
+ * schema errors, a route without page or redirect (or both), unknown pages, routes, blocks,
10
+ * collections or items, redirect cycles, a route without any path, the same path twice in a locale,
11
+ * and blocks with both items and source.
12
+ */
13
+ export function validateSite(collections) {
14
+ const routes = byId(collections[ROUTES_COLLECTION]);
15
+ const pages = byId(collections[PAGES_COLLECTION]);
16
+ const blocks = byId(collections[BLOCKS_COLLECTION]);
17
+ const paths = new Map(); // "locale path" -> route id
18
+ for (const route of routes.values()) {
19
+ validateRouteItem(route);
20
+ if (!!route.page === !!route.redirect) {
21
+ throw new Error(`Invalid _routes item (${route.id}): needs either a page or a redirect`);
22
+ }
23
+ if (route.page && !pages.has(route.page)) {
24
+ throw new Error(`Invalid _routes item (${route.id}): unknown page "${route.page}"`);
25
+ }
26
+ if (route.redirect && !routes.has(route.redirect)) {
27
+ throw new Error(`Invalid _routes item (${route.id}): redirects to unknown route "${route.redirect}"`);
28
+ }
29
+ const localized = Object.entries(route.translations).filter(([, t]) => typeof t?.path === "string");
30
+ if (localized.length === 0) {
31
+ throw new Error(`Invalid _routes item (${route.id}): has no path in any locale`);
32
+ }
33
+ for (const [locale, t] of localized) {
34
+ const key = `${locale} ${t.path}`;
35
+ const existing = paths.get(key);
36
+ if (existing)
37
+ throw new Error(`Path ${t.path} (${locale}) is used by routes ${existing} and ${route.id}`);
38
+ paths.set(key, route.id);
39
+ }
40
+ }
41
+ for (const route of routes.values()) {
42
+ const seen = new Set([route.id]);
43
+ let next = route.redirect;
44
+ while (next) {
45
+ if (seen.has(next))
46
+ throw new Error(`Redirect cycle: ${[...seen, next].join(" -> ")}`);
47
+ seen.add(next);
48
+ next = routes.get(next)?.redirect;
49
+ }
50
+ }
51
+ for (const page of pages.values()) {
52
+ validatePageItem(page);
53
+ for (const blockId of page.blocks ?? []) {
54
+ if (!blocks.has(blockId))
55
+ throw new Error(`Invalid _pages item (${page.id}): unknown block "${blockId}"`);
56
+ }
57
+ }
58
+ for (const block of blocks.values()) {
59
+ validateBlockItem(block);
60
+ if (block.items && block.source) {
61
+ throw new Error(`Invalid _blocks item (${block.id}): use either items or source, not both`);
62
+ }
63
+ if (block.source && !collections[block.source.collection]) {
64
+ throw new Error(`Invalid _blocks item (${block.id}): source collection "${block.source.collection}" doesn't exist`);
65
+ }
66
+ for (const ref of block.items ?? []) {
67
+ if (!collections[ref.collection]?.some((i) => i.id === ref.id)) {
68
+ throw new Error(`Invalid _blocks item (${block.id}): unknown item ${ref.collection}/${ref.id}`);
69
+ }
70
+ }
71
+ }
72
+ }
73
+ /**
74
+ * Structure that is valid but probably unintended: pages no route shows, blocks no page uses.
75
+ */
76
+ export function siteRecommendations(collections) {
77
+ const issues = [];
78
+ const routedPages = new Set((collections[ROUTES_COLLECTION] ?? []).map((r) => r.page).filter(Boolean));
79
+ const usedBlocks = new Set((collections[PAGES_COLLECTION] ?? []).flatMap((p) => p.blocks ?? []));
80
+ if (collections[ROUTES_COLLECTION]) {
81
+ for (const page of collections[PAGES_COLLECTION] ?? []) {
82
+ if (!routedPages.has(page.id)) {
83
+ issues.push({ collection: PAGES_COLLECTION, id: page.id, issue: "unrouted-page", message: `Page ${page.id} isn't shown by any route` });
84
+ }
85
+ }
86
+ }
87
+ if (collections[PAGES_COLLECTION]) {
88
+ for (const block of collections[BLOCKS_COLLECTION] ?? []) {
89
+ if (!usedBlocks.has(block.id)) {
90
+ issues.push({ collection: BLOCKS_COLLECTION, id: block.id, issue: "unused-block", message: `Block ${block.id} isn't used by any page` });
91
+ }
92
+ }
93
+ }
94
+ return issues;
95
+ }
96
+ //# sourceMappingURL=site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/core/site.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { ObjectStore } from "../types.js";
2
+ export interface StoredFile {
3
+ kind: "object" | "media";
4
+ hash: string;
5
+ file: string;
6
+ bytes: number | null;
7
+ }
8
+ export interface ReleaseDiff {
9
+ previousReleaseId: string;
10
+ added: string[];
11
+ removed: string[];
12
+ shared: number;
13
+ }
14
+ export interface ReleaseUsage {
15
+ releaseId: string;
16
+ channels: string[];
17
+ objects: number;
18
+ media: number;
19
+ bytes: number;
20
+ uniqueBytes: number;
21
+ missing: string[];
22
+ diff: ReleaseDiff | null;
23
+ }
24
+ export interface StorageReport {
25
+ releases: ReleaseUsage[];
26
+ channels: Record<string, {
27
+ releaseId: string;
28
+ retained: boolean;
29
+ }>;
30
+ totals: {
31
+ objects: number;
32
+ media: number;
33
+ bytes: number;
34
+ };
35
+ orphans: {
36
+ files: StoredFile[];
37
+ bytes: number;
38
+ };
39
+ }
40
+ /**
41
+ * Walks the store and reports per-release usage, release-to-release diffs,
42
+ * channel pointers and orphaned files. Read-only.
43
+ */
44
+ export declare function analyzeStorage(store: ObjectStore): Promise<StorageReport>;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Walks the store and reports per-release usage, release-to-release diffs,
3
+ * channel pointers and orphaned files. Read-only.
4
+ */
5
+ export async function analyzeStorage(store) {
6
+ // 1. Inventory of stored files
7
+ const files = new Map(); // keyed by file path
8
+ const mediaFilesByHash = new Map();
9
+ for (const hash of await store.listObjects()) {
10
+ const file = `objects/${hash}.json`;
11
+ files.set(file, { kind: "object", hash, file, bytes: await store.objectSize(hash) });
12
+ }
13
+ for (const filename of await store.listMedia()) {
14
+ // Filename is <hash>.<ext>
15
+ const hash = filename.split(".")[0];
16
+ const file = `media/${filename}`;
17
+ files.set(file, { kind: "media", hash, file, bytes: await store.mediaSize(filename) });
18
+ mediaFilesByHash.set(hash, [...(mediaFilesByHash.get(hash) ?? []), file]);
19
+ }
20
+ // 2. Channel pointers
21
+ const channels = {};
22
+ const releaseIds = (await store.listReleases()).sort();
23
+ for (const channel of await store.listChannels()) {
24
+ const manifest = await store.readChannelManifest(channel);
25
+ if (manifest) {
26
+ channels[channel] = { releaseId: manifest.releaseId, retained: releaseIds.includes(manifest.releaseId) };
27
+ }
28
+ }
29
+ // 3. Files referenced by each retained release
30
+ const referencesByRelease = new Map();
31
+ for (const releaseId of releaseIds) {
32
+ const manifest = await store.readRelease(releaseId);
33
+ if (!manifest)
34
+ continue;
35
+ const referenced = new Set();
36
+ for (const col of Object.values(manifest.collections)) {
37
+ referenced.add(`objects/${col.hash}.json`);
38
+ }
39
+ for (const [virtualPath, med] of Object.entries(manifest.media)) {
40
+ const stored = mediaFilesByHash.get(med.hash);
41
+ if (stored) {
42
+ stored.forEach((f) => referenced.add(f));
43
+ }
44
+ else {
45
+ const ext = virtualPath.includes(".") ? virtualPath.substring(virtualPath.lastIndexOf(".")) : "";
46
+ referenced.add(`media/${med.hash}${ext}`);
47
+ }
48
+ }
49
+ referencesByRelease.set(releaseId, { files: referenced, manifest });
50
+ }
51
+ const referenceCount = new Map();
52
+ for (const { files: referenced } of referencesByRelease.values()) {
53
+ referenced.forEach((f) => referenceCount.set(f, (referenceCount.get(f) ?? 0) + 1));
54
+ }
55
+ // 4. Per-release usage and diff against the previous retained release
56
+ const releases = [];
57
+ let previous = null;
58
+ for (const [releaseId, { files: referenced }] of referencesByRelease) {
59
+ const usage = {
60
+ releaseId,
61
+ channels: Object.keys(channels).filter((c) => channels[c].releaseId === releaseId),
62
+ objects: 0,
63
+ media: 0,
64
+ bytes: 0,
65
+ uniqueBytes: 0,
66
+ missing: [],
67
+ diff: null
68
+ };
69
+ for (const file of referenced) {
70
+ const stored = files.get(file);
71
+ if (!stored || stored.bytes === null) {
72
+ usage.missing.push(file);
73
+ continue;
74
+ }
75
+ if (stored.kind === "object")
76
+ usage.objects++;
77
+ else
78
+ usage.media++;
79
+ usage.bytes += stored.bytes;
80
+ if (referenceCount.get(file) === 1)
81
+ usage.uniqueBytes += stored.bytes;
82
+ }
83
+ if (previous) {
84
+ const prevFiles = previous.files;
85
+ usage.diff = {
86
+ previousReleaseId: previous.releaseId,
87
+ added: [...referenced].filter((f) => !prevFiles.has(f)),
88
+ removed: [...prevFiles].filter((f) => !referenced.has(f)),
89
+ shared: [...referenced].filter((f) => prevFiles.has(f)).length
90
+ };
91
+ }
92
+ releases.push(usage);
93
+ previous = { releaseId, files: referenced };
94
+ }
95
+ // 5. Totals and orphans
96
+ const all = [...files.values()];
97
+ const orphanFiles = all.filter((f) => !referenceCount.has(f.file));
98
+ return {
99
+ releases,
100
+ channels,
101
+ totals: {
102
+ objects: all.filter((f) => f.kind === "object").length,
103
+ media: all.filter((f) => f.kind === "media").length,
104
+ bytes: sum(all)
105
+ },
106
+ orphans: { files: orphanFiles, bytes: sum(orphanFiles) }
107
+ };
108
+ }
109
+ function sum(files) {
110
+ return files.reduce((total, f) => total + (f.bytes ?? 0), 0);
111
+ }
112
+ //# sourceMappingURL=storage-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-report.js","sourceRoot":"","sources":["../../src/core/storage-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export declare const DEFAULT_TARGET_ID = "default";
2
+ export declare const RECOMMENDED_MAX_TARGETS = 8;
3
+ export interface CollectionRules {
4
+ localized?: object;
5
+ fields?: object;
6
+ }
7
+ export interface CollectionRequirements extends CollectionRules {
8
+ minItems?: number;
9
+ presets?: string[];
10
+ }
11
+ export interface MediaPreset {
12
+ aspect?: string;
13
+ fit?: "fill" | "fit";
14
+ widths: Record<string, number>;
15
+ formats?: ("avif" | "webp" | "jpeg" | "png")[];
16
+ quality?: number;
17
+ lossless?: boolean;
18
+ background?: string;
19
+ }
20
+ export interface TargetDefinition {
21
+ id: string;
22
+ scope?: string[];
23
+ locales?: {
24
+ required?: string[];
25
+ minCompleteness?: number;
26
+ maxStale?: number;
27
+ };
28
+ collections?: Record<string, CollectionRequirements>;
29
+ items?: {
30
+ collection: string;
31
+ key: string;
32
+ }[];
33
+ recommendations?: Record<string, CollectionRules>;
34
+ media?: {
35
+ breakpoints?: Record<string, number>;
36
+ dpr?: number[];
37
+ presets?: Record<string, MediaPreset>;
38
+ };
39
+ }
40
+ /**
41
+ * Used when no default target is provided.
42
+ */
43
+ export declare const BUILTIN_DEFAULT_TARGET: TargetDefinition;
44
+ export interface ResolvedTargets {
45
+ defaultTarget: TargetDefinition;
46
+ named: TargetDefinition[];
47
+ effective: Record<string, TargetDefinition>;
48
+ warnings: string[];
49
+ }
50
+ /**
51
+ * Loads all *.json target definitions from a folder. default.json is the default target.
52
+ */
53
+ export declare function loadTargets(dir: string): Promise<TargetDefinition[]>;
54
+ /**
55
+ * Validates the given definitions, picks the default target (built-in if none) and
56
+ * computes each named target's effective definition (default merged with its own).
57
+ */
58
+ export declare function resolveTargets(definitions: TargetDefinition[]): ResolvedTargets;
59
+ /**
60
+ * Additive merge: lists are combined, thresholds take the stricter value, schemas are
61
+ * combined with allOf (both must pass). Nothing is overwritten. Scope is the named target's own.
62
+ */
63
+ export declare function mergeTargets(base: TargetDefinition, own: TargetDefinition): TargetDefinition;
@@ -0,0 +1,213 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { deterministicStringify } from "../utils.js";
4
+ import { validateTargetDefinition } from "../validation.js";
5
+ export const DEFAULT_TARGET_ID = "default";
6
+ export const RECOMMENDED_MAX_TARGETS = 8;
7
+ /**
8
+ * Used when no default target is provided.
9
+ */
10
+ export const BUILTIN_DEFAULT_TARGET = {
11
+ id: DEFAULT_TARGET_ID,
12
+ recommendations: {
13
+ _media: {
14
+ localized: {
15
+ type: "object",
16
+ required: ["alt", "description"],
17
+ properties: {
18
+ alt: { type: "string", minLength: 1, maxLength: 125 },
19
+ description: { type: "string", minLength: 50, maxLength: 300 }
20
+ }
21
+ }
22
+ },
23
+ _pages: {
24
+ localized: {
25
+ type: "object",
26
+ required: ["title", "description"],
27
+ properties: {
28
+ title: { type: "string", minLength: 1, maxLength: 60 },
29
+ description: { type: "string", minLength: 50, maxLength: 160 }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ };
35
+ /**
36
+ * Loads all *.json target definitions from a folder. default.json is the default target.
37
+ */
38
+ export async function loadTargets(dir) {
39
+ const files = (await fs.readdir(dir)).filter((f) => f.endsWith(".json")).sort();
40
+ const targets = [];
41
+ for (const file of files) {
42
+ const target = JSON.parse(await fs.readFile(path.join(dir, file), "utf-8"));
43
+ validateTargetDefinition(target);
44
+ const expectedDefault = file === `${DEFAULT_TARGET_ID}.json`;
45
+ if (expectedDefault !== (target.id === DEFAULT_TARGET_ID)) {
46
+ throw new Error(`Target file ${file}: only default.json may (and must) use the id "${DEFAULT_TARGET_ID}"`);
47
+ }
48
+ targets.push(target);
49
+ }
50
+ return targets;
51
+ }
52
+ /**
53
+ * Validates the given definitions, picks the default target (built-in if none) and
54
+ * computes each named target's effective definition (default merged with its own).
55
+ */
56
+ export function resolveTargets(definitions) {
57
+ const warnings = [];
58
+ const seen = new Set();
59
+ for (const def of definitions) {
60
+ validateTargetDefinition(def);
61
+ if (seen.has(def.id))
62
+ throw new Error(`Duplicate target id: ${def.id}`);
63
+ seen.add(def.id);
64
+ if (def.id !== DEFAULT_TARGET_ID)
65
+ checkOwnScope(def);
66
+ }
67
+ const defaultTarget = definitions.find((d) => d.id === DEFAULT_TARGET_ID) ?? BUILTIN_DEFAULT_TARGET;
68
+ if (defaultTarget.scope) {
69
+ throw new Error(`The default target applies to everything and can't declare a scope`);
70
+ }
71
+ const named = definitions.filter((d) => d.id !== DEFAULT_TARGET_ID);
72
+ if (named.length > RECOMMENDED_MAX_TARGETS) {
73
+ warnings.push(`${named.length} named targets; the recommended maximum is ${RECOMMENDED_MAX_TARGETS}`);
74
+ }
75
+ checkPresetConflicts([defaultTarget, ...named]);
76
+ checkBreakpoints([defaultTarget, ...named]);
77
+ const effective = { [DEFAULT_TARGET_ID]: defaultTarget };
78
+ for (const target of named) {
79
+ effective[target.id] = mergeTargets(defaultTarget, target);
80
+ }
81
+ return { defaultTarget, named, effective, warnings };
82
+ }
83
+ /**
84
+ * Additive merge: lists are combined, thresholds take the stricter value, schemas are
85
+ * combined with allOf (both must pass). Nothing is overwritten. Scope is the named target's own.
86
+ */
87
+ export function mergeTargets(base, own) {
88
+ const merged = { id: own.id };
89
+ if (own.scope)
90
+ merged.scope = [...own.scope];
91
+ const locales = {
92
+ required: union(base.locales?.required, own.locales?.required),
93
+ minCompleteness: stricter(base.locales?.minCompleteness, own.locales?.minCompleteness, Math.max),
94
+ maxStale: stricter(base.locales?.maxStale, own.locales?.maxStale, Math.min)
95
+ };
96
+ if (locales.required || locales.minCompleteness !== undefined || locales.maxStale !== undefined) {
97
+ merged.locales = dropUndefined(locales);
98
+ }
99
+ const collections = mergeRecords(base.collections, own.collections, (a, b) => dropUndefined({
100
+ minItems: stricter(a.minItems, b.minItems, Math.max),
101
+ localized: allOf(a.localized, b.localized),
102
+ fields: allOf(a.fields, b.fields),
103
+ presets: union(a.presets, b.presets)
104
+ }));
105
+ if (collections)
106
+ merged.collections = collections;
107
+ const items = unionBy([...(base.items ?? []), ...(own.items ?? [])], (i) => `${i.collection}\u0000${i.key}`);
108
+ if (items.length)
109
+ merged.items = items;
110
+ const recommendations = mergeRecords(base.recommendations, own.recommendations, (a, b) => dropUndefined({ localized: allOf(a.localized, b.localized), fields: allOf(a.fields, b.fields) }));
111
+ if (recommendations)
112
+ merged.recommendations = recommendations;
113
+ if (base.media || own.media) {
114
+ merged.media = dropUndefined({
115
+ breakpoints: base.media?.breakpoints || own.media?.breakpoints
116
+ ? { ...base.media?.breakpoints, ...own.media?.breakpoints }
117
+ : undefined,
118
+ dpr: union(base.media?.dpr, own.media?.dpr)?.sort((x, y) => x - y),
119
+ presets: base.media?.presets || own.media?.presets ? { ...base.media?.presets, ...own.media?.presets } : undefined
120
+ });
121
+ }
122
+ return merged;
123
+ }
124
+ // A named target's own requirements and recommendations must stay within its own scope
125
+ function checkOwnScope(target) {
126
+ if (!target.scope)
127
+ return;
128
+ const scope = new Set(target.scope);
129
+ const outside = [
130
+ ...Object.keys(target.collections ?? {}),
131
+ ...Object.keys(target.recommendations ?? {}),
132
+ ...(target.items ?? []).map((i) => i.collection)
133
+ ].filter((c) => !scope.has(c));
134
+ if (outside.length) {
135
+ throw new Error(`Target ${target.id} declares rules outside its scope: ${[...new Set(outside)].join(", ")}`);
136
+ }
137
+ }
138
+ // All variants land in one release, so a preset name must mean the same thing in every target
139
+ function checkPresetConflicts(targets) {
140
+ const presets = new Map();
141
+ for (const target of targets) {
142
+ for (const [name, preset] of Object.entries(target.media?.presets ?? {})) {
143
+ const definition = deterministicStringify(preset);
144
+ const existing = presets.get(name);
145
+ if (existing && existing.definition !== definition) {
146
+ throw new Error(`Preset "${name}" is defined differently in targets ${existing.target} and ${target.id}`);
147
+ }
148
+ presets.set(name, { target: target.id, definition });
149
+ }
150
+ }
151
+ }
152
+ // Breakpoints are shared like presets: one name, one width. Presets may only use declared breakpoints.
153
+ function checkBreakpoints(targets) {
154
+ const widths = new Map();
155
+ for (const target of targets) {
156
+ for (const [name, minWidth] of Object.entries(target.media?.breakpoints ?? {})) {
157
+ const existing = widths.get(name);
158
+ if (existing && existing.minWidth !== minWidth) {
159
+ throw new Error(`Breakpoint "${name}" is defined differently in targets ${existing.target} and ${target.id}`);
160
+ }
161
+ widths.set(name, { target: target.id, minWidth });
162
+ }
163
+ }
164
+ for (const target of targets) {
165
+ for (const [presetName, preset] of Object.entries(target.media?.presets ?? {})) {
166
+ for (const breakpoint of Object.keys(preset.widths)) {
167
+ if (!widths.has(breakpoint)) {
168
+ throw new Error(`Preset "${presetName}" in target ${target.id} uses unknown breakpoint "${breakpoint}"`);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ function union(a, b) {
175
+ if (!a && !b)
176
+ return undefined;
177
+ return [...new Set([...(a ?? []), ...(b ?? [])])];
178
+ }
179
+ function unionBy(list, key) {
180
+ const map = new Map();
181
+ for (const item of list)
182
+ map.set(key(item), item);
183
+ return [...map.values()];
184
+ }
185
+ function stricter(a, b, pick) {
186
+ if (a === undefined)
187
+ return b;
188
+ if (b === undefined)
189
+ return a;
190
+ return pick(a, b);
191
+ }
192
+ function allOf(a, b) {
193
+ if (!a)
194
+ return b;
195
+ if (!b)
196
+ return a;
197
+ if (deterministicStringify(a) === deterministicStringify(b))
198
+ return a;
199
+ return { allOf: [a, b] };
200
+ }
201
+ function mergeRecords(a, b, merge) {
202
+ if (!a && !b)
203
+ return undefined;
204
+ const result = { ...a };
205
+ for (const [key, value] of Object.entries(b ?? {})) {
206
+ result[key] = key in result ? merge(result[key], value) : value;
207
+ }
208
+ return result;
209
+ }
210
+ function dropUndefined(obj) {
211
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
212
+ }
213
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/core/targets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { CollectionItem, TranslationCounts, TranslationSummary } from "../types.js";
2
+ export declare const DEFAULT_SOURCE_LOCALE = "en";
3
+ export type SourceLocaleOrigin = "argument" | "source" | "inferred" | "fallback";
4
+ export interface TranslationIssue {
5
+ collection: string;
6
+ id: string;
7
+ locale: string;
8
+ field: string;
9
+ issue: "missing" | "stale";
10
+ }
11
+ export interface TranslationReport extends TranslationSummary {
12
+ sourceLocaleOrigin: SourceLocaleOrigin;
13
+ collections: Record<string, Record<string, TranslationCounts>>;
14
+ itemsWithoutSource: {
15
+ collection: string;
16
+ id: string;
17
+ }[];
18
+ issues: TranslationIssue[];
19
+ }
20
+ /**
21
+ * Hash of a source text, as stored in _provenance translation markers (sourceHash).
22
+ */
23
+ export declare function translationSourceHash(text: string): string;
24
+ /**
25
+ * Infers the source locale from _provenance translation markers: the locales of fields marked
26
+ * "original" plus all "from" locales. Returns undefined unless exactly one candidate exists.
27
+ */
28
+ export declare function inferSourceLocale(collections: Record<string, CollectionItem[]>): string | undefined;
29
+ export type ItemLocales = (collection: string, item: CollectionItem) => string[] | undefined;
30
+ /**
31
+ * Measures translation completeness against the source locale.
32
+ *
33
+ * - Expected: every source-locale field whose value is a non-empty string. Other source values are ignored.
34
+ * - Missing: the translation is absent, null or "".
35
+ * - Stale: the marker's sourceHash differs from the current source text. Without a sourceHash,
36
+ * falls back to the previous release: source text changed but the translation didn't.
37
+ * - Items restricted by itemLocales are only measured in those locales, and skipped entirely
38
+ * if they aren't used in the source locale (their texts are originals, not translations).
39
+ */
40
+ export declare function analyzeTranslations(collections: Record<string, CollectionItem[]>, sourceLocale: string, sourceLocaleOrigin: SourceLocaleOrigin, previous?: Record<string, CollectionItem[]>, itemLocales?: ItemLocales): TranslationReport;
41
+ export declare function toTranslationSummary(report: TranslationReport): TranslationSummary;