diff --git a/plugins/plugin-md-power/src/client/composables/codeRepl.ts b/plugins/plugin-md-power/src/client/composables/codeRepl.ts index 070f037c..6f1a91ac 100644 --- a/plugins/plugin-md-power/src/client/composables/codeRepl.ts +++ b/plugins/plugin-md-power/src/client/composables/codeRepl.ts @@ -5,18 +5,63 @@ import { http } from '../utils/http.js' import { sleep } from '../utils/sleep.js' import { rustExecute } from './rustRepl.js' +/** + * CSS selectors for nodes to ignore when extracting code. + * + * 提取代码时要忽略的节点的 CSS 选择器。 + */ const ignoredNodes = ['.diff.remove', '.vp-copy-ignore'] + +/** + * Regular expression for matching language class. + * + * 匹配语言类的正则表达式。 + */ const RE_LANGUAGE = /language-(\w+)/ + +/** + * API endpoints for code execution backends. + * + * 代码执行后端的 API 端点。 + */ const api = { go: 'https://api.pengzhanbo.cn/repl/golang/run', kotlin: 'https://api.pengzhanbo.cn/repl/kotlin/run', } + +/** + * Pyodide instance for Python execution. + * + * 用于 Python 执行的 Pyodide 实例。 + */ let pyodide: PyodideInterface | null = null +/** + * Supported languages for code execution. + * + * 支持代码执行的语言。 + */ type Lang = 'kotlin' | 'go' | 'rust' | 'python' + +/** + * Function type for code execution. + * + * 代码执行的函数类型。 + */ type ExecuteFn = (code: string) => Promise + +/** + * Map of language to execution function. + * + * 语言到执行函数的映射。 + */ type ExecuteMap = Record +/** + * Language alias mapping. + * + * 语言别名映射。 + */ const langAlias: Record = { kt: 'kotlin', kotlin: 'kotlin', @@ -27,12 +72,33 @@ const langAlias: Record = { python: 'python', } +/** + * List of supported languages. + * + * 支持的语言列表。 + */ const supportLang: Lang[] = ['kotlin', 'go', 'rust', 'python'] +/** + * Resolve language name from alias. + * + * 从别名解析语言名称。 + * + * @param lang - Language or alias / 语言或别名 + * @returns Resolved language name / 解析后的语言名称 + */ function resolveLang(lang?: string) { return lang ? langAlias[lang] || lang : '' } +/** + * Resolve code content from HTML element, ignoring specified nodes. + * + * 从 HTML 元素解析代码内容,忽略指定的节点。 + * + * @param el - HTML element / HTML 元素 + * @returns Code content / 代码内容 + */ export function resolveCode(el: HTMLElement): string { const clone = el.cloneNode(true) as HTMLElement clone @@ -42,6 +108,14 @@ export function resolveCode(el: HTMLElement): string { return clone.textContent || '' } +/** + * Resolve code information from HTML element. + * + * 从 HTML 元素解析代码信息。 + * + * @param el - HTML element / HTML 元素 + * @returns Object with language and code / 包含语言和代码的对象 + */ export function resolveCodeInfo(el: HTMLDivElement): { lang: Lang code: string @@ -57,19 +131,55 @@ export function resolveCodeInfo(el: HTMLDivElement): { return { lang: resolveLang(lang) as Lang, code } } +/** + * Result interface for useCodeRepl composable. + * + * useCodeRepl 组合式函数的结果接口。 + */ interface UseCodeReplResult { + /** Current language / 当前语言 */ lang: Ref + /** Whether the code is loaded / 代码是否已加载 */ loaded: Ref + /** Whether this is the first run / 是否为首次运行 */ firstRun: Ref + /** Whether execution is finished / 执行是否完成 */ finished: Ref + /** Standard output lines / 标准输出行 */ stdout: Ref + /** Standard error lines / 标准错误行 */ stderr: Ref + /** Error message / 错误信息 */ error: Ref + /** Backend version / 后端版本 */ backendVersion: Ref + /** Clean run state / 清理运行状态 */ onCleanRun: () => void + /** Run code execution / 运行代码执行 */ onRunCode: () => Promise } +/** + * Composable for code REPL functionality. + * + * 代码 REPL 功能的组合式函数。 + * + * This composable provides functionality to execute code in various languages + * (Kotlin, Go, Rust, Python) and manage the execution state. + * + * 该组合式函数提供在各种语言(Kotlin、Go、Rust、Python)中执行代码和管理执行状态的功能。 + * + * @param el - Reference to the code element / 代码元素的引用 + * @returns REPL state and methods / REPL 状态和方法 + * + * @example + * ```vue + * + * ``` + */ export function useCodeRepl(el: Ref): UseCodeReplResult { const lang = ref() const loaded = ref(true) @@ -227,36 +337,74 @@ export function useCodeRepl(el: Ref): UseCodeReplResult { } } +/** + * Request interface for Golang execution API. + * + * Golang 执行 API 的请求接口。 + */ interface GolangRequest { + /** Code to execute / 要执行的代码 */ code: string + /** Go version / Go 版本 */ version?: '' | 'goprev' | 'gotip' } +/** + * Response interface for Golang execution API. + * + * Golang 执行 API 的响应接口。 + */ interface GolangResponse { + /** Execution events / 执行事件 */ events?: { + /** Event message / 事件消息 */ message: '' + /** Event kind / 事件类型 */ kind: 'stdout' | 'stderr' + /** Event delay / 事件延迟 */ delay: number }[] + /** Error message / 错误信息 */ error?: string + /** Go version / Go 版本 */ version: string } +/** + * Request interface for Kotlin execution API. + * + * Kotlin 执行 API 的请求接口。 + */ interface KotlinRequest { + /** Command line arguments / 命令行参数 */ args?: string + /** Files to compile / 要编译的文件 */ files: { + /** File name / 文件名 */ name: string + /** Public ID / 公共 ID */ publicId: string + /** File content / 文件内容 */ text: string }[] } +/** + * Response interface for Kotlin execution API. + * + * Kotlin 执行 API 的响应接口。 + */ interface KotlinResponse { + /** Execution output / 执行输出 */ text: string + /** Kotlin version / Kotlin 版本 */ version: string + /** Compilation errors / 编译错误 */ errors: { [filename: string]: { + /** Error message / 错误信息 */ message: string + /** Error severity / 错误严重程度 */ severity: 'ERROR' | 'WARNING' }[] } diff --git a/plugins/plugin-md-power/src/client/composables/decrypt.ts b/plugins/plugin-md-power/src/client/composables/decrypt.ts index a1891e3e..731d472f 100644 --- a/plugins/plugin-md-power/src/client/composables/decrypt.ts +++ b/plugins/plugin-md-power/src/client/composables/decrypt.ts @@ -1,11 +1,48 @@ import type { ComputedRef } from 'vue' +/** + * Composable for decrypting encrypted content. + * + * 用于解密加密内容的组合式函数。 + * + * This composable provides a decrypt function that uses the Web Crypto API + * to decrypt content encrypted with AES-CBC algorithm. + * + * 该组合式函数提供一个解密函数,使用 Web Crypto API 解密使用 AES-CBC 算法加密的内容。 + * + * @param config - Configuration containing salt and IV / 包含盐值和 IV 的配置 + * @returns Object with decrypt function / 包含解密函数的对象 + * + * @example + * ```ts + * const config = computed(() => ({ salt: [...], iv: [...] })) + * const { decrypt } = useDecrypt(config) + * const content = await decrypt('password', 'encrypted-content') + * ``` + */ export function useDecrypt( config: ComputedRef<{ salt: number[], iv: number[] }>, ) { + /** + * Convert number array to Uint8Array. + * + * 将数字数组转换为 Uint8Array。 + * + * @param raw - Number array / 数字数组 + * @returns Uint8Array / Uint8Array + */ const toUnit8Array = (raw: number[]) => Uint8Array.from(raw) return { + /** + * Decrypt encrypted content using password. + * + * 使用密码解密加密内容。 + * + * @param password - Decryption password / 解密密码 + * @param text - Encrypted content / 加密内容 + * @returns Decrypted content or undefined / 解密后的内容或 undefined + */ decrypt: async (password: string, text: string) => { if (!password) return @@ -29,6 +66,14 @@ export function useDecrypt( } } +/** + * Get key material from password using PBKDF2. + * + * 使用 PBKDF2 从密码获取密钥材料。 + * + * @param password - Password string / 密码字符串 + * @returns CryptoKey for key derivation / 用于密钥派生的 CryptoKey + */ function getKeyMaterial(password: string) { const enc = new TextEncoder() return window.crypto.subtle.importKey( @@ -41,7 +86,13 @@ function getKeyMaterial(password: string) { } /** - * crypto + * Derive encryption key from key material using PBKDF2. + * + * 使用 PBKDF2 从密钥材料派生加密密钥。 + * + * @param keyMaterial - Key material from password / 从密码获取的密钥材料 + * @param salt - Salt for key derivation / 密钥派生盐值 + * @returns Derived CryptoKey for AES-CBC / 用于 AES-CBC 的派生 CryptoKey */ function getCryptoDeriveKey(keyMaterial: CryptoKey, salt: BufferSource) { return window.crypto.subtle.deriveKey( diff --git a/plugins/plugin-md-power/src/client/composables/mark.ts b/plugins/plugin-md-power/src/client/composables/mark.ts index a7187f77..6789b5d5 100644 --- a/plugins/plugin-md-power/src/client/composables/mark.ts +++ b/plugins/plugin-md-power/src/client/composables/mark.ts @@ -1,12 +1,61 @@ import { onContentUpdated } from 'vuepress/client' +/** + * Attribute name for mark mode. + * + * 标记模式属性名。 + */ const MARK_MODE_ATTR = 'data-mark-mode' +/** + * Lazy mode constant. + * + * 懒加载模式常量。 + */ const MARK_MODE_LAZY = 'lazy' +/** + * CSS class for visible marks. + * + * 可见标记的 CSS 类名。 + */ const MARK_VISIBLE_CLASS = 'vp-mark-visible' +/** + * Attribute name for mark boundary. + * + * 标记边界属性名。 + */ const MARK_BOUND_ATTR = 'data-vp-mark-bound' +/** + * CSS selector for mark elements. + * + * 标记元素的 CSS 选择器。 + */ const MARK_SELECTOR = 'mark' +/** + * CSS selector for bounded mark elements. + * + * 已绑定标记元素的 CSS 选择器。 + */ const BOUND_SELECTOR = `${MARK_SELECTOR}[${MARK_BOUND_ATTR}="1"]` +/** + * Setup mark highlight animation for lazy mode. + * + * 为懒加载模式设置标记高亮动画。 + * + * When mode is 'lazy', marks will animate into view using IntersectionObserver. + * When mode is 'eager', marks are immediately visible without animation. + * + * 当模式为 'lazy' 时,标记将使用 IntersectionObserver 在进入视口时显示动画。 + * 当模式为 'eager' 时,标记立即显示,没有动画效果。 + * + * @param mode - Animation mode: 'lazy' or 'eager' / 动画模式:'lazy' 或 'eager' + * + * @example + * ```ts + * // In client config setup + * setupMarkHighlight('lazy') + * ``` + */ export function setupMarkHighlight(mode: 'lazy' | 'eager'): void { if (typeof window === 'undefined' || __VUEPRESS_SSR__) return diff --git a/plugins/plugin-md-power/src/client/composables/pdf.ts b/plugins/plugin-md-power/src/client/composables/pdf.ts index fa3474f3..2bfca4c6 100644 --- a/plugins/plugin-md-power/src/client/composables/pdf.ts +++ b/plugins/plugin-md-power/src/client/composables/pdf.ts @@ -17,6 +17,14 @@ import { withBase } from 'vuepress/client' import { ensureEndingSlash, isLinkHttp } from 'vuepress/shared' import { pluginOptions } from '../options.js' +/** + * Build query string from PDF options. + * + * 从 PDF 选项构建查询字符串。 + * + * @param options - PDF token metadata / PDF 令牌元数据 + * @returns Query string / 查询字符串 + */ function queryStringify(options: PDFTokenMeta): string { const { page, noToolbar, zoom } = options const params = [ @@ -32,6 +40,16 @@ function queryStringify(options: PDFTokenMeta): string { return queryString } +/** + * Render PDF viewer in the specified element. + * + * 在指定元素中渲染 PDF 查看器。 + * + * @param el - Container element / 容器元素 + * @param url - PDF URL / PDF URL + * @param embedType - Embed type: 'pdfjs', 'iframe', or 'embed' / 嵌入类型 + * @param options - PDF token metadata / PDF 令牌元数据 + */ export function renderPDF( el: HTMLElement, url: string, @@ -72,6 +90,20 @@ export function renderPDF( el.appendChild(pdf) } +/** + * Composable for PDF viewer functionality. + * + * PDF 查看器功能的组合式函数。 + * + * This function detects browser capabilities and chooses the appropriate + * embedding method for PDF display (PDF.js, iframe, or embed). + * + * 该函数检测浏览器能力并选择适当的嵌入方法来显示 PDF(PDF.js、iframe 或 embed)。 + * + * @param el - Container element / 容器元素 + * @param url - PDF URL / PDF URL + * @param options - PDF token metadata / PDF 令牌元数据 + */ export function usePDF( el: HTMLElement, url: string, @@ -86,10 +118,10 @@ export function usePDF( const isModernBrowser = typeof window.Promise === 'function' // Quick test for mobile devices. - const isMobileDevice = isiPad(userAgent) || isMobile(userAgent) + const isMobileDevice = isiPad() || isMobile() // Safari desktop requires special handling - const isSafariDesktop = !isMobileDevice && isSafari(userAgent) + const isSafariDesktop = !isMobileDevice && isSafari() const isFirefoxWithPDFJS = !isMobileDevice diff --git a/plugins/plugin-md-power/src/client/options.ts b/plugins/plugin-md-power/src/client/options.ts index 41fb8a0e..d135fe47 100644 --- a/plugins/plugin-md-power/src/client/options.ts +++ b/plugins/plugin-md-power/src/client/options.ts @@ -8,8 +8,18 @@ declare const __MD_POWER_HLSJS_INSTALLED__: boolean declare const __MD_POWER_MPEGTSJS_INSTALLED__: boolean declare const __MD_POWER_ENCRYPT_LOCALES__: LocaleConfig +/** + * Plugin options injected at build time. + * + * 构建时注入的插件选项。 + */ export const pluginOptions: MarkdownPowerPluginOptions = __MD_POWER_INJECT_OPTIONS__ +/** + * Package installation status for video streaming libraries. + * + * 视频流媒体库的安装状态。 + */ export const installed: { dashjs: boolean hlsjs: boolean @@ -20,6 +30,11 @@ export const installed: { mpegtsjs: __MD_POWER_MPEGTSJS_INSTALLED__, } +/** + * Supported video types for ArtPlayer. + * + * ArtPlayer 支持的视频类型。 + */ export const ART_PLAYER_SUPPORTED_VIDEO_TYPES: string[] = ['mp4', 'mp3', 'webm', 'ogg'] if (installed.dashjs) { @@ -34,12 +49,27 @@ if (installed.mpegtsjs) { ART_PLAYER_SUPPORTED_VIDEO_TYPES.push('ts', 'flv') } +/** + * Injection key for timeline component communication. + * + * 时间线组件通信的注入键。 + */ export const INJECT_TIMELINE_KEY: symbol = Symbol( __VUEPRESS_DEV__ ? 'timeline' : '', ) +/** + * Injection key for collapse component communication. + * + * 折叠面板组件通信的注入键。 + */ export const INJECT_COLLAPSE_KEY: symbol = Symbol( __VUEPRESS_DEV__ ? 'collapse' : '', ) +/** + * Encrypt snippet locale data. + * + * 加密片段本地化数据。 + */ export const ENCRYPT_LOCALES = __MD_POWER_ENCRYPT_LOCALES__ diff --git a/plugins/plugin-md-power/src/node/demo/index.ts b/plugins/plugin-md-power/src/node/demo/index.ts index eba10b44..7a6dd2f4 100644 --- a/plugins/plugin-md-power/src/node/demo/index.ts +++ b/plugins/plugin-md-power/src/node/demo/index.ts @@ -3,6 +3,19 @@ import type { Markdown } from 'vuepress/markdown' import { demoContainer, demoEmbed } from './demo.js' import { createDemoRender } from './watcher.js' +/** + * Register demo plugin for markdown-it. + * + * 为 markdown-it 注册 demo 插件。 + * + * This plugin enables demo syntax in markdown files, allowing users to + * create interactive code demonstrations with live preview. + * + * 该插件在 markdown 文件中启用 demo 语法,允许用户创建带有实时预览的交互式代码演示。 + * + * @param app - VuePress app instance / VuePress 应用实例 + * @param md - Markdown-it instance / Markdown-it 实例 + */ export function demoPlugin(app: App, md: Markdown): void { createDemoRender() demoEmbed(app, md) diff --git a/plugins/plugin-md-power/src/node/locales/index.ts b/plugins/plugin-md-power/src/node/locales/index.ts index 2050a037..d707c2d2 100644 --- a/plugins/plugin-md-power/src/node/locales/index.ts +++ b/plugins/plugin-md-power/src/node/locales/index.ts @@ -9,6 +9,17 @@ import { ruLocale } from './ru' import { zhLocale } from './zh' import { zhTWLocale } from './zh-tw' +/** + * Default locale options for the plugin. + * + * 插件的默认本地化选项。 + * + * This constant defines the default locale configurations for all supported languages. + * Each locale entry maps language codes to their respective locale data. + * + * 该常量定义了所有支持语言的默认本地化配置。 + * 每个本地化条目将语言代码映射到其相应的本地化数据。 + */ export const LOCALE_OPTIONS: DefaultLocaleInfo = [ [['en', 'en-US'], enLocale], [['zh', 'zh-CN', 'zh-Hans', 'zh-Hant'], zhLocale], diff --git a/plugins/plugin-md-power/src/node/plugin.ts b/plugins/plugin-md-power/src/node/plugin.ts index 3a4b50ad..251c2dc0 100644 --- a/plugins/plugin-md-power/src/node/plugin.ts +++ b/plugins/plugin-md-power/src/node/plugin.ts @@ -16,6 +16,41 @@ import { LOCALE_OPTIONS } from './locales/index.js' import { prepareConfigFile } from './prepareConfigFile.js' import { provideData } from './provideData.js' +/** + * Create markdown power plugin for VuePress. + * + * 为 VuePress 创建 markdown 增强插件。 + * + * This plugin provides various markdown enhancements including: + * - Custom containers (tabs, collapse, timeline, etc.) + * - Code blocks enhancements (code tabs, file tree, demo) + * - Embed syntax (video, PDF, code playground) + * - Inline syntax (mark, subscript, superscript, footnote) + * - Icon support + * + * 该插件提供多种 markdown 增强功能,包括: + * - 自定义容器(标签页、折叠面板、时间线等) + * - 代码块增强(代码标签页、文件树、演示) + * - 嵌入语法(视频、PDF、代码游乐场) + * - 行内语法(标记、下标、上标、脚注) + * - 图标支持 + * + * @param options - Plugin options / 插件配置选项 + * @returns VuePress plugin instance / VuePress 插件实例 + * + * @example + * ```ts + * // Basic usage + * markdownPowerPlugin() + * + * // With options + * markdownPowerPlugin({ + * tabs: true, + * collapse: true, + * pdf: true, + * }) + * ``` + */ export function markdownPowerPlugin( options: MarkdownPowerPluginOptions = {}, ): Plugin { diff --git a/plugins/plugin-md-power/src/node/prepareConfigFile.ts b/plugins/plugin-md-power/src/node/prepareConfigFile.ts index 802fb97f..30fdc3c2 100644 --- a/plugins/plugin-md-power/src/node/prepareConfigFile.ts +++ b/plugins/plugin-md-power/src/node/prepareConfigFile.ts @@ -7,10 +7,38 @@ import { prepareIcon } from './icon/index.js' const { url: filepath } = import.meta const __dirname = getDirname(filepath) +/** + * Client folder path constant. + * + * 客户端文件夹路径常量。 + */ const CLIENT_FOLDER = ensureEndingSlash( path.resolve(__dirname, '../client'), ) +/** + * Prepare client configuration file for the plugin. + * + * 为插件准备客户端配置文件。 + * + * This function dynamically generates the client config file based on the plugin options. + * It imports and registers Vue components conditionally based on which features are enabled. + * + * 该函数根据插件选项动态生成客户端配置文件。 + * 它根据启用的功能有条件地导入和注册 Vue 组件。 + * + * @param app - VuePress app instance / VuePress 应用实例 + * @param options - Plugin options / 插件配置选项 + * @returns Path to the generated config file / 生成的配置文件路径 + * + * @example + * ```ts + * const configPath = await prepareConfigFile(app, { + * pdf: true, + * tabs: true, + * }) + * ``` + */ export async function prepareConfigFile(app: App, options: MarkdownPowerPluginOptions): Promise { const imports = new Set() const enhances = new Set() diff --git a/plugins/plugin-md-power/src/node/provideData.ts b/plugins/plugin-md-power/src/node/provideData.ts index e7768f1a..563ccc5e 100644 --- a/plugins/plugin-md-power/src/node/provideData.ts +++ b/plugins/plugin-md-power/src/node/provideData.ts @@ -3,6 +3,34 @@ import type { MarkdownPowerPluginOptions, MDPowerLocaleData } from '../shared/in import { isPackageExists } from 'local-pkg' import { findLocales } from './utils/findLocales.js' +/** + * Provide data to be injected into the client-side application. + * + * 提供要注入到客户端应用的数据。 + * + * This function creates a record of data that will be defined as global constants + * in the client bundle, allowing the client to access plugin configuration and + * runtime information. + * + * 该函数创建一个数据记录,将作为全局常量定义在客户端包中, + * 允许客户端访问插件配置和运行时信息。 + * + * @param options - Plugin options / 插件配置选项 + * @param locales - Locale configuration / 本地化配置 + * @returns Record of data to be defined / 要定义的数据记录 + * + * @example + * ```ts + * const data = provideData(options, locales) + * // Returns: + * // { + * // __MD_POWER_INJECT_OPTIONS__: { plot: true, pdf: true }, + * // __MD_POWER_DASHJS_INSTALLED__: true, + * // __MD_POWER_HLSJS_INSTALLED__: false, + * // ... + * // } + * ``` + */ export function provideData( options: MarkdownPowerPluginOptions, locales: ExactLocaleConfig, diff --git a/plugins/plugin-md-power/src/node/utils/cleanMarkdownEnv.ts b/plugins/plugin-md-power/src/node/utils/cleanMarkdownEnv.ts index 533978c1..c2cd6628 100644 --- a/plugins/plugin-md-power/src/node/utils/cleanMarkdownEnv.ts +++ b/plugins/plugin-md-power/src/node/utils/cleanMarkdownEnv.ts @@ -36,13 +36,26 @@ const WHITE_LIST = ['base', 'filePath', 'filePathRelative', 'references', 'abbre type WhiteListUnion = (typeof WHITE_LIST)[number] /** - * Clean markdown environment, keeping only whitelisted keys + * Clean markdown environment for inline rendering. * - * 清理 Markdown 环境,仅保留白名单中的键 + * 清理 markdown 环境以用于行内渲染。 + * + * When using `md.renderInline()` in custom renderers, some environment properties + * may cause issues. This function creates a clean environment object with only + * the necessary properties preserved. + * + * 在自定义渲染器中使用 `md.renderInline()` 时,某些环境属性可能会导致问题。 + * 该函数创建一个只保留必要属性的干净环境对象。 * * @param env - Markdown environment / Markdown 环境 * @param excludes - Keys to exclude / 要排除的键 * @returns Cleaned environment / 清理后的环境 + * + * @example + * ```ts + * const cleanEnv = cleanMarkdownEnv(env) + * const rendered = md.renderInline(content, cleanEnv) + * ``` */ export function cleanMarkdownEnv(env: CleanMarkdownEnv, excludes: WhiteListUnion[] = []): CleanMarkdownEnv { const result: CleanMarkdownEnv = {}