[其他] 初始化项目结构

This commit is contained in:
就眠仪式
2021-09-27 06:09:33 +08:00
commit b2fa2b90b8
73 changed files with 9752 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
import vue from '@vitejs/plugin-vue'
import Markdown from 'vite-plugin-md'
import container from 'markdown-it-container'
import highlight from './highlight'
import snippet from './snippet'
import demo from './demo'
import createContainer from './create-container'
import preWrapper from './pre-wrapper'
import type Token from 'markdown-it/lib/token'
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(...createContainer('tip', 'TIP'))
.use(...createContainer('warning', 'WARNING'))
.use(...createContainer('danger', 'WARNING'))
.use(container, 'v-pre', {
render: (tokens: Token[], idx: number) =>
tokens[idx].nesting === 1 ? '<div v-pre>\n' : '</div>\n',
})
.use(container, 'details', {
render: (tokens: Token[], idx: number) => {
const info = tokens[idx].info.trim().slice(7).trim() // 7 = 'details'.length
return tokens[idx].nesting === 1
? `<details class="custom-block details">${
info ? `<summary>${info}</summary>` : ''
}\n`
: '</details>'
},
})
},
}),
]
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,
defaultTitle: 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 `<div class="${klass} custom-block"><p class="custom-block-title">${
info || defaultTitle
}</p>\n`
} else {
return '</div>\n'
}
},
},
]
}

146
docs/src/plugin/demo.ts Normal file
View File

@@ -0,0 +1,146 @@
import markdown from 'markdown-it'
import highlight from './highlight'
import type Token from 'markdown-it/lib/token'
/**
* Combine the script content
* @param {string} script script string
*/
function assignScript(script: string) {
const dependencies = {} as Record<string, string[]>
const attrs = {} as Record<string, string>
const content = script
// import { ref } from 'vue' -> ''
.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,46 @@
// copy from [vitepress](https://github.com/vuejs/vitepress)
import prism from 'prismjs'
import loadLanguages from 'prismjs/components/index'
import escapeHtml from 'escape-html'
// required to make embedded highlighting work...
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,49 @@
// copy from [vitepress](https://github.com/vuejs/vitepress)
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 it's indented more than 3 spaces, it should be a code block
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)
}