refactor: unify declare block scanning between CLI and client

Introduce `scanDeclareBlocks` in `declare-parser.ts` to provide a
single source of truth for parsing `role=declare` blocks. This
replaces redundant scanning logic in both the CLI and the journal
completions.

Also remove unused `dice.ts` and `spark-scanner.ts` files.
This commit is contained in:
2026-07-13 10:43:44 +08:00
parent 3137970b97
commit f172da378a
5 changed files with 73 additions and 220 deletions
+17 -58
View File
@@ -10,57 +10,33 @@
*/
import { createSignal } from "solid-js";
import Slugger from "github-slugger";
import { extractHeadings } from "../../data-loader/toc";
import {
getPathsByExtension,
getIndexedData,
} from "../../data-loader/file-index";
import {
FENCED_BLOCK_RE,
parseBlockAttrs,
} from "../../cli/completions/block-scanner";
import {
scanDirectives,
} from "../../cli/completions/directive-scanner";
import { parseDeclareCsv } from "./declare-parser";
import type { VarDeclaration, TagModifier } from "./declare-parser";
import { scanDeclareBlocks } from "../../cli/completions/declare-parser";
import type {
CompletionsPayload,
DiceCompletion,
LinkCompletion,
SparkTableCompletion,
VarDeclaration,
TagModifier,
} from "../../cli/completions/types";
import { initReactivity, computeInitialValues } from "./var-reactivity";
import { sendMessage, journalStreamState } from "../stores/journalStream";
export type { VarDeclaration, TagModifier };
// ------------------- Types (mirrors CLI) -------------------
// Re-export CLI types so consumers don't need to know about the CLI path
export type { DiceCompletion, LinkCompletion, SparkTableCompletion };
export interface DiceCompletion {
label: string;
notation: string;
source: string;
}
export interface LinkCompletion {
path: string;
label: string;
section: string | null;
}
export interface SparkTableCompletion {
label: string;
notation: string;
slug: string;
filePath: string;
csvPath: string;
headers: string[];
remix: boolean;
}
export interface JournalCompletions {
dice: DiceCompletion[];
links: LinkCompletion[];
sparkTables: SparkTableCompletion[];
declarations: VarDeclaration[];
tagModifiers: TagModifier[];
}
/** Convenience alias — same shape as the CLI's CompletionsPayload. */
export type JournalCompletions = CompletionsPayload;
export type CompletionsState =
| { status: "loading" }
@@ -120,9 +96,6 @@ async function scanClientSide(): Promise<JournalCompletions> {
const content = tempIndex[filePath];
if (!content) continue;
// Fresh slugger per file
const slugger = new Slugger();
// ---- Links (headings) - from original content ----
const basePath = filePath.replace(/\.md$/, "");
const fileName = basePath.split("/").filter(Boolean).pop() || basePath;
@@ -135,24 +108,10 @@ async function scanClientSide(): Promise<JournalCompletions> {
});
}
// ---- Unified block scanning (declare) ----
FENCED_BLOCK_RE.lastIndex = 0;
let blockMatch: RegExpExecArray | null;
while ((blockMatch = FENCED_BLOCK_RE.exec(content)) !== null) {
const [, lang, infoString, body] = blockMatch;
const attrs = parseBlockAttrs(infoString);
attrs.lang = attrs.lang || lang;
if (attrs.role === "declare") {
try {
const result = parseDeclareCsv(body, filePath);
declarations.push(...result.variables);
tagModifiers.push(...result.tagModifiers);
} catch (e) {
console.warn(`[completions] ${filePath}: ${e}`);
}
}
}
// ---- Declare block scanning (shared with CLI) ----
const declareResult = scanDeclareBlocks(content, filePath);
declarations.push(...declareResult.variables);
tagModifiers.push(...declareResult.tagModifiers);
// ---- Directive scanning (dice + spark tables) ----
const fileDir = filePath.split("/").slice(0, -1).join("/") || ".";