- Split loadCSV into parseCSVString (content) and loadCSVFromPath (path); drop isCSV/looksLikeCsv heuristics - Delete coerceSparkTables and markedTable label-header magic; plain markdown tables now render as plain tables - Add explicit markdown role=spark-table fence syntax that converts pipe tables to CSV at scan time, with dice-header validation - Map ESM-only github-slugger and csv-parse browser build to CJS in jest config; add content-registry tests
169 lines
4.3 KiB
TypeScript
169 lines
4.3 KiB
TypeScript
import { createStore } from "solid-js/store";
|
|
import type { MdCommanderCommand, MdCommanderCommandMap } from "../types";
|
|
import { setupHelpCommand, clearCommand, rollCommand, trackCommand, untrackCommand, listTrackCommand } from "../commands";
|
|
import {resolvePath} from "../../utils/path";
|
|
import {loadCSVFromPath} from "../../utils/csv-loader";
|
|
|
|
const defaultCommands: MdCommanderCommandMap = {
|
|
help: setupHelpCommand({}),
|
|
clear: clearCommand,
|
|
roll: rollCommand,
|
|
track: trackCommand,
|
|
untrack: untrackCommand,
|
|
list: listTrackCommand,
|
|
};
|
|
|
|
export interface CommandsStoreState {
|
|
commands: MdCommanderCommandMap;
|
|
initialized: boolean;
|
|
loading: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
const [commandsStore, setCommandsStore] = createStore<CommandsStoreState>({
|
|
commands: { ...defaultCommands },
|
|
initialized: false,
|
|
loading: false,
|
|
});
|
|
|
|
/**
|
|
* 初始化命令(包括 help 命令的动态更新)
|
|
*/
|
|
export function initializeCommands(customCommands?: MdCommanderCommandMap): MdCommanderCommandMap {
|
|
const commands = { ...defaultCommands, ...customCommands };
|
|
// 更新 help 命令的命令列表
|
|
commands.help = setupHelpCommand(commands);
|
|
return commands;
|
|
}
|
|
|
|
/**
|
|
* 注册命令到 store
|
|
*/
|
|
export function registerCommands(customCommands?: MdCommanderCommandMap): void {
|
|
const commands = initializeCommands(customCommands);
|
|
setCommandsStore({ commands, initialized: true, loading: false });
|
|
}
|
|
|
|
/**
|
|
* 从 store 获取命令
|
|
*/
|
|
export function getCommands(): MdCommanderCommandMap {
|
|
return commandsStore.commands;
|
|
}
|
|
|
|
/**
|
|
* 检查命令是否已初始化
|
|
*/
|
|
export function isCommandsInitialized(): boolean {
|
|
return commandsStore.initialized;
|
|
}
|
|
|
|
/**
|
|
* 获取单个命令
|
|
*/
|
|
export function getCommand(name: string): MdCommanderCommand | undefined {
|
|
return commandsStore.commands[name];
|
|
}
|
|
|
|
/**
|
|
* 获取加载状态
|
|
*/
|
|
export function getCommandsLoading(): boolean {
|
|
return commandsStore.loading;
|
|
}
|
|
|
|
/**
|
|
* 获取错误信息
|
|
*/
|
|
export function getCommandsError(): string | undefined {
|
|
return commandsStore.error;
|
|
}
|
|
|
|
/**
|
|
* 设置加载状态
|
|
*/
|
|
export function setCommandsLoading(loading: boolean): void {
|
|
setCommandsStore("loading", loading);
|
|
}
|
|
|
|
/**
|
|
* 设置错误信息
|
|
*/
|
|
export function setCommandsError(error?: string): void {
|
|
setCommandsStore("error", error);
|
|
}
|
|
|
|
/**
|
|
* 更新命令
|
|
*/
|
|
export function updateCommands(updater: (prev: MdCommanderCommandMap) => MdCommanderCommandMap): void {
|
|
setCommandsStore("commands", (prev) => updater(prev));
|
|
}
|
|
|
|
/**
|
|
* 从 CSV 文件加载命令模板并更新命令定义
|
|
*/
|
|
export async function loadCommandTemplatesFromCSV(
|
|
path: string,
|
|
articlePath: string
|
|
): Promise<void> {
|
|
setCommandsLoading(true);
|
|
setCommandsError(undefined);
|
|
|
|
try {
|
|
const csv = await loadCSVFromPath<CommandTemplateRow>(resolvePath(articlePath, path));
|
|
|
|
// 按命令分组模板
|
|
const templatesByCommand = new Map<string, CommandTemplateRow[]>();
|
|
for (const row of csv) {
|
|
if (!row.command || !row.label || !row.insertedText) continue;
|
|
|
|
if (!templatesByCommand.has(row.command)) {
|
|
templatesByCommand.set(row.command, []);
|
|
}
|
|
templatesByCommand.get(row.command)!.push(row);
|
|
}
|
|
|
|
// 为每个命令添加模板
|
|
updateCommands((prev) => {
|
|
const updated = { ...prev };
|
|
for (const [commandName, rows] of templatesByCommand.entries()) {
|
|
const cmd = updated[commandName];
|
|
if (!cmd || !cmd.parameters) continue;
|
|
|
|
const templates = rows.map((row) => ({
|
|
label: row.label,
|
|
description: row.description || "",
|
|
insertText: row.insertedText,
|
|
}));
|
|
|
|
// 为每个参数添加模板
|
|
updated[commandName] = {
|
|
...cmd,
|
|
parameters: cmd.parameters.map((param) => ({
|
|
...param,
|
|
templates: param.templates ? [...param.templates, ...templates] : templates,
|
|
})),
|
|
};
|
|
}
|
|
return updated;
|
|
});
|
|
|
|
setCommandsStore("initialized", true);
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
setCommandsError(`加载命令模板失败:${errorMessage}`);
|
|
console.warn(`Error loading command templates from ${path}:`, error);
|
|
} finally {
|
|
setCommandsLoading(false);
|
|
}
|
|
}
|
|
|
|
interface CommandTemplateRow {
|
|
command: string;
|
|
parameter: string;
|
|
label: string;
|
|
description: string;
|
|
insertedText: string;
|
|
}
|