♻️(document): 调整文档结构

This commit is contained in:
就眠儀式
2022-06-25 20:10:12 +08:00
parent d18425cb2a
commit b86b7d308c
166 changed files with 528 additions and 60 deletions

View File

@@ -0,0 +1,42 @@
import vue from "@vitejs/plugin-vue";
import Markdown from "vite-plugin-md";
import container from "markdown-it-container";
import preWrapper from "./pre-wrapper";
import highlight from "./highlight";
import snippet from "./snippet";
import demo from "./create-demo";
import createTitle from "./create-title";
import createQuote from "./create-quote";
import createDescribe from "./create-describe";
import createTable from "./create-table";
import createAnchor from "./create-anchor";
import createPreviousNext from "./create-previous-next";
import createContributor from "./create-contributor";
const plugins = [
vue({
include: [/\.vue$/, /\.md$/],
}),
Markdown({
markdownItOptions: {
html: true,
linkify: true,
typographer: true,
highlight,
},
markdownItSetup(md) {
md.use(snippet)
.use(preWrapper)
.use(container, "demo", demo)
.use(...createTable("table"))
.use(...createQuote("quote"))
.use(...createTitle("title"))
.use(...createDescribe("describe"))
.use(...createAnchor("anchor"))
.use(...createPreviousNext("previousNext"))
.use(...createContributor("contributor"));
},
}),
] as any;
export default plugins;

View File

@@ -0,0 +1,33 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{ render(tokens: Token[], idx: number): string }
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
if (token.nesting === 1) {
const anchors = [];
for (const token of tokens) {
if (token.nesting === 1 && token.info.includes("title")) {
const info = token.info.trim().slice(klass.length).trim();
anchors.push(info);
}
}
// 此处仅支持 string | number | boolean 类型
return `<lay-anchor anchors="${anchors}" :currIndex="-1" :show="true">`;
} else {
return "</lay-anchor>\n";
}
},
},
];
}

View File

@@ -0,0 +1,28 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{
render(tokens: Token[], idx: number): string;
}
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
if (token.nesting === 1) {
return `<lay-contributor file-path='${info}'></lay-contributor>`;
} else {
return ``;
}
},
},
];
}

View File

