refactor: remove as= override and render data-spark at runtime

- Drop resolveBlockAs and the as= attribute; scanDoc now switches
  directly on role and warns on unknown roles instead of silently
  stripping
- md-table derives data-spark from its loaded CSV via
  parseSparkTableCsv; delete injectSparkDirectives and the second
  registry pass so pathIndex is exactly scanDoc output
- Align spark-table dice header regex with isSparkTableHeader
This commit is contained in:
2026-09-08 22:18:12 +08:00
parent 256c685f6c
commit b7a804f1cf
8 changed files with 131 additions and 201 deletions
+3 -3
View File
@@ -110,7 +110,7 @@ async function scanClientSide(): Promise<JournalCompletions> {
const paths = await getPathsByExtension("md");
// Load all .md content into a raw index, then build the registry through
// the same shared pipeline as the CLI (scanDoc + spark injection).
// the same shared pipeline as the CLI (scanDoc).
const index: Record<string, string> = {};
for (const filePath of paths) {
const content = await getIndexedData(filePath);
@@ -122,8 +122,8 @@ async function scanClientSide(): Promise<JournalCompletions> {
activeRegistry = registry;
// Write the processed (stripped) content back into the file index so
// Article/md-embed render the same content as CLI mode (spark tables
// coerced, attributed blocks processed, data-spark injected).
// Article/md-embed render the same content as CLI mode (attributed blocks
// processed by role).
for (const [path, content] of Object.entries(registry.pathIndex)) {
setIndexedData(path, content);
}
+15 -7
View File
@@ -10,10 +10,11 @@ import {
import { parseMarkdown } from "../markdown";
import { parseCSVString, CSV, processVariables } from "./utils/csv-loader";
import { resolveContentRef } from "./utils/resolve-content";
import { parseSparkTableCsv } from "./utils/spark-table";
import {
areAllLabelsNumeric,
weightedRandomIndex,
} from "./utils/weighted-random";
} from "./utils/weighted-random";;
export interface TableProps {
roll?: boolean;
@@ -59,16 +60,23 @@ customElement(
if (content === null) {
throw new Error(`Failed to resolve table content: "${ref}"`);
}
return parseCSVString(content);
return content;
},
);
// 当数据加载完成后更新 rows
// 当数据加载完成后更新 rows,并为火花表设置 data-spark(供 RevealManager
// 悬停触发 /roll)。data-spark 在渲染时派生,不在扫描时注入。
createEffect(() => {
const data = csvData();
if (data) {
// 将加载的数据赋值给 rows,CSV 类型已经包含 sourcePath 等属性
setRows(data as unknown as CSV<TableRow>);
const content = csvData();
if (!content) return;
setRows(parseCSVString(content) as unknown as CSV<TableRow>);
if (element) {
const meta = parseSparkTableCsv(content);
if (meta) {
element.setAttribute("data-spark", meta.slug);
} else {
element.removeAttribute("data-spark");
}
}
});
+3 -1
View File
@@ -53,7 +53,9 @@ export interface SparkTableMeta {
// CSV parsing
// ---------------------------------------------------------------------------
const DICE_HEADER_RE = /^d\d+$/i;
// Matches the scanner's `isSparkTableHeader` (content-registry): plain dice,
// counts, and modifiers all count as spark-table first columns.
const DICE_HEADER_RE = /^\d*d\d+(?:[+-]\d+)?$/i;
/**
* Parse a CSV string into a SparkTableMeta.