refactor(cli): centralize content registry building
Extract buildRegistryFromIndex and normalizePathKey from the CLI serve command and the browser completions module into the shared content-registry module. This ensures both paths produce identical pathIndex/docContent, including the spark-injection pass that was previously only applied in the CLI.
This commit is contained in:
@@ -63,6 +63,16 @@ export const EMPTY_REGISTRY: ContentRegistry = {
|
||||
docContent: {},
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize a file path into a stable registry key: forward slashes and a
|
||||
* single leading `/`. Both the CLI filesystem walk and the browser folder
|
||||
* scan funnel through this so identical files always share a key.
|
||||
*/
|
||||
export function normalizePathKey(path: string): string {
|
||||
const normalized = path.split("\\").join("/");
|
||||
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Id / hash derivation (single source of truth)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -185,6 +195,46 @@ export function scanDoc(content: string, docPath: string): DocScanResult {
|
||||
return { stripped: rewritten, content: contentStore };
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a `ContentRegistry` from a raw `{ path: content }` index.
|
||||
*
|
||||
* Shared by the CLI (`buildRegistry` in `commands/serve.ts`) and the browser
|
||||
* folder scan (`scanClientSide` in `components/journal/completions.ts`) so
|
||||
* both modes produce identical `pathIndex`/`docContent` — including the
|
||||
* `data-spark` injection pass that only the CLI used to run.
|
||||
*
|
||||
* Keys are normalized via `normalizePathKey`; `.md` files are run through
|
||||
* `scanDoc` and the spark-injection pass, other extensions are stored raw.
|
||||
*/
|
||||
export function buildRegistryFromIndex(
|
||||
index: Record<string, string>,
|
||||
): ContentRegistry {
|
||||
const registry: ContentRegistry = { pathIndex: {}, docContent: {} };
|
||||
|
||||
for (const [rawPath, content] of Object.entries(index)) {
|
||||
const path = normalizePathKey(rawPath);
|
||||
if (path.endsWith(".md")) {
|
||||
const result = scanDoc(content, path);
|
||||
registry.pathIndex[path] = result.stripped;
|
||||
registry.docContent[path] = result.content;
|
||||
} else {
|
||||
registry.pathIndex[path] = content;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject data-spark into real-file spark table directives (idempotent).
|
||||
for (const [relPath, content] of Object.entries(registry.pathIndex)) {
|
||||
if (!relPath.endsWith(".md")) continue;
|
||||
registry.pathIndex[relPath] = injectSparkDirectives(
|
||||
content,
|
||||
relPath,
|
||||
registry,
|
||||
);
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Spark table coercion
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user