vite-bolt/plugin/initialize.ts

194 lines
3.6 KiB
TypeScript
Raw Permalink Normal View History

2023-02-01 17:52:53 +08:00
import path from "path";
import fs from "fs";
import TsToJson from "./ts2json";
import toc from "markdown-toc";
import objHash from "object-hash";
const hash = (str: string) => "" + objHash(str).substring(0, 6);
/**
* props
*/
interface IPropMeta {
/**
* ts ?
*/
required?: boolean;
/**
* @name
*/
name?: string;
/**
* @type
*/
type?: string;
/**
* @description
*/
description?: string;
/**
* @default
*/
default?: string;
/**
* @version
*/
version?: string | number;
}
interface IProp2jsonItem {
[key: string]: {
props: IPropMeta[];
};
}
interface IRoute {
active: false;
path: string;
name: string;
}
export interface ITree {
/**
* 🎄
*/
compoTree: ICompoTree;
/**
* 🎄
*/
fileTree?: {};
/**
* 🎄 menuTree
*/
routerList: IRoute[];
/**
*
*/
config?: {};
}
interface ITocItem {
/**
* hash
*/
anchor?: string;
/**
* mardkown h标签 innerHTML
*/
content: string;
i: 0;
lvl: 1;
seen: 0;
/**
* innerHTML
*/
slug: "hi";
}
/**
* ts interface json
*/
const tsParser = new TsToJson();
/**
*
*/
const root = path.resolve(process.cwd(), "src/components");
/**
* For HMR
*/
const fileTree = {};
/**
* ICompoTree Item
*/
interface ICompoMetadata {
/**
* props
*/
props: IPropMeta[] | [];
/**
* markdown table of content
*/
toc: ITocItem[];
}
/**
* 🎄
*/
interface ICompoTree {
[key: string]: ICompoMetadata;
}
/**
* markdown table of content
* @param {string} content markdown
*/
const md2toc = (content: string) => {
if (!content) return [];
return toc(content).json;
};
/**
*
* @param {ICompoTree} compoTree
*/
const processRouter = (compoTree: ICompoTree): IRoute[] => {
return Object.keys(compoTree).map((t) => ({
active: false,
path: t.toLowerCase(),
name: t,
}));
};
/**
* props.ts json
* @param {string} path props.ts
* @returns
*/
const parsePropsTs = (path: string) => {
const prop2json: IProp2jsonItem = fs.existsSync(path)
? tsParser.parse(path)
: {};
return Object.values(prop2json)?.[0]?.props ?? [];
};
/**
* mdx
* @param {string} path mdx
*/
const parseToc = (path: string) => {
const isFile = fs.statSync(path).isFile();
const mdxContent = isFile ? fs.readFileSync(path).toString() : "";
// 注入锚点 hash
const toc = md2toc(mdxContent).map((i) => ({
...i,
anchor: `anchor-${hash(i.content)}`,
}));
return toc;
};
const walkCompoMetadata = (dirs: string[]): ICompoTree => {
const compoTree: ICompoTree = {};
dirs.forEach((dir) => {
const mdxFile = path.resolve(root, dir, "index.mdx");
const propFile = path.resolve(root, dir, "props.ts");
fileTree[mdxFile] = dir;
fileTree[propFile] = dir;
const toc = parseToc(mdxFile);
const props = parsePropsTs(propFile);
compoTree[dir] = { toc, props };
});
return compoTree;
};
/**
*
* @returns menuTree: 目录树, markdownHeadings | propsTree: 组件 api
*/
export const initialize = (): ITree => {
const dirs = fs.existsSync(root) ? fs.readdirSync(root) : [];
const compoTree = walkCompoMetadata(dirs);
const routerList = processRouter(compoTree);
return { compoTree, fileTree, routerList };
};