refactor: remove implicit content sniffing and table conversion
- 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
This commit is contained in:
@@ -2,7 +2,7 @@ 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 {loadCSV} from "../../utils/csv-loader";
|
||||
import {loadCSVFromPath} from "../../utils/csv-loader";
|
||||
|
||||
const defaultCommands: MdCommanderCommandMap = {
|
||||
help: setupHelpCommand({}),
|
||||
@@ -111,7 +111,7 @@ export async function loadCommandTemplatesFromCSV(
|
||||
setCommandsError(undefined);
|
||||
|
||||
try {
|
||||
const csv = await loadCSV<CommandTemplateRow>(resolvePath(articlePath, path));
|
||||
const csv = await loadCSVFromPath<CommandTemplateRow>(resolvePath(articlePath, path));
|
||||
|
||||
// 按命令分组模板
|
||||
const templatesByCommand = new Map<string, CommandTemplateRow[]>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createStore } from "solid-js/store";
|
||||
import yaml from "js-yaml";
|
||||
import { calculateDimensions } from "./dimensions";
|
||||
import { loadCSV, CSV } from "../../utils/csv-loader";
|
||||
import { loadCSVFromPath, CSV } from "../../utils/csv-loader";
|
||||
import { formatLayers } from "./layer-parser";
|
||||
import * as layerCrud from "./layer-crud";
|
||||
import type {
|
||||
@@ -461,7 +461,7 @@ export function createDeckStore(initialSrc: string = ""): DeckStore {
|
||||
setState({ isLoading: true, error: null, src: path, rawSrc: rawSrc });
|
||||
|
||||
try {
|
||||
const data = await loadCSV(path);
|
||||
const data = await loadCSVFromPath(path);
|
||||
|
||||
if (data.length === 0) {
|
||||
setState({
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
createResource,
|
||||
} from "solid-js";
|
||||
import { parseMarkdown } from "../markdown";
|
||||
import { loadCSV, CSV, processVariables } from "./utils/csv-loader";
|
||||
import { parseCSVString, CSV, processVariables } from "./utils/csv-loader";
|
||||
import { resolveContentRef } from "./utils/resolve-content";
|
||||
import {
|
||||
areAllLabelsNumeric,
|
||||
@@ -59,7 +59,7 @@ customElement(
|
||||
if (content === null) {
|
||||
throw new Error(`Failed to resolve table content: "${ref}"`);
|
||||
}
|
||||
return loadCSV(content);
|
||||
return parseCSVString(content);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -31,42 +31,6 @@ function parseFrontMatter(content: string): { frontmatter?: JSONObject; remainin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测字符串是否是 CSV 格式
|
||||
* @param str 待检测的字符串
|
||||
* @returns 如果是 CSV 格式返回 true
|
||||
*/
|
||||
export function isCSV(str: string): boolean {
|
||||
const trimmed = str.trim();
|
||||
|
||||
// 检查是否以 YAML front matter 开头
|
||||
if (trimmed.startsWith('---\n') || trimmed.startsWith('---\r\n')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查是否包含 CSV 特征:多行且有分隔符
|
||||
const lines = trimmed.split(/\r?\n/).filter(line => line.trim() !== '');
|
||||
if (lines.length < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测常见 CSV 分隔符
|
||||
const separators = [',', '\t', ';', '|'];
|
||||
const firstLine = lines[0];
|
||||
|
||||
for (const sep of separators) {
|
||||
if (firstLine.includes(sep)) {
|
||||
// 检查其他行是否也有相同的分隔符
|
||||
const hasSeparatorInOtherLines = lines.slice(1).some(line => line.includes(sep));
|
||||
if (hasSeparatorInOtherLines) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 CSV 字符串
|
||||
* @template T 返回数据的类型,默认为 Record<string, string>
|
||||
@@ -102,18 +66,12 @@ export function parseCSVString<T = Record<string, string>>(csvString: string, so
|
||||
/**
|
||||
* 加载 CSV 文件
|
||||
* @template T 返回数据的类型,默认为 Record<string, string>
|
||||
* @param pathOrContent 文件路径或 inline CSV 字符串
|
||||
* @param path 文件路径(通过 file-index 获取内容)
|
||||
* @returns 解析后的 CSV 数据
|
||||
*/
|
||||
export async function loadCSV<T = Record<string, string>>(pathOrContent: string): Promise<CSV<T>> {
|
||||
// 检测是否是 inline CSV 数据
|
||||
if (isCSV(pathOrContent)) {
|
||||
return parseCSVString<T>(pathOrContent, 'inline');
|
||||
}
|
||||
|
||||
// 从索引获取文件内容
|
||||
const content = await getIndexedData(pathOrContent);
|
||||
return parseCSVString<T>(content, pathOrContent);
|
||||
export async function loadCSVFromPath<T = Record<string, string>>(path: string): Promise<CSV<T>> {
|
||||
const content = await getIndexedData(path);
|
||||
return parseCSVString<T>(content, path);
|
||||
}
|
||||
|
||||
type JSONData = JSONArray | JSONObject | string | number | boolean | null;
|
||||
|
||||
Reference in New Issue
Block a user