-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
{ | ||
"name": "@vuepress/plugin-markdown-ext", | ||
"version": "2.0.0-rc.54", | ||
"description": "VuePress plugin - markdown extension", | ||
"keywords": [ | ||
"vuepress-plugin", | ||
"vuepress", | ||
"plugin", | ||
"markdown", | ||
"extension" | ||
], | ||
"homepage": "https://ecosystem.vuejs.press/plugins/markdown/markdown-ext.html", | ||
"bugs": { | ||
"url": "https://github.com/vuepress/ecosystem/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/vuepress/ecosystem.git", | ||
"directory": "plugins/markdown/plugin-markdown-ext" | ||
}, | ||
"license": "MIT", | ||
"author": { | ||
"name": "Mr.Hope", | ||
"email": "mister-hope@outlook.com", | ||
"url": "https://mister-hope.com" | ||
}, | ||
"type": "module", | ||
"exports": { | ||
".": "./lib/node/index.js", | ||
"./package.json": "./package.json" | ||
}, | ||
"main": "./lib/node/index.js", | ||
"types": "./lib/node/index.d.ts", | ||
"files": [ | ||
"lib" | ||
], | ||
"scripts": { | ||
"build": "tsc -b tsconfig.build.json", | ||
"bundle": "rollup -c rollup.config.ts --configPlugin esbuild", | ||
"clean": "rimraf --glob ./lib ./*.tsbuildinfo" | ||
}, | ||
"dependencies": { | ||
"@mdit/plugin-container": "^0.13.1", | ||
"@mdit/plugin-footnote": "^0.13.1", | ||
"@mdit/plugin-tasklist": "^0.13.1", | ||
"@types/markdown-it": "^14.1.2", | ||
"@vuepress/helper": "workspace:*", | ||
"js-yaml": "^4.1.0" | ||
}, | ||
"peerDependencies": { | ||
"vuepress": "2.0.0-rc.18" | ||
}, | ||
"devDependencies": { | ||
"@types/js-yaml": "4.0.9", | ||
"markdown-it": "^14.1.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { rollupBundle } from '../../../scripts/rollup.js' | ||
|
||
export default rollupBundle('node/index', { | ||
external: [ | ||
'@mdit/plugin-container', | ||
'@mdit/plugin-footnote', | ||
'@mdit/plugin-tasklist', | ||
'js-yaml', | ||
], | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './markdownExtPlugin.js' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { load } from 'js-yaml' | ||
import type { Options, PluginSimple } from 'markdown-it' | ||
import type { RenderRule } from 'markdown-it/lib/renderer.mjs' | ||
import type Token from 'markdown-it/lib/token.mjs' | ||
import type { MarkdownEnv } from 'vuepress/markdown' | ||
|
||
import { logger } from '../utils.js' | ||
import { stringifyProp } from './utils.js' | ||
|
||
const getComponentRender = | ||
(name: string): RenderRule => | ||
( | ||
tokens: Token[], | ||
index: number, | ||
_options: Options, | ||
{ filePathRelative }: MarkdownEnv, | ||
): string => { | ||
const token = tokens[index] | ||
const { content } = token | ||
|
||
let config: unknown = null | ||
|
||
if (content.trim().startsWith('{')) | ||
try { | ||
config = JSON.parse(content) as unknown | ||
} catch { | ||
// Do nothing | ||
} | ||
else | ||
try { | ||
config = load(content) | ||
} catch { | ||
// Do nothing | ||
} | ||
|
||
if (config) return `<${name} v-bind='${stringifyProp(config)}' />` | ||
|
||
logger.error( | ||
`Invalid ${name} config${ | ||
filePathRelative ? ` found in ${filePathRelative}` : '' | ||
}: | ||
${content} | ||
`, | ||
) | ||
|
||
return '' | ||
} | ||
|
||
export const component: PluginSimple = (md) => { | ||
// Handle ```component blocks | ||
const { fence } = md.renderer.rules | ||
|
||
md.renderer.rules.fence = (...args): string => { | ||
const [tokens, index] = args | ||
const { info } = tokens[index] | ||
|
||
const [fenceName, componentName] = info.split(' ', 2) | ||
|
||
if (fenceName === 'component') { | ||
const render = getComponentRender(componentName) | ||
|
||
return render(...args) | ||
} | ||
|
||
return fence!(...args) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './component.js' | ||
export * from './vPre.js' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Single quote will break @vue/compiler-sfc | ||
export const stringifyProp = (data: unknown): string => | ||
JSON.stringify(data).replace(/'/g, ''') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { container } from '@mdit/plugin-container' | ||
import type { PluginSimple } from 'markdown-it' | ||
|
||
export const vPre: PluginSimple = (md) => { | ||
container(md, { | ||
name: 'v-pre', | ||
openRender: () => `<div v-pre>\n`, | ||
closeRender: () => '</div>\n', | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { footnote as footnotePlugin } from '@mdit/plugin-footnote' | ||
import { tasklist as tasklistPlugin } from '@mdit/plugin-tasklist' | ||
import type { Plugin } from 'vuepress/core' | ||
import { isPlainObject } from 'vuepress/shared' | ||
|
||
import { | ||
component as componentPlugin, | ||
vPre as vPrePlugin, | ||
} from './markdown-it-plugins/index.js' | ||
import type { MarkdownExtPluginOptions } from './options.js' | ||
import { PLUGIN_NAME } from './utils.js' | ||
|
||
export const markdownExtPlugin = ({ | ||
gfm, | ||
breaks, | ||
linkify, | ||
footnote, | ||
tasklist, | ||
|
||
component, | ||
vPre, | ||
}: MarkdownExtPluginOptions): Plugin => { | ||
return { | ||
name: PLUGIN_NAME, | ||
|
||
extendsMarkdown: (md) => { | ||
// Behavior | ||
if (breaks ?? gfm) md.options.breaks = true | ||
if (linkify ?? gfm) md.options.linkify = true | ||
|
||
if (footnote ?? gfm) md.use(footnotePlugin) | ||
if (tasklist ?? gfm) | ||
md.use(tasklistPlugin, [isPlainObject(tasklist) ? tasklist : {}]) | ||
if (component) md.use(componentPlugin) | ||
if (vPre) md.use(vPrePlugin) | ||
}, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import type { MarkdownItTaskListOptions } from '@mdit/plugin-tasklist' | ||
|
||
/** | ||
* Options of markdown-ext plugin | ||
*/ | ||
export interface MarkdownExtPluginOptions { | ||
/** | ||
* Whether enable standard GFM support | ||
* | ||
* 是否启用标准的 GitHub Favor Markdown 支持 | ||
* | ||
* @default false | ||
*/ | ||
gfm?: boolean | ||
|
||
/** | ||
* Whether convert `\n` in paragraphs into `<br>`s | ||
* | ||
* 是否将段落中的 `\n` 转换为 `<br>` | ||
* | ||
* @description enabled in gfm mode | ||
* | ||
* @default false | ||
*/ | ||
breaks?: boolean | ||
|
||
/** | ||
* Whether convert URL-like text into links | ||
* | ||
* 是否将文字中的链接格式文字转换为链接 | ||
* | ||
* @description enabled in gfm mode | ||
* | ||
* @default false | ||
*/ | ||
linkify?: boolean | ||
|
||
/** | ||
* Whether to enable footnote format support | ||
* | ||
* 是否启用脚注格式支持。 | ||
* | ||
* @description enabled in gfm mode | ||
* | ||
* @default false | ||
*/ | ||
footnote?: boolean | ||
|
||
/** | ||
* Whether to enable tasklist format support | ||
* | ||
* 是否启用任务列表支持 | ||
* | ||
* @description enabled in gfm mode | ||
* | ||
* @default false | ||
*/ | ||
tasklist?: MarkdownItTaskListOptions | boolean | ||
|
||
/** | ||
* Whether to enable component support | ||
* | ||
* 是否启用组件支持 | ||
* | ||
* @default false | ||
*/ | ||
component?: boolean | ||
|
||
/** | ||
* Whether to enable v-pre wrapper. | ||
* | ||
* 是否启用 v-pre 容器。 | ||
* | ||
* @default false | ||
*/ | ||
vPre?: boolean | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Logger } from '@vuepress/helper' | ||
|
||
export const PLUGIN_NAME = '@vuepress/plugin-markdown-ext' | ||
|
||
export const logger = new Logger(PLUGIN_NAME) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import MarkdownIt from 'markdown-it' | ||
import { describe, expect, it } from 'vitest' | ||
|
||
import { component } from '../../src/node/markdown-it-plugins/component.js' | ||
|
||
describe('component', () => { | ||
const markdownIt = MarkdownIt({ linkify: true }).use(component) | ||
|
||
it('Should resolve component fence', () => { | ||
const result1 = markdownIt.render( | ||
` | ||
\`\`\`component VPCard | ||
title: A card | ||
desc: A card desc | ||
logo: https://example.com/logo.png | ||
link: https://example.com | ||
color: "#000" | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
const result2 = markdownIt.render( | ||
` | ||
\`\`\`component VPCard | ||
{ | ||
"title": "A card", | ||
"desc": "A card desc", | ||
"logo": "https://example.com/logo.png", | ||
"link": "https://example.com", | ||
"color": "#000" | ||
} | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
expect(result1).toContain('VPCard') | ||
expect(result1).toMatchSnapshot() | ||
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / coverageplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / build-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / bundle-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / coverageplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / build-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
Check failure on line 39 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / bundle-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should resolve component fence
|
||
expect(result2).toContain('VPCard') | ||
expect(result2).toMatchSnapshot() | ||
}) | ||
|
||
it('Should not throw with invalid syntax', () => { | ||
const result1 = markdownIt.render( | ||
` | ||
\`\`\`component VPCard | ||
title: a | ||
title: b | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
const result2 = markdownIt.render( | ||
` | ||
\`\`\`component VPCard | ||
title: a | ||
title: b | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
expect(result1).toEqual('') | ||
expect(result2).toEqual('') | ||
}) | ||
|
||
it('Should drop when receiving a invalid syntax', () => { | ||
const result = markdownIt.render( | ||
` | ||
\`\`\`component VPCard | ||
{a:1} | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
expect(result).toMatch('') | ||
}) | ||
|
||
it('Should not break markdown fence', () => { | ||
const result = markdownIt.render( | ||
` | ||
\`\`\`js | ||
const a = 1; | ||
\`\`\` | ||
`, | ||
{}, | ||
) | ||
|
||
expect(result).toMatch(/<pre.*>[\s\S]*<\/pre>/) | ||
expect(result).toMatchSnapshot() | ||
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / coverageplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / build-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / bundle-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / coverageplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / build-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
Check failure on line 93 in plugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts GitHub Actions / bundle-checkplugins/markdown/plugin-markdown-ext/tests/node/component.spec.ts > component > Should not break markdown fence
|
||
}) | ||
}) |