RLE-wiki/docs/.vitepress/plugins/MarkdownSectionWrapper.ts

166 lines
5.2 KiB
TypeScript
Raw Normal View History

2024-04-10 09:35:31 +08:00
import { resolve, relative } from 'node:path'
import type { Plugin } from 'vite'
import {
pathEndsWith,
pathEquals,
pathStartsWith,
} from '../path'
interface Context {
helpers: {
/**
* A helper function to help to determine whether the passed string parameter equals the
* current transforming module ID with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param equalsWith - String to equal with
* @returns boolean
*/
idEquals: (equalsWith: string) => boolean
/**
* A helper function to help to determine whether the passed string parameter startsWith the
* current transforming module ID with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param startsWith - String to start with
* @returns boolean
*/
idStartsWith: (startsWith: string) => boolean
/**
* A helper function to help to determine whether the passed string parameter endsWith the
* current transforming module ID with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param endsWith - String to end with
* @returns boolean
*/
idEndsWith: (endsWith: string) => boolean
/**
* A helper function to help to determine whether the passed first path parameter
* equals the second passed string with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param path - Path to be compared with
* @param equalsWith - String to equal with
* @returns boolean
*/
pathEquals: (path: string, equalsWith: string) => boolean
/**
* A helper function to help to determine whether the passed first path parameter
* startsWith the second passed string with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param path - Path to be compared with
* @param startsWith - String to start with
* @returns boolean
*/
pathStartsWith: (path: string, startsWith: string) => boolean
/**
* A helper function to help to determine whether the passed first path parameter
* endsWith the second passed string with normalization of paths capabilities and
* cross platform / OS compatibilities.
* @param path - Path to be compared with
* @param endsWith - String to end with
* @returns boolean
*/
pathEndsWith: (path: string, endsWith: string) => boolean
}
}
export interface MarkdownSectionWrapperOptions {
/**
* The list of file names to exclude from the transformation
* @default ['index.md']
*/
excludes?: string[]
/**
* The function to exclude the file from the transformation
* @param id - the current transforming module ID (comes from vite when transform hook is called)
* @param context - the context object, contains several helper functions
* @returns boolean
* @default () => false
*/
exclude?: (id: string, context: Context) => boolean
}
2024-04-10 09:35:31 +08:00
export function MarkdownSectionWrapper(headerTransformers: ((frontmatter: string|null, text: string, id: string) => string)[], footerTransformers: ((frontmatter: string|null, text: string, id: string) => string)[], options?: MarkdownSectionWrapperOptions): Plugin {
const {
excludes = ['index.md'],
exclude = () => false,
} = options ?? {}
let root = ''
return {
name: '@pjts/markdown-section-wrapper',
// May set to 'pre' since end user may use vitepress wrapped vite plugin to
// specify the plugins, which may cause this plugin to be executed after
// vitepress or the other markdown processing plugins.
enforce: 'pre',
configResolved(config) {
root = config.root ?? ''
},
transform(code, id) {
function idEndsWith(endsWith: string) {
return pathEndsWith(relative(root, id), endsWith)
}
function idEquals(equals: string) {
return pathEquals(relative(root, id), equals)
}
function idStartsWith(startsWith: string) {
return pathStartsWith(relative(root, id), startsWith)
}
if (!id.endsWith('.md'))
return null
if (excludes.includes(id))
return null
if (exclude(id, { helpers: { idEndsWith, idEquals, idStartsWith, pathEndsWith, pathEquals, pathStartsWith } }))
return null
2024-04-10 09:35:31 +08:00
let frontmatter = (code.match(/(^---$(\s|\S)+?^---$)/m)?.[0] ?? null)
let text = code.replace(/(^---$(\s|\S)+?^---$)/m, '')
2024-04-10 09:35:31 +08:00
let headers: string[] = headerTransformers.map(f => f(frontmatter, text, id))
let footers: string[] = footerTransformers.map(f => f(frontmatter, text, id))
return [frontmatter, ...headers, text, ...footers].join("")
},
}
}
2024-04-10 09:35:31 +08:00
export function TemplateAppSBox(_frontmatter: string|null, _text: string, _id: string): string {
return `
##
<AppSBox />
`
}
2024-04-10 09:35:31 +08:00
export function TemplateCopyrightInfo(_frontmatter: string|null, _text: string, _id: string): string {
return `
<CopyrightInfo />
`
}
2024-04-10 09:35:31 +08:00
const ROOT = resolve(__dirname, '../../')
export function PageHeaderTemplate(_frontmatter: string|null, _text: string, id: string): string {
if (!id.endsWith('.md'))
return ''
id = relative(ROOT, id)
if (id == 'index.md')
return ''
return `
# {{ $frontmatter.title }}
<PageInfo />
`}