227 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type {
AutoFrontmatterContext,
AutoFrontmatterData,
AutoFrontmatterOptions,
AutoFrontmatterRule,
ThemeDocCollection,
} from '../../shared/index.js'
import type { ThemePostCollection } from '../../shared/index.js'
import { hasOwn, toArray } from '@pengzhanbo/utils'
import { ensureEndingSlash, ensureLeadingSlash, removeLeadingSlash } from 'vuepress/shared'
import { path } from 'vuepress/utils'
import { getThemeConfig } from '../loadConfig/index.js'
import { nanoid } from '../utils/index.js'
import {
EXCLUDE,
getCurrentName,
getFileCreateTime,
getPermalinkByFilepath,
isReadme,
} from './helper.js'
import { resolveLinkBySidebar } from './resolveLinkBySidebar.js'
const rules: AutoFrontmatterRule[] = []
export function getRules(): AutoFrontmatterRule[] {
return rules
}
export function genAutoFrontmatterRules(): void {
const options = getThemeConfig()
const remainExclude: string[] = [...EXCLUDE]
rules.length = 0
const autoFrontmatter = options.autoFrontmatter ?? {}
for (const [locale, { collections }] of Object.entries(options.locales || {})) {
if (!collections?.length)
continue
for (const collection of collections) {
const source = removeLeadingSlash(path.join(locale, collection.dir, '**/*.md'))
// 无论 集合是否启用 autoFrontmatter
// 在最后的对剩余文件的 auto frontmatter 都需要排除当前集合的文件
remainExclude.push(source)
if ((collection.autoFrontmatter ?? autoFrontmatter) === false)
continue
if (collection.type === 'post') {
rules.push({
filter: [
source,
...toArray(collection.include),
...EXCLUDE,
...toArray(collection.exclude).map(s => `!${s}`),
],
handle: (data, context) => generateWithPost(data, context, collection, autoFrontmatter, locale),
})
}
else {
rules.push({
filter: [source, ...EXCLUDE],
handle: (data, context) => generateWithDoc(data, context, collection, autoFrontmatter, locale),
})
}
}
if (locale !== '/') {
const source = removeLeadingSlash(path.join(locale, '**/*.md'))
// locale fallback
rules.push({
filter: [
source,
...remainExclude.map(s => `!${s}`),
],
handle: (data, context) => generateWithRemain(data, context, autoFrontmatter, locale),
})
remainExclude.push(source)
}
}
// root fallback
rules.push({
filter: [
'**/*.md',
...remainExclude.map(s => `!${s}`),
],
handle: (data, context) => generateWithRemain(data, context, autoFrontmatter, '/'),
})
}
async function generateWithPost(
data: AutoFrontmatterData,
context: AutoFrontmatterContext,
collection: ThemePostCollection,
fm: AutoFrontmatterOptions | false,
locale: string,
): Promise<AutoFrontmatterData> {
if ((collection.autoFrontmatter ?? fm) === false)
return data
const { title: et = true, createTime: ec = true, permalink: ep = true } = { ...fm, ...collection.autoFrontmatter }
const transform = (collection.autoFrontmatter || {}).transform
const isRoot = context.filepath.endsWith(path.join(locale, collection.dir, 'README.md'))
if (et && !hasOwn(data, 'title')) {
data.title = isRoot ? collection.title : getCurrentName(context.relativePath)
}
if (ec && !hasOwn(data, 'createTime')) {
data.createTime = getFileCreateTime(context.filepath)
}
if (ep && !hasOwn(data, 'permalink')) {
data.permalink = path.join(
locale,
collection.linkPrefix || collection.link || collection.dir,
ep === 'filepath'
? await getPermalinkByFilepath(context.relativePath, path.join(locale, collection.dir))
: nanoid(),
'/',
)
}
data = await transform?.(data, context, locale) ?? data
return data
}
async function generateWithDoc(
data: AutoFrontmatterData,
context: AutoFrontmatterContext,
collection: ThemeDocCollection,
fm: AutoFrontmatterOptions | false,
locale: string,
): Promise<AutoFrontmatterData> {
if ((collection.autoFrontmatter ?? fm) === false)
return data
const { title: et = true, createTime: ec = true, permalink: ep = true } = { ...fm, ...collection.autoFrontmatter }
const transform = (collection.autoFrontmatter || {}).transform
const isRoot = context.filepath.endsWith(path.join(locale, collection.dir, 'README.md'))
if (et && !hasOwn(data, 'title')) {
data.title = isRoot ? collection.title : getCurrentName(context.relativePath)
}
if (ec && !hasOwn(data, 'createTime')) {
data.createTime = getFileCreateTime(context.filepath)
}
if (ep && !hasOwn(data, 'permalink')) {
if (isRoot) {
data.permalink = path.join(locale, collection.linkPrefix, '/')
}
else if (collection.sidebar && collection.sidebar !== 'auto') {
const res = resolveLinkBySidebar(collection.sidebar, ensureLeadingSlash(collection.dir))
const file = path.dirname(context.relativePath)
const link = res[ensureLeadingSlash(ensureEndingSlash(file))] || '/'
data.permalink = path.join(
locale,
collection.linkPrefix,
link,
isReadme(context.relativePath)
? ''
: ep === 'filepath'
? await getPermalinkByFilepath(
link === '/' ? context.relativePath : path.basename(context.relativePath),
link === '/' ? path.join(locale, collection.dir) : '',
)
: nanoid(8),
'/',
)
}
else {
data.permalink = path.join(
locale,
collection.linkPrefix,
ep === 'filepath'
? await getPermalinkByFilepath(context.relativePath, path.join(locale, collection.dir))
: nanoid(8),
'/',
)
}
}
data = await transform?.(data, context, locale) ?? data
return data
}
async function generateWithRemain(
data: AutoFrontmatterData,
context: AutoFrontmatterContext,
fm: AutoFrontmatterOptions | false,
locale: string,
): Promise<AutoFrontmatterData> {
if (fm === false)
return data
const { title: et = true, createTime: ec = true, permalink: ep = true, transform } = fm
const isRoot = context.filepath.endsWith(path.join(locale, 'README.md'))
if (isRoot) {
data.pageLayout = 'home'
}
if (et && !hasOwn(data, 'title')) {
data.title = isRoot ? 'Home' : getCurrentName(context.relativePath)
}
if (ec && !hasOwn(data, 'createTime') && !isRoot) {
data.createTime = getFileCreateTime(context.filepath)
}
if (ep && !hasOwn(data, 'permalink') && !isRoot) {
data.permalink = path.join(
locale,
ep === 'filepath' ? await getPermalinkByFilepath(context.relativePath, locale) : nanoid(8),
'/',
)
}
data = await transform?.(data, context, locale) ?? data
return data
}