refactor(plugin-auto-frontmatter): 重构代码
This commit is contained in:
parent
e1141bcea0
commit
fa5f758b54
@ -30,13 +30,15 @@ export default {
|
||||
|
||||
### options
|
||||
|
||||
`{ glob?: string | string[]; formatter: Formatter }`
|
||||
`{ include?: string | string[]; exclude?: string | string[]; formatter: Formatter }`
|
||||
|
||||
- `glob`
|
||||
glob 匹配字符串或数组,匹配需要自动生成 `frontmatter` 的 md文件。
|
||||
默认预设为 `['**/*.md', '!.vuepress/', '!node_modules/']`。
|
||||
自定义匹配将被合并到预设配置中
|
||||
example: `['blog/**']`
|
||||
- `include`
|
||||
include 匹配字符串或数组,匹配需要自动生成 `frontmatter` 的 md文件。
|
||||
默认预设为 `['**/*.md']`。
|
||||
|
||||
- `exclude`
|
||||
exclude 排除不需要的文件
|
||||
默认预设为: `['!.vuepress/', '!node_modules/']`
|
||||
|
||||
- `formatter`
|
||||
配置`frontmatter`每个字段的生成规则。
|
||||
@ -58,7 +60,7 @@ export default {
|
||||
>
|
||||
|
||||
type FormatterArray = {
|
||||
glob: string
|
||||
include: string
|
||||
formatter: FormatterObject
|
||||
}[]
|
||||
|
||||
@ -82,7 +84,7 @@ export default {
|
||||
const formatterArr: Formatter = [
|
||||
{
|
||||
// 更精细化的匹配某个 md文件,支持glob 匹配字符串
|
||||
glob: '**/{README,index}.md',
|
||||
include: '**/{README,index}.md',
|
||||
// formatter 仅对 glob命中的文件有效
|
||||
formatter: {
|
||||
home(value, matter, file) {
|
||||
@ -92,8 +94,8 @@ export default {
|
||||
{
|
||||
// 通配,如果文件没有被其他精细glob命中,
|
||||
// 则使用 通配 formatter
|
||||
// 如果是数组,必须有且用一个 glob为 * 的 项
|
||||
glob: '*',
|
||||
// 如果是数组,必须有且用一个 include 为 * 的 项
|
||||
include: '*',
|
||||
formatter: {
|
||||
title(title) {
|
||||
return title || '默认标题'
|
||||
|
||||
@ -31,10 +31,11 @@
|
||||
"dependencies": {
|
||||
"@vuepress/core": "2.0.0-beta.60",
|
||||
"@vuepress/shared": "2.0.0-beta.60",
|
||||
"@vuepress/utils": "2.0.0-beta.60",
|
||||
"chokidar": "^3.5.3",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"gray-matter": "^4.0.3"
|
||||
"create-filter": "^1.0.0",
|
||||
"fast-glob": "^3.2.12",
|
||||
"gray-matter": "^4.0.3",
|
||||
"json2yaml": "^1.1.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -1,16 +1,5 @@
|
||||
declare module 'glob-to-regexp' {
|
||||
interface GlobToRegexp {
|
||||
(
|
||||
glob: string,
|
||||
options?: {
|
||||
globstar?: boolean
|
||||
extended?: boolean
|
||||
flags?: string
|
||||
}
|
||||
): RegExp
|
||||
}
|
||||
declare module 'json2yaml' {
|
||||
const result: any
|
||||
|
||||
const globToRegexp: GlobToRegexp
|
||||
|
||||
export default globToRegexp
|
||||
export default result
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import fs from 'node:fs'
|
||||
import type { Plugin } from '@vuepress/core'
|
||||
import { fs } from '@vuepress/utils'
|
||||
import chokidar from 'chokidar'
|
||||
import globToRegexp from 'glob-to-regexp'
|
||||
import { createFilter } from 'create-filter'
|
||||
import grayMatter from 'gray-matter'
|
||||
import jsonToYaml from 'json2yaml'
|
||||
import type {
|
||||
AutoFrontmatterOptions,
|
||||
FormatterArray,
|
||||
@ -10,30 +11,31 @@ import type {
|
||||
MarkdownFile,
|
||||
} from '../shared/index.js'
|
||||
import { readMarkdown, readMarkdownList } from './readFiles.js'
|
||||
import { ensureArray } from './utils.js'
|
||||
|
||||
export const autoFrontmatterPlugin = ({
|
||||
glob = '',
|
||||
include = ['**/*.{md,MD}'],
|
||||
exclude = ['.vuepress/**/*', 'node_modules'],
|
||||
formatter = {},
|
||||
}: AutoFrontmatterOptions = {}): Plugin => {
|
||||
glob = glob ? (Array.isArray(glob) ? glob : [glob]) : []
|
||||
glob = ['**/*.{md,MD}', '!.vuepress/', '!node_modules/', ...glob]
|
||||
include = ensureArray(include)
|
||||
exclude = ensureArray(exclude)
|
||||
|
||||
const globFilter = createFilter(include, exclude, { resolve: false })
|
||||
|
||||
const matterFormatter: FormatterArray = Array.isArray(formatter)
|
||||
? formatter
|
||||
: [{ glob: '*', formatter }]
|
||||
: [{ include: '*', formatter }]
|
||||
|
||||
const globFormatter: FormatterObject =
|
||||
matterFormatter.find(({ glob }) => glob === '*')?.formatter || {}
|
||||
matterFormatter.find(({ include }) => include === '*')?.formatter || {}
|
||||
|
||||
const otherFormatters = matterFormatter
|
||||
.filter(({ glob }) => glob !== '*')
|
||||
.map(({ glob, formatter }) => {
|
||||
.filter(({ include }) => include !== '*')
|
||||
.map(({ include, formatter }) => {
|
||||
return {
|
||||
glob,
|
||||
regexp: globToRegexp(glob, {
|
||||
globstar: true,
|
||||
extended: true,
|
||||
}),
|
||||
include,
|
||||
filter: createFilter(include),
|
||||
formatter,
|
||||
}
|
||||
})
|
||||
@ -42,26 +44,27 @@ export const autoFrontmatterPlugin = ({
|
||||
const { filepath, relativePath } = file
|
||||
|
||||
const formatter =
|
||||
otherFormatters.find(({ regexp }) => regexp.test(relativePath))
|
||||
?.formatter || globFormatter
|
||||
otherFormatters.find(({ filter }) => filter(relativePath))?.formatter ||
|
||||
globFormatter
|
||||
const { data, content } = grayMatter(file.content)
|
||||
|
||||
Object.keys(formatter).forEach((key) => {
|
||||
const value = formatter[key](data[key], data, file)
|
||||
data[key] = value ?? data[key]
|
||||
})
|
||||
const newContent = grayMatter.stringify({ content }, data)
|
||||
const yaml = jsonToYaml
|
||||
.stringify(data)
|
||||
.replace(/\n\s{2}/g, '\n')
|
||||
.replace(/"/g, '')
|
||||
const newContent = `${yaml}---\n${content}`
|
||||
|
||||
fs.writeFileSync(filepath, newContent)
|
||||
fs.writeFileSync(filepath, newContent, 'utf-8')
|
||||
}
|
||||
|
||||
return {
|
||||
name: '@vuepress-plume/vuepress-plugin-auto-frontmatter',
|
||||
onInitialized: async (app) => {
|
||||
const markdownList = await readMarkdownList(
|
||||
app.dir.source(),
|
||||
glob as string[]
|
||||
)
|
||||
const markdownList = await readMarkdownList(app.dir.source(), globFilter)
|
||||
markdownList.forEach((file) => formatMarkdown(file))
|
||||
},
|
||||
onWatched: async (app, watchers) => {
|
||||
@ -72,8 +75,7 @@ export const autoFrontmatterPlugin = ({
|
||||
})
|
||||
|
||||
watcher.on('add', (relativePath) => {
|
||||
if ((glob as string[]).some((_) => !globToRegexp(_).test(relativePath)))
|
||||
return
|
||||
if (!globFilter(relativePath)) return
|
||||
formatMarkdown(readMarkdown(app.dir.source(), relativePath))
|
||||
})
|
||||
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
import { fs, globby, path } from '@vuepress/utils'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import fg from 'fast-glob'
|
||||
import type { MarkdownFile } from '../shared/index.js'
|
||||
|
||||
type MarkdownFileList = MarkdownFile[]
|
||||
|
||||
export const readMarkdownList = async (
|
||||
sourceDir: string,
|
||||
glob: string[]
|
||||
filter: (id: string) => boolean
|
||||
): Promise<MarkdownFileList> => {
|
||||
const files: string[] = await globby(glob, {
|
||||
const files: string[] = await fg(['**/*.md'], {
|
||||
cwd: sourceDir,
|
||||
gitignore: true,
|
||||
ignore: ['node_modules/', '.vuepress/'],
|
||||
})
|
||||
|
||||
return files.map((file) => readMarkdown(sourceDir, file))
|
||||
return files
|
||||
.filter((file) => filter(file))
|
||||
.map((file) => readMarkdown(sourceDir, file))
|
||||
}
|
||||
|
||||
export const readMarkdown = (
|
||||
|
||||
5
packages/plugin-auto-frontmatter/src/node/utils.ts
Normal file
5
packages/plugin-auto-frontmatter/src/node/utils.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export function ensureArray<T>(thing: T | T[] | null | undefined): T[] {
|
||||
if (Array.isArray(thing)) return thing
|
||||
if (thing === null || thing === undefined) return []
|
||||
return [thing]
|
||||
}
|
||||
@ -15,15 +15,17 @@ export type FormatterObject<K = object, T = any> = Record<
|
||||
>
|
||||
|
||||
export type FormatterArray = {
|
||||
glob: string
|
||||
include: string
|
||||
formatter: FormatterObject
|
||||
}[]
|
||||
|
||||
export interface AutoFrontmatterOptions {
|
||||
/**
|
||||
* glob string
|
||||
* FilterPattern
|
||||
*/
|
||||
glob?: string | string[]
|
||||
include?: string | string[]
|
||||
|
||||
exclude?: string | string[]
|
||||
|
||||
/**
|
||||
* {
|
||||
|
||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@ -102,15 +102,19 @@ importers:
|
||||
'@vuepress/shared': 2.0.0-beta.60
|
||||
'@vuepress/utils': 2.0.0-beta.60
|
||||
chokidar: ^3.5.3
|
||||
glob-to-regexp: ^0.4.1
|
||||
create-filter: ^1.0.0
|
||||
fast-glob: ^3.2.12
|
||||
gray-matter: ^4.0.3
|
||||
json2yaml: ^1.1.0
|
||||
dependencies:
|
||||
'@vuepress/core': 2.0.0-beta.60
|
||||
'@vuepress/shared': 2.0.0-beta.60
|
||||
'@vuepress/utils': 2.0.0-beta.60
|
||||
chokidar: 3.5.3
|
||||
glob-to-regexp: 0.4.1
|
||||
create-filter: 1.0.0
|
||||
fast-glob: 3.2.12
|
||||
gray-matter: 4.0.3
|
||||
json2yaml: 1.1.0
|
||||
|
||||
packages/plugin-baidu-tongji:
|
||||
specifiers:
|
||||
@ -10156,6 +10160,14 @@ packages:
|
||||
/json-stringify-safe/5.0.1:
|
||||
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
|
||||
|
||||
/json2yaml/1.1.0:
|
||||
resolution: {integrity: sha512-/xse+m0SlllfZahQrNOelmLrFNfeZv4QG0QKlvg7VsPSGIxpB3X+ggLkdffwmI1DdQ3o9XjZX+K+EOI1epdKgg==}
|
||||
engines: {node: '>= 0.2.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
remedial: 1.0.8
|
||||
dev: false
|
||||
|
||||
/json5/1.0.1:
|
||||
resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
|
||||
hasBin: true
|
||||
@ -13369,6 +13381,10 @@ packages:
|
||||
engines: {node: '>= 0.10'}
|
||||
dev: false
|
||||
|
||||
/remedial/1.0.8:
|
||||
resolution: {integrity: sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==}
|
||||
dev: false
|
||||
|
||||
/remove-trailing-separator/1.1.0:
|
||||
resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==}
|
||||
dev: false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user