diff --git a/packages/markdown/src/markdown.ts b/packages/markdown/src/markdown.ts index abe1235235..88aeb05e83 100644 --- a/packages/markdown/src/markdown.ts +++ b/packages/markdown/src/markdown.ts @@ -1,9 +1,9 @@ import { slugify as defaultSlugify } from '@mdit-vue/shared' +import { logger } from '@vuepress/utils' import MarkdownIt from 'markdown-it' import { anchorPlugin, assetsPlugin, - codePlugin, componentPlugin, emojiPlugin, frontmatterPlugin, @@ -13,11 +13,11 @@ import { sfcPlugin, titlePlugin, tocPlugin, + vPrePlugin, } from './plugins.js' import type { AnchorPluginOptions, AssetsPluginOptions, - CodePluginOptions, EmojiPluginOptions, FrontmatterPluginOptions, HeadersPluginOptions, @@ -25,6 +25,7 @@ import type { LinksPluginOptions, SfcPluginOptions, TocPluginOptions, + VPrePluginOptions, } from './plugins.js' import type { Markdown, MarkdownOptions } from './types.js' @@ -35,6 +36,7 @@ export const createMarkdown = ({ anchor, assets, code, + vPre, component, emoji, frontmatter, @@ -82,8 +84,10 @@ export const createMarkdown = ({ } // process code fence - if (code !== false) { - md.use(codePlugin, code) + if (code) { + logger.warn( + `\`markdown.code\` option has been removed, please use '@vuepress/plugin-shiki' or '@vuepress/plugin-prismjs' instead.\n See https://v2.vuepress.vuejs.org/reference/config.html#markdown-code`, + ) } // treat unknown html tags as components @@ -146,5 +150,10 @@ export const createMarkdown = ({ md.use(titlePlugin) } + // add v-pre to `
` and ``
+  if (vPre !== false) {
+    md.use(vPrePlugin, vPre)
+  }
+
   return md
 }
diff --git a/packages/markdown/src/plugins.ts b/packages/markdown/src/plugins.ts
index 8c2161e71f..a1ceb31f29 100644
--- a/packages/markdown/src/plugins.ts
+++ b/packages/markdown/src/plugins.ts
@@ -22,10 +22,6 @@ export {
   assetsPlugin,
   type AssetsPluginOptions,
 } from './plugins/assetsPlugin/assetsPlugin.js'
-export {
-  codePlugin,
-  type CodePluginOptions,
-} from './plugins/codePlugin/codePlugin.js'
 export { emojiPlugin, type EmojiPluginOptions } from './plugins/emojiPlugin.js'
 export {
   importCodePlugin,
@@ -35,3 +31,7 @@ export {
   linksPlugin,
   type LinksPluginOptions,
 } from './plugins/linksPlugin/linksPlugin.js'
+export {
+  vPrePlugin,
+  type VPrePluginOptions,
+} from './plugins/vPrePlugin/vPrePlugin.js'
diff --git a/packages/markdown/src/plugins/codePlugin/codePlugin.ts b/packages/markdown/src/plugins/codePlugin/codePlugin.ts
deleted file mode 100644
index c930933468..0000000000
--- a/packages/markdown/src/plugins/codePlugin/codePlugin.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import type { PluginWithOptions } from 'markdown-it'
-import { resolveAttr } from './resolveAttr.js'
-import {
-  isHighlightLine,
-  resolveHighlightLines,
-} from './resolveHighlightLines.js'
-import { resolveLanguage } from './resolveLanguage.js'
-import { resolveLineNumbers } from './resolveLineNumbers.js'
-import { resolveVPre } from './resolveVPre.js'
-
-export interface CodePluginOptions {
-  /**
-   * Enable highlight lines or not
-   */
-  highlightLines?: boolean
-
-  /**
-   * Enable line numbers or not
-   *
-   * - A `boolean` value is to enable line numbers or not.
-   * - A `number` value is the minimum number of lines to enable line numbers
-   */
-  lineNumbers?: boolean | number
-
-  /**
-   * Wrap the `
` tag with an extra `
` or not. Do not disable it unless you - * understand what's it for - * - * - Required for `highlightLines` - * - Required for `lineNumbers` - * - Required for title display of default theme - */ - preWrapper?: boolean - - /** - * Add `v-pre` directive or not - */ - vPre?: { - /** - * Add `v-pre` directive to `
` tag of code block or not
-     */
-    block?: boolean
-
-    /**
-     * Add `v-pre` directive to `` tag of inline code or not
-     */
-    inline?: boolean
-  }
-}
-
-/**
- * Code plugin
- */
-export const codePlugin: PluginWithOptions = (
-  md,
-  {
-    highlightLines = true,
-    lineNumbers = true,
-    preWrapper = true,
-    vPre: { block: vPreBlock = true, inline: vPreInline = true } = {},
-  }: CodePluginOptions = {},
-): void => {
-  // override default fence renderer
-  md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
-    const token = tokens[idx]
-
-    // get token info
-    const info = token.info ? md.utils.unescapeAll(token.info).trim() : ''
-
-    // resolve language from token info
-    const language = resolveLanguage(info)
-    const languageClass = `${options.langPrefix}${language.name}`
-
-    // try to get highlighted code
-    const code =
-      options.highlight?.(token.content, language.name, '') ||
-      md.utils.escapeHtml(token.content)
-
-    token.attrJoin('class', languageClass)
-
-    // wrap highlighted code with `
` and ``
-    let result = code.startsWith('${code}
` - - // resolve v-pre mark from token info - const useVPre = resolveVPre(info) ?? vPreBlock - if (useVPre) { - result = `
 {
-          if (isHighlightLine(index + 1, highlightLinesRanges)) {
-            return '
 
' - } - return '
' - }) - .join('') - - result = `${result}
${highlightLinesCode}
` - } - - // resolve line-numbers mark from token info - const useLineNumbers = - resolveLineNumbers(info) ?? - (typeof lineNumbers === 'number' - ? lines.length >= lineNumbers - : lineNumbers) - // generate line numbers - if (useLineNumbers) { - // generate line numbers code - const lineNumbersCode = lines - .map(() => `
`) - .join('') - - result = `${result}` - } - - // resolve title from token info - const title = resolveAttr(info, 'title') ?? language.ext - - result = `
${result}
` - - return result - } - - if (vPreInline) { - const rawInlineCodeRule = md.renderer.rules.code_inline! - md.renderer.rules.code_inline = (tokens, idx, options, env, slf) => { - const result = rawInlineCodeRule(tokens, idx, options, env, slf) - return ` { - // try to match specified attr mark - const pattern = `\\b${attr}\\s*=\\s*(?['"])(?.+?)\\k(\\s|$)` - const regex = new RegExp(pattern, 'i') - const match = info.match(regex) - - // return content if matched, null if not specified - return match?.groups?.content ?? null -} diff --git a/packages/markdown/src/plugins/codePlugin/resolveHighlightLines.ts b/packages/markdown/src/plugins/codePlugin/resolveHighlightLines.ts deleted file mode 100644 index 6c41120144..0000000000 --- a/packages/markdown/src/plugins/codePlugin/resolveHighlightLines.ts +++ /dev/null @@ -1,34 +0,0 @@ -export type HighlightLinesRange = [start: number, end: number] - -/** - * Resolve highlight-lines ranges from token info - */ -export const resolveHighlightLines = ( - info: string, -): HighlightLinesRange[] | null => { - // try to match highlight-lines mark - const match = info.match(/{([\d,-]+)}/) - - // no highlight-lines mark, return `null` - if (match === null) { - return null - } - - // resolve lines ranges from the highlight-lines mark - return match[1].split(',').map((item) => { - const range = item.split('-') - if (range.length === 1) { - range.push(range[0]) - } - return range.map((str) => Number.parseInt(str, 10)) as HighlightLinesRange - }) -} - -/** - * Check if a line number is in ranges - */ -export const isHighlightLine = ( - lineNumber: number, - ranges: HighlightLinesRange[], -): boolean => - ranges.some(([start, end]) => lineNumber >= start && lineNumber <= end) diff --git a/packages/markdown/src/plugins/codePlugin/resolveLanguage.ts b/packages/markdown/src/plugins/codePlugin/resolveLanguage.ts deleted file mode 100644 index 8f2bde24f7..0000000000 --- a/packages/markdown/src/plugins/codePlugin/resolveLanguage.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as languages from './languages.js' -import type { HighlightLanguage } from './languages.js' - -type LanguagesMap = Record - -/** - * A key-value map to get language info from alias - * - * - key: alias - * - value: language - */ -let languagesMap: LanguagesMap - -/** - * Lazy generate languages map - */ -const getLanguagesMap = (): LanguagesMap => { - if (!languagesMap) { - languagesMap = Object.values(languages).reduce((result, item) => { - item.aliases.forEach((alias) => { - result[alias] = item - }) - return result - }, {} as LanguagesMap) - } - - return languagesMap -} - -/** - * Resolve language for highlight from token info - */ -export const resolveLanguage = (info: string): HighlightLanguage => { - // get user-defined language alias - const alias = info.match(/^([^ :[{]+)/)?.[1] || 'text' - - // if the alias does not have a match in the map - // fallback to the alias itself - return ( - getLanguagesMap()[alias] ?? { - name: alias, - ext: alias, - aliases: [alias], - } - ) -} diff --git a/packages/markdown/src/plugins/codePlugin/resolveLineNumbers.ts b/packages/markdown/src/plugins/codePlugin/resolveLineNumbers.ts deleted file mode 100644 index 73cd43a83c..0000000000 --- a/packages/markdown/src/plugins/codePlugin/resolveLineNumbers.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Resolve the `:line-numbers` / `:no-line-numbers` mark from token info - */ -export const resolveLineNumbers = (info: string): boolean | null => { - if (/:line-numbers\b/.test(info)) { - return true - } - - if (/:no-line-numbers\b/.test(info)) { - return false - } - - return null -} diff --git a/packages/markdown/src/plugins/codePlugin/resolveVPre.ts b/packages/markdown/src/plugins/vPrePlugin/resolveVPre.ts similarity index 100% rename from packages/markdown/src/plugins/codePlugin/resolveVPre.ts rename to packages/markdown/src/plugins/vPrePlugin/resolveVPre.ts diff --git a/packages/markdown/src/plugins/vPrePlugin/vPrePlugin.ts b/packages/markdown/src/plugins/vPrePlugin/vPrePlugin.ts new file mode 100644 index 0000000000..78787f4f30 --- /dev/null +++ b/packages/markdown/src/plugins/vPrePlugin/vPrePlugin.ts @@ -0,0 +1,46 @@ +import type { PluginWithOptions } from 'markdown-it' +import { resolveVPre } from './resolveVPre.js' + +export interface VPrePluginOptions { + /** + * Add `v-pre` directive to `
` tag of code block or not
+   */
+  block?: boolean
+
+  /**
+   * Add `v-pre` directive to `` tag of inline code or not
+   */
+  inline?: boolean
+}
+
+/**
+ * v-pre plugin
+ */
+export const vPrePlugin: PluginWithOptions = (
+  md,
+  { inline = true, block = true }: VPrePluginOptions = {},
+) => {
+  const rawFence = md.renderer.rules.fence!
+  md.renderer.rules.fence = (...args) => {
+    const [tokens, idx] = args
+    const token = tokens[idx]
+
+    // get token info
+    const info = token.info ? md.utils.unescapeAll(token.info).trim() : ''
+
+    let result = rawFence(...args)
+
+    if (resolveVPre(info) ?? block) {
+      result = `
 {
+      const result = rawInlineCodeRule(...args)
+      return ` plugins > codePlugin > :line-numbers / :no-line-numbers > should work properly if \`lineNumbers\` is disabled by default 1`] = `
-"
Raw text
-
Raw text
-
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > :line-numbers / :no-line-numbers > should work properly if \`lineNumbers\` is enabled by default 1`] = ` -"
Raw text
-
Raw text
-
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > :line-numbers / :no-line-numbers > should work properly if \`lineNumbers\` is set to a number by default 1`] = ` -"
Raw text
-
Raw text
-
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > :v-pre / :no-v-pre > should work properly if \`vPre.block\` is disabled by default 1`] = ` -"
Raw text
-
Raw text
-
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > :v-pre / :no-v-pre > should work properly if \`vPre.block\` is enabled by default 1`] = ` -"
Raw text
-
Raw text
-
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`highlightLines\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-

{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`lineNumbers\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`preWrapper\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-

{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`vPre.block\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`vPre.inline\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should disable \`vPre.inline\` and \`vPre.block\` 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should enable \`lineNumbers\` according to number of code lines 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > plugin options > should process code fences with default options 1`] = ` -"
Raw text
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
 
 



const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-
-const baz = () => {
-  return 2048
-}
-
 
 
 
 
 




{{ inlineCode }}

-" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > syntax highlighting > should work if highlighted code is not wrapped with \`
\` 1`] = `
-"
highlighted code: Raw text
-, lang: text
highlighted code: const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-, lang: javascript
highlighted code: const foo: string = 'foo'
-
-function bar (): number {
-  return 1024
-}
-, lang: typescript
highlighted code: 
-
-, lang: vue-html
" -`; - -exports[`@vuepress/markdown > plugins > codePlugin > syntax highlighting > should work if highlighted code is wrapped with \`
\` 1`] = `
-"
highlighted code: Raw text
-, lang: text
highlighted code: const foo = 'foo'
-
-function bar () {
-  return 1024
-}
-, lang: javascript
highlighted code: const foo: string = 'foo'
-
-function bar (): number {
-  return 1024
-}
-, lang: typescript
highlighted code: 
-
-, lang: vue-html
" -`; diff --git a/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap b/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap index 5f6171d6f2..afce065776 100644 --- a/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap +++ b/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap @@ -1,15 +1,21 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`@vuepress/markdown > plugins > importCodePlugin > compatibility with codePlugin > should work with syntax supported by codePlugin 1`] = ` -"
const msg = 'hello from js'
+exports[`@vuepress/markdown > plugins > importCodePlugin > compatibility with otherPlugin > should preserve the things after code as fence info 1`] = `
+"
const msg = 'hello from js'
 
 console.log(msg)
 
 console.log('foo bar')
-
 

 
 

# msg
+
+" +`; + +exports[`@vuepress/markdown > plugins > importCodePlugin > compatibility with otherPlugin > should preserve the things after code as fence info 2`] = ` +"
# msg
 
 hello from md
 
 ## foo bar
-
" +
+" `; diff --git a/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap b/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap new file mode 100644 index 0000000000..6cb750f95f --- /dev/null +++ b/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap @@ -0,0 +1,101 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should work if \`block\` is disabled 1`] = ` +"
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should work if \`block\` is enabled by default 1`] = ` +"
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+
const a = 1
+
+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`block\` 1`] = ` +"
const a = 1
+
+

inline

+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`block\` and \`inline\` 1`] = ` +"
const a = 1
+
+

inline

+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`inline\` 1`] = ` +"
const a = 1
+
+

inline

+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should process code with default options 1`] = ` +"
const a = 1
+
+

inline

+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > syntax highlighting > should work highlighted code is wrapped with \`
\` 1`] = `
+"
highlighted code: const a = 1
+, lang: js:v-pre
+
highlighted code: const a = 1
+, lang: js:no-v-pre
+
highlighted code: const a = 1
+, lang: js{1,2}:v-pre
+
highlighted code: const a = 1
+, lang: js{1,2}:no-v-pre
+
highlighted code: const a = 1
+, lang: js:other-syntax:v-pre
+
highlighted code: const a = 1
+, lang: js:other-syntax:no-v-pre
+
highlighted code: const a = 1
+, lang: js
+" +`; + +exports[`@vuepress/markdown > plugins > vPrePlugin > syntax highlighting > should work if highlighted code is not wrapped with \`
\` 1`] = `
+"
highlighted code: const a = 1
+, lang: js:v-pre
+
highlighted code: const a = 1
+, lang: js:no-v-pre
+
highlighted code: const a = 1
+, lang: js{1,2}:v-pre
+
highlighted code: const a = 1
+, lang: js{1,2}:no-v-pre
+
highlighted code: const a = 1
+, lang: js:other-syntax:v-pre
+
highlighted code: const a = 1
+, lang: js:other-syntax:no-v-pre
+
highlighted code: const a = 1
+, lang: js
+" +`; diff --git a/packages/markdown/tests/plugins/codePlugin.spec.ts b/packages/markdown/tests/plugins/codePlugin.spec.ts deleted file mode 100644 index 2033a74072..0000000000 --- a/packages/markdown/tests/plugins/codePlugin.spec.ts +++ /dev/null @@ -1,372 +0,0 @@ -import MarkdownIt from 'markdown-it' -import { describe, expect, it, vi } from 'vitest' -import { codePlugin } from '../../src/index.js' - -const codeFence = '```' - -describe('@vuepress/markdown > plugins > codePlugin', () => { - describe('plugin options', () => { - const source = `\ -${codeFence} -Raw text -${codeFence} - -${codeFence}ts -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2} -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts title="config/foo.ts" foo="foo" {1,2-4,5-5} -const foo = 'foo' - -function bar () { - return 1024 -} - -const baz = () => { - return 2048 -} -${codeFence} - -${codeFence}{{ inlineCode }}${codeFence} -` - - it('should process code fences with default options', () => { - const md = MarkdownIt().use(codePlugin) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `highlightLines`', () => { - const md = MarkdownIt().use(codePlugin, { - highlightLines: false, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `lineNumbers`', () => { - const md = MarkdownIt().use(codePlugin, { - lineNumbers: false, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should enable `lineNumbers` according to number of code lines', () => { - const md = MarkdownIt().use(codePlugin, { - lineNumbers: 4, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `preWrapper`', () => { - const md = MarkdownIt().use(codePlugin, { - preWrapper: false, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `vPre.block`', () => { - const md = MarkdownIt().use(codePlugin, { - vPre: { - block: false, - inline: true, - }, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `vPre.inline`', () => { - const md = MarkdownIt().use(codePlugin, { - vPre: { - block: true, - inline: false, - }, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should disable `vPre.inline` and `vPre.block`', () => { - const md = MarkdownIt().use(codePlugin, { - vPre: { - block: false, - inline: false, - }, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should always disable `highlightLines` if `preWrapper` is disabled', () => { - const mdWithHighlightLines = MarkdownIt().use(codePlugin, { - highlightLines: true, - preWrapper: false, - }) - const mdWithoutHighlightLine = MarkdownIt().use(codePlugin, { - highlightLines: false, - preWrapper: false, - }) - - expect(mdWithHighlightLines.render(source)).toBe( - mdWithoutHighlightLine.render(source), - ) - }) - - it('should always disable `lineNumbers` if `preWrapper` is disabled', () => { - const mdWithLineNumbers = MarkdownIt().use(codePlugin, { - lineNumbers: true, - preWrapper: false, - }) - const mdWithoutLineNumbers = MarkdownIt().use(codePlugin, { - lineNumbers: false, - preWrapper: false, - }) - - expect(mdWithLineNumbers.render(source)).toBe( - mdWithoutLineNumbers.render(source), - ) - }) - }) - - describe(':line-numbers / :no-line-numbers', () => { - const source = `\ -${codeFence} -Raw text -${codeFence} - -${codeFence}:line-numbers -Raw text -${codeFence} - -${codeFence}:no-line-numbers -Raw text -${codeFence} - -${codeFence}ts -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts:line-numbers -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts:no-line-numbers -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2} -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2}:line-numbers -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts title="config/foo.ts" foo="foo" {1,2}:no-line-numbers -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} -` - - it('should work properly if `lineNumbers` is enabled by default', () => { - const md = MarkdownIt().use(codePlugin, { - lineNumbers: true, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should work properly if `lineNumbers` is disabled by default', () => { - const md = MarkdownIt().use(codePlugin, { - lineNumbers: false, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should work properly if `lineNumbers` is set to a number by default', () => { - const md = MarkdownIt().use(codePlugin, { - lineNumbers: 4, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - }) - - describe(':v-pre / :no-v-pre', () => { - const source = `\ -${codeFence} -Raw text -${codeFence} - -${codeFence}:v-pre -Raw text -${codeFence} - -${codeFence}:no-v-pre -Raw text -${codeFence} - -${codeFence}ts -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts:v-pre -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts:no-v-pre -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2} -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2}:v-pre -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts{1,2}:no-v-pre -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} -` - - it('should work properly if `vPre.block` is enabled by default', () => { - const md = MarkdownIt().use(codePlugin, { - vPre: { - block: true, - }, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - - it('should work properly if `vPre.block` is disabled by default', () => { - const md = MarkdownIt().use(codePlugin, { - vPre: { - block: false, - }, - }) - - expect(md.render(source)).toMatchSnapshot() - }) - }) - - describe('syntax highlighting', () => { - const source = `\ -${codeFence} -Raw text -${codeFence} - -${codeFence}js -const foo = 'foo' - -function bar () { - return 1024 -} -${codeFence} - -${codeFence}ts -const foo: string = 'foo' - -function bar (): number { - return 1024 -} -${codeFence} - -${codeFence}vue-html - - -${codeFence} -` - - it('should work if highlighted code is wrapped with `
`', () => {
-      const highlight = vi.fn(
-        (code, lang) =>
-          `
highlighted code: ${code}, lang: ${lang}
`, - ) - const md = MarkdownIt({ highlight }).use(codePlugin) - - expect(md.render(source)).toMatchSnapshot() - expect(highlight).toHaveBeenCalledTimes(4) - }) - - it('should work if highlighted code is not wrapped with `
`', () => {
-      const highlight = vi.fn(
-        (code, lang) => `highlighted code: ${code}, lang: ${lang}`,
-      )
-      const md = MarkdownIt({ highlight }).use(codePlugin)
-
-      expect(md.render(source)).toMatchSnapshot()
-      expect(highlight).toHaveBeenCalledTimes(4)
-    })
-  })
-})
diff --git a/packages/markdown/tests/plugins/importCodePlugin.spec.ts b/packages/markdown/tests/plugins/importCodePlugin.spec.ts
index 66e467cc97..157c6a6fef 100644
--- a/packages/markdown/tests/plugins/importCodePlugin.spec.ts
+++ b/packages/markdown/tests/plugins/importCodePlugin.spec.ts
@@ -9,7 +9,7 @@ import {
   it,
   vi,
 } from 'vitest'
-import { codePlugin, importCodePlugin } from '../../src/index.js'
+import { importCodePlugin, vPrePlugin } from '../../src/index.js'
 import type { MarkdownEnv } from '../../src/index.js'
 
 const jsFixturePathRelative = '../__fixtures__/importCode.js'
@@ -283,21 +283,67 @@ foo
     })
   })
 
-  describe('compatibility with codePlugin', () => {
-    it('should work with syntax supported by codePlugin', () => {
-      const source = `\
+  describe('compatibility with otherPlugin', () => {
+    it('should preserve the things after code as fence info', () => {
+      const source1 = `\
 @[code js{1,3-4}](${jsFixturePathRelative})
-@[code md:no-line-numbers title="no-line-numbers.md"](${mdFixturePathRelative})
 `
+      const source2 = `\
+@[code md:no-line-numbers:no-v-pre title="no-line-numbers.md"](${mdFixturePathRelative})
+`
+
+      const md = MarkdownIt().use(importCodePlugin)
+      const env1: MarkdownEnv = {
+        filePath: __filename,
+      }
+
+      const rendered1 = md.render(source1, env1)
+
+      expect(rendered1).toEqual(
+        md.render(`\
+\`\`\`js{1,3-4}
+${jsFixtureContent}\
+\`\`\`
+`),
+      )
+      expect(rendered1).toMatchSnapshot()
+      expect(env1.importedFiles).toEqual([jsFixturePath])
+
+      const env2: MarkdownEnv = {
+        filePath: __filename,
+      }
 
-      const md = MarkdownIt().use(importCodePlugin).use(codePlugin)
+      const rendered2 = md.render(source2, env2)
+
+      expect(rendered2).toEqual(
+        md.render(`\
+\`\`\`md:no-line-numbers:no-v-pre title="no-line-numbers.md"
+${mdFixtureContent}\
+\`\`\`
+`),
+      )
+      expect(rendered2).toMatchSnapshot()
+      expect(env2.importedFiles).toEqual([mdFixturePath])
+    })
+
+    it('should work with syntax supported by vPrePlugin', () => {
+      const source1 = `\
+@[code js{1,3-4}](${jsFixturePathRelative})
+`
+      const source2 = `\
+@[code md:no-line-numbers:no-v-pre title="no-line-numbers.md"](${mdFixturePathRelative})
+`
+
+      const md = MarkdownIt().use(importCodePlugin).use(vPrePlugin)
       const env: MarkdownEnv = {
         filePath: __filename,
       }
-      const rendered = md.render(source, env)
 
-      expect(rendered).toMatchSnapshot()
-      expect(env.importedFiles).toEqual([jsFixturePath, mdFixturePath])
+      const rendered1 = md.render(source1, env)
+      const rendered2 = md.render(source2, env)
+
+      expect(rendered1).to.contain('v-pre')
+      expect(rendered2).to.not.contain(' v-pre')
     })
   })
 })
diff --git a/packages/markdown/tests/plugins/vPrePlugin.spec.ts b/packages/markdown/tests/plugins/vPrePlugin.spec.ts
new file mode 100644
index 0000000000..1bda5aaf05
--- /dev/null
+++ b/packages/markdown/tests/plugins/vPrePlugin.spec.ts
@@ -0,0 +1,136 @@
+import MarkdownIt from 'markdown-it'
+import { describe, expect, it, vi } from 'vitest'
+import { vPrePlugin } from '../../src/index.js'
+
+const codeFence = '```'
+
+describe('@vuepress/markdown > plugins > vPrePlugin', () => {
+  describe('plugin options', () => {
+    const source = `\
+${codeFence}js
+const a = 1
+${codeFence}
+
+\`inline\`
+`
+    it('should process code with default options', () => {
+      const md = MarkdownIt().use(vPrePlugin)
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+
+    it('should disable `block`', () => {
+      const md = MarkdownIt().use(vPrePlugin, { block: false })
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+
+    it('should disable `inline`', () => {
+      const md = MarkdownIt().use(vPrePlugin, { inline: false })
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+
+    it('should disable `block` and `inline`', () => {
+      const md = MarkdownIt().use(vPrePlugin, { block: false, inline: false })
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+  })
+
+  describe(':v-pre / :no-v-pre', () => {
+    const source = `\
+${codeFence}js:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js{1,2}:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js{1,2}:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:other-syntax:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:other-syntax:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js
+const a = 1
+${codeFence}
+`
+    it('should work if `block` is enabled by default', () => {
+      const md = MarkdownIt().use(vPrePlugin)
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+
+    it('should work if `block` is disabled', () => {
+      const md = MarkdownIt().use(vPrePlugin, { block: false })
+
+      expect(md.render(source)).toMatchSnapshot()
+    })
+  })
+
+  describe('syntax highlighting', () => {
+    const source = `\
+${codeFence}js:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js{1,2}:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js{1,2}:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:other-syntax:v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js:other-syntax:no-v-pre
+const a = 1
+${codeFence}
+
+${codeFence}js
+const a = 1
+${codeFence}
+`
+    it('should work highlighted code is wrapped with `
`', () => {
+      const highlight = vi.fn(
+        (code, lang) =>
+          `
highlighted code: ${code}, lang: ${lang}
`, + ) + + const md = MarkdownIt({ highlight }).use(vPrePlugin) + + expect(md.render(source)).toMatchSnapshot() + expect(highlight).toHaveBeenCalledTimes(7) + }) + + it('should work if highlighted code is not wrapped with `
`', () => {
+      const highlight = vi.fn(
+        (code, lang) => `highlighted code: ${code}, lang: ${lang}`,
+      )
+      const md = MarkdownIt({ highlight }).use(vPrePlugin)
+
+      expect(md.render(source)).toMatchSnapshot()
+      expect(highlight).toHaveBeenCalledTimes(7)
+    })
+  })
+})