refactor: replace stat-parser with declare-parser

Replace the old stat-parser logic with a new declare-parser to handle
variable declarations and tag modifiers. This includes moving the
declare-parser logic to a shared location in cli/completions to avoid
duplication between the CLI and the journal component.
This commit is contained in:
2026-07-12 19:14:35 +08:00
parent dbe2f9d9d8
commit 981c829d0f
8 changed files with 158 additions and 547 deletions
+14 -34
View File
@@ -7,14 +7,7 @@
import { posix } from "path";
import { createHash } from "crypto";
import {
parseStatYaml,
parseStatCsv,
parseTemplateCsv,
parseStatModifiers,
type StatDef,
type StatTemplate,
} from "./stat-parser.js";
import { parseDeclareCsv, type VarDeclaration, type TagModifier } from "./declare-parser.js";
import {
FENCED_BLOCK_RE,
parseBlockAttrs,
@@ -34,8 +27,8 @@ export {
// ---------------------------------------------------------------------------
export interface ProcessedBlocks {
stats: StatDef[];
statTemplates: StatTemplate[];
declarations: VarDeclaration[];
tagModifiers: TagModifier[];
}
export interface BlockResult {
@@ -62,7 +55,7 @@ function contentHash(body: string): string {
*
* - Strips/replaces blocks based on `as`
* - Injects `role=file` bodies into the content index
* - Collects stat/template blocks for completions
* - Collects declare blocks for completions
* - role=spark-table blocks are converted to :md-table directives
* (spark table completions are collected later by the directive scanner)
*/
@@ -74,8 +67,8 @@ export function processBlocks(
const fileDir = posix.dirname(fileRelativePath);
const blocks: ProcessedBlocks = {
stats: [],
statTemplates: [],
declarations: [],
tagModifiers: [],
};
const stripped = content.replace(
@@ -92,29 +85,16 @@ export function processBlocks(
// ---- Dispatch by role ----
if (attrs.role === "stat") {
if (attrs.lang === "yaml" || attrs.lang === "yml") {
blocks.stats.push(...parseStatYaml(body, fileRelativePath));
} else if (attrs.lang === "csv") {
blocks.stats.push(...parseStatCsv(body, fileRelativePath));
if (attrs.role === "declare") {
try {
const result = parseDeclareCsv(body, fileRelativePath);
blocks.declarations.push(...result.variables);
blocks.tagModifiers.push(...result.tagModifiers);
} catch (e) {
console.warn(`[block-processor] ${fileRelativePath}: ${e}`);
}
}
if (attrs.role === "stat-template") {
const name = attrs.id || `_tpl_${contentHash(body)}`;
blocks.statTemplates.push(
parseTemplateCsv(body, fileRelativePath, name),
);
}
if (attrs.role === "stat-modifiers") {
const id = attrs.id || `_mod_${contentHash(body)}`;
const result = parseStatModifiers(body, fileRelativePath, id, "player", attrs.extra["label"]);
blocks.stats.push(result.statDef);
blocks.stats.push(...result.modifierDefs);
blocks.statTemplates.push(result.template);
}
if (attrs.role === "file") {
const filename = attrs.id
? `${attrs.id}.${attrs.lang || "txt"}`
@@ -161,4 +141,4 @@ export function processBlocks(
);
return { stripped, blocks };
}
}