/*
App-agnostic utility functions for normalizing Astro content entry IDs and extracting
language codes from them. Shared across all apps in apps/*; no app-specific imports allowed.
- Do not import from apps/* or astro:content.
- Do not perform schema validation or runtime data fetching.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
*/
// Shared entity-ID normalization for all schema dispatchers.
// Source: app content schemas/entity-id (migrated to packages/share).
export function toDataEntryId(entry: string): string {
return entry.replace(/\\/g, "/").replace(/\.md$/i, "");
}
export function getEntryLanguage(id: string): string | null {
const [firstSegment] = toDataEntryId(id).split("/");
if (!firstSegment || !/^[a-z]{2}$/i.test(firstSegment)) {
return null;
}
return firstSegment;
}
export function stripEntryLanguage(id: string): string {
const normalizedId = toDataEntryId(id);
const entryLanguage = getEntryLanguage(normalizedId);
if (!entryLanguage) {
return normalizedId;
}
return normalizedId.slice(entryLanguage.length + 1);
}
export function pageIdToContentFileSlug(pageId: string): string {
return pageId
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
.toLowerCase();
}
/**
* Creates a schema lookup function keyed by normalized entry ID.
*/
export function createDispatcherResolver(schemaMap: Record) {
return (entryId: string): T | undefined => {
const schemaId = stripEntryLanguage(toDataEntryId(entryId));
if (!(schemaId in schemaMap)) {
return undefined;
}
return schemaMap[schemaId];
};
}