diff --git a/plugins/plugin-md-power/src/node/container/fileTree/resolveTreeNodeInfo.ts b/plugins/plugin-md-power/src/node/container/fileTree.ts similarity index 63% rename from plugins/plugin-md-power/src/node/container/fileTree/resolveTreeNodeInfo.ts rename to plugins/plugin-md-power/src/node/container/fileTree.ts index 410d21b0..df1964ec 100644 --- a/plugins/plugin-md-power/src/node/container/fileTree/resolveTreeNodeInfo.ts +++ b/plugins/plugin-md-power/src/node/container/fileTree.ts @@ -1,5 +1,8 @@ +import type { Markdown } from 'vuepress/markdown' import Token from 'markdown-it/lib/token.mjs' +import container from 'markdown-it-container' import { removeEndingSlash, removeLeadingSlash } from 'vuepress/shared' +import { getFileIcon } from '../fileIcons/index.js' interface FileTreeNode { filename: string @@ -9,6 +12,63 @@ interface FileTreeNode { empty: boolean } +const type = 'file-tree' +const closeType = `container_${type}_close` +const componentName = 'FileTreeItem' +const itemOpen = 'file_tree_item_open' +const itemClose = 'file_tree_item_close' + +export function fileTreePlugin(md: Markdown) { + const validate = (info: string): boolean => info.trim().startsWith(type) + const render = (tokens: Token[], idx: number): string => { + if (tokens[idx].nesting === 1) { + const hasRes: number[] = [] // level stack + for ( + let i = idx + 1; + !(tokens[i].nesting === -1 + && tokens[i].type === closeType); + ++i + ) { + const token = tokens[i] + if (token.type === 'list_item_open') { + const result = resolveTreeNodeInfo(tokens, token, i) + if (result) { + hasRes.push(token.level) + const [info, inline] = result + const { filename, type, expanded, empty } = info + const icon = getFileIcon(filename, type) + + token.type = itemOpen + token.tag = componentName + token.attrSet('type', type) + token.attrSet(':expanded', expanded ? 'true' : 'false') + token.attrSet(':empty', empty ? 'true' : 'false') + updateInlineToken(inline, info, icon) + } + else { + hasRes.push(-1) + } + } + else if (token.type === 'list_item_close') { + if (token.level === hasRes.pop()) { + token.type = itemClose + token.tag = componentName + } + } + } + const info = tokens[idx].info.trim() + + const title = info.slice(type.length).trim() + return `
${title ? `

${title}

` : ''}` + } + else { + return '
' + } + } + + md.use(container, type, { validate, render }) +} + export function resolveTreeNodeInfo( tokens: Token[], current: Token, diff --git a/plugins/plugin-md-power/src/node/container/fileTree/index.ts b/plugins/plugin-md-power/src/node/container/fileTree/index.ts deleted file mode 100644 index e575307e..00000000 --- a/plugins/plugin-md-power/src/node/container/fileTree/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type Token from 'markdown-it/lib/token.mjs' -import type { Markdown } from 'vuepress/markdown' -import container from 'markdown-it-container' -import { getFileIcon } from './findIcon.js' -import { resolveTreeNodeInfo, updateInlineToken } from './resolveTreeNodeInfo.js' - -const type = 'file-tree' -const closeType = `container_${type}_close` -const componentName = 'FileTreeItem' -const itemOpen = 'file_tree_item_open' -const itemClose = 'file_tree_item_close' - -export function fileTreePlugin(md: Markdown) { - const validate = (info: string): boolean => info.trim().startsWith(type) - const render = (tokens: Token[], idx: number): string => { - if (tokens[idx].nesting === 1) { - const hasRes: number[] = [] // level stack - for ( - let i = idx + 1; - !(tokens[i].nesting === -1 - && tokens[i].type === closeType); - ++i - ) { - const token = tokens[i] - if (token.type === 'list_item_open') { - const result = resolveTreeNodeInfo(tokens, token, i) - if (result) { - hasRes.push(token.level) - const [info, inline] = result - const { filename, type, expanded, empty } = info - const icon = getFileIcon(filename, type) - - token.type = itemOpen - token.tag = componentName - token.attrSet('type', type) - token.attrSet(':expanded', expanded ? 'true' : 'false') - token.attrSet(':empty', empty ? 'true' : 'false') - updateInlineToken(inline, info, icon) - } - else { - hasRes.push(-1) - } - } - else if (token.type === 'list_item_close') { - if (token.level === hasRes.pop()) { - token.type = itemClose - token.tag = componentName - } - } - } - const info = tokens[idx].info.trim() - - const title = info.slice(type.length).trim() - return `
${title ? `

${title}

` : ''}` - } - else { - return '
' - } - } - - md.use(container, type, { validate, render }) -} diff --git a/plugins/plugin-md-power/src/node/container/index.ts b/plugins/plugin-md-power/src/node/container/index.ts index d8bc84ac..59aaf591 100644 --- a/plugins/plugin-md-power/src/node/container/index.ts +++ b/plugins/plugin-md-power/src/node/container/index.ts @@ -1,7 +1,7 @@ import type { App } from 'vuepress' import type { Markdown } from 'vuepress/markdown' import type { MarkdownPowerPluginOptions } from '../../shared/index.js' -import { fileTreePlugin } from './fileTree/index.js' +import { fileTreePlugin } from './fileTree.js' import { langReplPlugin } from './langRepl.js' export async function containerPlugin( diff --git a/plugins/plugin-md-power/src/node/container/fileTree/definitions.ts b/plugins/plugin-md-power/src/node/fileIcons/definitions.ts similarity index 100% rename from plugins/plugin-md-power/src/node/container/fileTree/definitions.ts rename to plugins/plugin-md-power/src/node/fileIcons/definitions.ts diff --git a/plugins/plugin-md-power/src/node/container/fileTree/findIcon.ts b/plugins/plugin-md-power/src/node/fileIcons/findIcon.ts similarity index 100% rename from plugins/plugin-md-power/src/node/container/fileTree/findIcon.ts rename to plugins/plugin-md-power/src/node/fileIcons/findIcon.ts diff --git a/plugins/plugin-md-power/src/node/fileIcons/index.ts b/plugins/plugin-md-power/src/node/fileIcons/index.ts new file mode 100644 index 00000000..10170d63 --- /dev/null +++ b/plugins/plugin-md-power/src/node/fileIcons/index.ts @@ -0,0 +1,2 @@ +export * from './definitions.js' +export * from './findIcon.js'