@@ -0,0 +1,140 @@
import markdown from "markdown-it";
import highlight from "./highlight";
import type Token from "markdown-it/lib/token";
function assignScript(script: string) {
const dependencies = {} as Record<string, string[]>;
const attrs = {} as Record<string, string>;
const content = script
.replace(/import\s?\{.*\}.*/g, (item) => {
const key = getInnerString(item.replace(/'/g, '"'), '"', '"');
const value = getInnerString(item.replace(/\s+/g, ""), "{", "}");
const list = value ? value.split(",") : [];
if (key && dependencies[key]) {
dependencies[key] = dependencies[key].concat(list);
} else if (key) {
dependencies[key] = list;
}
return "";
})
/**
* const -> let
*
* const a = -> let a =
* const a = -> a =
*/
.replace(/(const|let|var)\s\w*\s?=/g, (item) => {
const attr = getInnerString(item, "\\s", "\\s?=");
if (attr && !(attr in attrs)) {
attrs[attr] = attr;
return `let ${attr} =`;
} else {
return attr + " =";
}
})
// Remove extra line breaks
.replace(/\n+/gm, "\n");
// Combine the import
const reImport = Object.keys(dependencies).reduce((all, item) => {
const filterAttrs = [...new Set(dependencies[item])];
return all + `import {${filterAttrs + ","}} from '${item}';\n`;
}, "");
return reImport + content;
}
/**
* Extract part of the new string from the middle of the string
* @param {string} string string
* @param {string} prefix RegExp string
* @param {string} postfix RegExp string
* @param {string} type g | m | i
*/
function getInnerString(
string: string,
prefix: string,
postfix = "",
type: "i" | "g" | "m" = "i"
): string | undefined {
const result = new RegExp(`${prefix}(.*)${postfix}`, type);
const match = string.match(result);
return match ? match[1].trim() : undefined;
}
let script = ""; // Record the <script> label of the current page
export default {
render: (tokens: Token[], idx: number): string => {
// the `demo` block of the current page
const htmlBlock = tokens.filter((item) => item.type === "html_block");
const { nesting, info = "", map } = tokens[idx];
if (nesting === -1) {
return "</lay-code>";
}
const matchedInfo = info.trim().match(/^demo\s+(.*)$/);
const description = matchedInfo && matchedInfo[1];
const descTemplate = markdown().render(description || "");
let str = ""; // copy the current `demo` block code
let lastLine = NaN;
for (let i = 0; i < htmlBlock.length; i++) {
const item = htmlBlock[i];
if (item.map && map && item.map[0] >= map[0] && item.map[1] <= map[1]) {
const { map, content } = item;
const delta = map[0] - (lastLine || map[1]);
if (delta > 0) {
str += "\n".repeat(delta);
}
str += content;
lastLine = map[1];
if (i === 0) {
script = "";
}
// Remove top <template>
if (/^<template>/.test(content)) {
const reContent = content.match(/^<template>((\s|\S)*)<\/template>/m);
htmlBlock[i].content = (reContent && reContent[1]) || "";
}
// Extract the <script> label content
if (content.includes("<script")) {
if (/export\sdefault\s?\{/m.test(content)) {
const setup = content.match(
/setup\s?\(\)\s?\{((\s|\S)*)return\s?\{/m
);
const reContent = content.replace(
/export\sdefault\s?\{((\s|\S)*)\}/m,
(setup && setup[1]) || ""
);
const reScript = reContent.match(
/^<script\s?.*?>((\s|\S)*)<\/script>/m
);
script += (reScript && reScript[1]) || "";
} else {
const reScript = content.match(
/^<script\s?.*?>((\s|\S)*)<\/script>/m
);
script += (reScript && reScript[1]) || "";
}
htmlBlock[i].content = "";
}
// Change the last content to <script> of the current page
if (i + 1 === htmlBlock.length) {
htmlBlock[i].content = `
<script setup>
${assignScript(script)}
</script>`;
}
}
}
return `
<lay-code>
${description ? `<template #description>${descTemplate}</template>` : ""}
<template #code>${highlight(str, "vue")}</template>
`;
},
};

View File

@@ -0,0 +1,26 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{ render(tokens: Token[], idx: number): string }
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
if (token.nesting === 1) {
return `<p style="padding-left: 30px;padding-top: 20px;padding-bottom: 20px;">${info}`;
} else {
return "</p>\n";
}
},
},
];
}

View File

@@ -0,0 +1,52 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
import menus from "../view/utils/menus";
type ContainerArgs = [
typeof container,
string,
{
render(tokens: Token[], idx: number): string;
}
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
const menusChild = menus.map((item) => item.children).flat(1);
let prevIndex = 0;
let nextIndex = 0;
menusChild.forEach((item, index) => {
if (item.subTitle === info) {
prevIndex = index - 1;
nextIndex = index + 1;
}
});
if (token.nesting === 1) {
return `<div style="display: flex; justify-content: space-between; margin-top:20px;">
<div><router-link to="${
menusChild[prevIndex]?.path
}" class="lay-link" style="display: ${
prevIndex < 0 ? "none" : ""
}"> <lay-icon type="layui-icon-left"/>${
menusChild[prevIndex]?.title
}</router-link></div>
<div><router-link to="${
menusChild[nextIndex]?.path
}" class="lay-link" style="display: ${
nextIndex >= menusChild.length ? "none" : ""
}">${
menusChild[nextIndex]?.title
} <lay-icon type="layui-icon-right"/></router-link> </div>
</div>`;
} else {
return ``;
}
},
},
];
}

View File

@@ -0,0 +1,26 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{ render(tokens: Token[], idx: number): string }
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
if (token.nesting === 1) {
return `<lay-quote style="margin-left:0px;margin-right:0px;margin-top:20px;margin-bottom:40px;">${info}`;
} else {
return "</lay-quote>\n";
}
},
},
];
}

View File

@@ -0,0 +1,26 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{ render(tokens: Token[], idx: number): string }
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
if (token.nesting === 1) {
return `<lay-table-box>${info}`;
} else {
return "</lay-table-box>\n";
}
},
},
];
}

View File

@@ -0,0 +1,26 @@
import container from "markdown-it-container";
import type Token from "markdown-it/lib/token";
type ContainerArgs = [
typeof container,
string,
{ render(tokens: Token[], idx: number): string }
];
export default function createContainer(klass: string): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx];
const info = token.info.trim().slice(klass.length).trim();
if (token.nesting === 1) {
return `<lay-field id="${info}" title="${info}" style="margin-top:21px;margin-bottom: 20px;">`;
} else {
return "</lay-field>\n";
}
},
},
];
}

View File

@@ -0,0 +1,44 @@
import prism from "prismjs";
import loadLanguages from "prismjs/components/index";
import escapeHtml from "escape-html";
loadLanguages(["markup", "css", "javascript"]);
function wrap(code: string, lang: string): string {
if (lang === "text") {
code = escapeHtml(code);
}
return `<pre v-pre><code>${code}</code></pre>`;
}
export default (str: string, lang: string): string => {
if (!lang) {
return wrap(str, "text");
}
lang = lang.toLowerCase();
const rawLang = lang;
if (lang === "vue" || lang === "html") {
lang = "markup";
}
if (lang === "md") {
lang = "markdown";
}
if (lang === "ts") {
lang = "typescript";
}
if (lang === "py") {
lang = "python";
}
if (!prism.languages[lang]) {
try {
loadLanguages([lang]);
} catch (e) {
console.warn(lang, e);
}
}
if (prism.languages[lang]) {
const code = prism.highlight(str, prism.languages[lang], lang);
return wrap(code, rawLang);
}
return wrap(str, "text");
};

View File

@@ -0,0 +1,11 @@
import MarkdownIt from "markdown-it";
export default (md: MarkdownIt): void => {
const fence = md.renderer.rules.fence!;
md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args;
const token = tokens[idx];
const rawCode = fence(...args);
return `<div class="language-${token.info.trim()}">${rawCode}</div>`;
};
};

View File

@@ -0,0 +1,39 @@
import fs from "fs";
import MarkdownIt from "markdown-it";
import { RuleBlock } from "markdown-it/lib/parser_block";
export default (md: MarkdownIt): void => {
const parser: RuleBlock = (state, startLine, endLine, silent) => {
const CH = "<".charCodeAt(0);
const pos = state.bMarks[startLine] + state.tShift[startLine];
const max = state.eMarks[startLine];
if (state.sCount[startLine] - state.blkIndent >= 4) {
return false;
}
for (let i = 0; i < 3; ++i) {
const ch = state.src.charCodeAt(pos + i);
if (ch !== CH || pos + i >= max) return false;
}
if (silent) {
return true;
}
const start = pos + 3;
const end = state.skipSpacesBack(max, pos);
const rawPath = state.src
.slice(start, end)
.trim()
.replace(/^@/, process.cwd());
const content = fs.existsSync(rawPath)
? fs.readFileSync(rawPath).toString()
: "Not found: " + rawPath;
const meta = rawPath.replace(rawPath, "");
state.line = startLine + 1;
const token = state.push("fence", "code", 0);
token.info = rawPath.split(".").pop() + meta;
token.content = content;
token.markup = "```";
token.map = [startLine, startLine + 1];
return true;
};
md.block.ruler.before("fence", "snippet", parser);
};