Files
dooring/packages/dooringx-doc/src/routes/docs/_api.ts

127 lines
3.1 KiB
TypeScript
Raw Normal View History

2021-07-09 01:41:03 +08:00
import fs from 'fs';
import path from 'path';
import marked from 'marked';
import { extract_frontmatter } from '../../utils/markdown';
import { highlight } from '../../utils/highlight';
import slugf from 'slug';
export interface MarkDownItemProps {
html: string;
metadata: Record<string, string>;
subsections: { slug: string; title: string; level: string }[];
slug: string;
file: string;
order: number;
sTitle: string;
}
export async function api(name: string) {
const res = await getMarkDown(name);
return {
status: 200,
body: res,
};
}
const blockTypes = [
'blockquote',
'html',
'heading',
'hr',
'list',
'listitem',
'paragraph',
'table',
'tablerow',
'tablecell',
];
export const getMarkDown = (name: string) => {
const root = process.cwd();
const docPath = path.resolve(root, 'src', name);
return fs
.readdirSync(docPath)
.filter((file) => file[0] !== '.' && path.extname(file) === '.md')
.map((file) => {
const currentFilePath = path.resolve(docPath, file);
const markdown = fs.readFileSync(currentFilePath, 'utf-8');
const { content, metadata } = extract_frontmatter(markdown);
const order = parseFloat(metadata.order);
const sTitle = metadata.sTitle;
const subsections = [];
const section_slug = slugf(metadata.title, '_');
const renderer = new marked.Renderer();
let block_open = false;
renderer.hr = () => {
block_open = true;
return '<div class="side-by-side"><div class="copy">';
};
renderer.code = (source, lang) => {
source = source.replace(/^ +/gm, (match) => match.split(' ').join('\t'));
let prefix = '';
let className = 'code-block';
const html = `<div class='${className}'>${prefix}${highlight(source, lang)}</div>`;
if (block_open) {
block_open = false;
return `</div><div class="code">${html}</div></div>`;
}
return html;
};
// 这个heading是md的标题
renderer.heading = (text, level, rawtext) => {
let slug;
const match = /<a href="([^"]+)"[^>]*>(.+)<\/a>/.exec(text); // 提取a标签链接为slug
if (match) {
slug = match[1];
text = match[2];
} else {
slug = slugf(rawtext, '_');
}
if (level === 1 || level === 2 || level === 3 || level === 4) {
const title = text
.replace(/<\/?code>/g, '')
.replace(/\.(\w+)(\((.+)?\))?/, (m, $1, $2, $3) => {
if ($3) return `.${$1}(...)`;
if ($2) return `.${$1}()`;
return `.${$1}`;
});
subsections.push({ slug, title, level });
}
return `
<h${level + 1}>
<span id="${slug}" ></span>
<a href="docs#${slug}" class="anchor" aria-hidden="true"></a>
${text}
</h${level + 1}>`;
};
blockTypes.forEach((type) => {
const fn = renderer[type];
renderer[type] = function () {
return fn.apply(this, arguments);
};
});
const html = marked(content, { renderer });
const hashes = {};
return {
html: html.replace(/@@(\d+)/g, (m, id) => hashes[id] || m),
metadata,
subsections,
slug: section_slug,
order,
file,
sTitle,
};
})
.sort((a, b) => a.order - b.order);
};