mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
refactor(plugin-md-power): improve md plugins (#562)
This commit is contained in:
parent
7c05f3abc3
commit
b07426dfc6
@ -18,7 +18,6 @@ permalink: /guide/chart/mermaid/
|
||||
你需要在你的项目中安装 [mermaid](https://mermaid.js.org/) 库。
|
||||
|
||||
::: npm-to
|
||||
@tab pnpm
|
||||
|
||||
```sh
|
||||
npm install mermaid
|
||||
|
||||
@ -40,7 +40,7 @@ export default defineUserConfig({
|
||||
golang 代码演示默认是只读的,不可编辑。
|
||||
|
||||
````md
|
||||
::: go-repl 自定义标题
|
||||
::: go-repl title="自定义标题"
|
||||
```go
|
||||
// your go code
|
||||
```
|
||||
@ -49,10 +49,10 @@ golang 代码演示默认是只读的,不可编辑。
|
||||
|
||||
### 可编辑代码演示
|
||||
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: go-repl#editable` 容器语法中
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: go-repl editable` 容器语法中
|
||||
|
||||
````md
|
||||
::: go-repl#editable 自定义标题
|
||||
::: go-repl editable title="自定义标题"
|
||||
```go
|
||||
// your go code
|
||||
```
|
||||
@ -103,7 +103,7 @@ func main() {
|
||||
**输入:**
|
||||
|
||||
````md
|
||||
:::go-repl#editable
|
||||
:::go-repl editable
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -120,7 +120,7 @@ func main() {
|
||||
|
||||
**输出:**
|
||||
|
||||
:::go-repl#editable
|
||||
:::go-repl editable
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -40,7 +40,7 @@ export default defineUserConfig({
|
||||
kotlin 代码演示默认是只读的,不可编辑。
|
||||
|
||||
````md
|
||||
::: kotlin-repl 自定义标题
|
||||
::: kotlin-repl title="自定义标题"
|
||||
```kotlin
|
||||
// your kotlin code
|
||||
```
|
||||
@ -49,10 +49,10 @@ kotlin 代码演示默认是只读的,不可编辑。
|
||||
|
||||
### 可编辑代码演示
|
||||
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: kotlin-repl#editable` 容器语法中
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: kotlin-repl editable` 容器语法中
|
||||
|
||||
````md
|
||||
::: kotlin-repl#editable 自定义标题
|
||||
::: kotlin-repl editable title="自定义标题"
|
||||
```kotlin
|
||||
// your kotlin code
|
||||
```
|
||||
@ -114,7 +114,7 @@ fun main(args: Array<String>) {
|
||||
**输入:**
|
||||
|
||||
````md
|
||||
::: kotlin-repl#editable
|
||||
::: kotlin-repl editable
|
||||
```kotlin
|
||||
class Contact(val id: Int, var email: String)
|
||||
|
||||
@ -128,7 +128,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
**输出:**
|
||||
|
||||
::: kotlin-repl#editable
|
||||
::: kotlin-repl editable
|
||||
|
||||
```kotlin
|
||||
class Contact(val id: Int, var email: String)
|
||||
|
||||
@ -40,7 +40,7 @@ export default defineUserConfig({
|
||||
rust 代码演示默认是只读的,不可编辑。
|
||||
|
||||
````md
|
||||
::: rust-repl 自定义标题
|
||||
::: rust-repl title="自定义标题"
|
||||
```rust
|
||||
// your rust code
|
||||
```
|
||||
@ -49,10 +49,10 @@ rust 代码演示默认是只读的,不可编辑。
|
||||
|
||||
### 可编辑代码演示
|
||||
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: rust-repl#editable` 容器语法中
|
||||
如果需要在线编辑并执行,需要将代码块包裹在 `::: rust-repl editable` 容器语法中
|
||||
|
||||
````md
|
||||
::: rust-repl#editable 自定义标题
|
||||
::: rust-repl editable title="自定义标题"
|
||||
```rust
|
||||
// your rust code
|
||||
```
|
||||
@ -66,7 +66,7 @@ rust 代码演示默认是只读的,不可编辑。
|
||||
**输入:**
|
||||
|
||||
````md
|
||||
::: rust-repl 打印内容
|
||||
::: rust-repl title="打印内容"
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
@ -77,7 +77,7 @@ fn main() {
|
||||
|
||||
**输出:**
|
||||
|
||||
::: rust-repl 打印内容
|
||||
::: rust-repl title="打印内容"
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -156,7 +156,7 @@ fn main() {
|
||||
**输入:**
|
||||
|
||||
````md
|
||||
::: rust-repl#editable
|
||||
::: rust-repl editable
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
@ -167,7 +167,7 @@ fn main() {
|
||||
|
||||
**输出:**
|
||||
|
||||
::: rust-repl#editable
|
||||
::: rust-repl editable
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`artPlayerPlugin > should not work 1`] = `
|
||||
"<ArtPlayer src="" fullscreen flip playback-rate aspect-ratio setting pip :volume="0.75" width="100%"/><p>@[artPlayer]xxx</p>
|
||||
"<ArtPlayer src="" fullscreen flip playback-rate aspect-ratio setting pip :volume="0.75" width="100%"/><p>@[artPlayer]xxx</p>
|
||||
<p>@[ artPlayer]123456</p>
|
||||
<p>@<a href="/xxx.mp4"> artPlayer</a></p>
|
||||
<ArtPlayer src="/xxx.xxx" fullscreen flip playback-rate aspect-ratio setting pip type="xxx" :volume="0.75" width="100%"/>"
|
||||
<ArtPlayer src="/xxx.xxx" fullscreen flip playback-rate aspect-ratio setting pip type="xxx" :volume="0.75" width="100%"/>"
|
||||
`;
|
||||
|
||||
exports[`artPlayerPlugin > should work 1`] = `"<ArtPlayer src="/xxx.mp4" fullscreen flip playback-rate aspect-ratio setting pip :volume="0.75" width="100%"/><ArtPlayer src="/xxx.m3u8" fullscreen flip playback-rate aspect-ratio setting pip loop autoplay muted :volume="0.75" width="100%"/><ArtPlayer src="/xxx.flv" fullscreen flip playback-rate aspect-ratio setting pip autoplay muted :volume="0.55" width="100%"/><ArtPlayer src="/xxx.mpd" fullscreen flip playback-rate aspect-ratio setting pip auto-min poster="xx.jpg" :volume="0.75" width="100%" height="600px" ratio="16:9"/><ArtPlayer src="/xxx" fullscreen flip playback-rate aspect-ratio setting pip type="mp3" :volume="0.75" width="100%"/>"`;
|
||||
exports[`artPlayerPlugin > should work 1`] = `"<ArtPlayer src="/xxx.mp4" fullscreen flip playback-rate aspect-ratio setting pip :volume="0.75" width="100%"/><ArtPlayer src="/xxx.m3u8" fullscreen flip playback-rate aspect-ratio setting pip autoplay muted loop :volume="0.75" width="100%"/><ArtPlayer src="/xxx.flv" fullscreen flip playback-rate aspect-ratio setting pip autoplay muted :volume="0.55" width="100%"/><ArtPlayer src="/xxx.mpd" fullscreen flip playback-rate aspect-ratio setting pip auto-mini :volume="0.75" poster="xx.jpg" width="100%" height="600px" ratio="16:9"/><ArtPlayer src="/xxx" fullscreen flip playback-rate aspect-ratio setting pip type="mp3" :volume="0.75" width="100%"/>"`;
|
||||
|
||||
@ -12,9 +12,9 @@ exports[`artPlayerPlugin > should not work 1`] = `
|
||||
`;
|
||||
|
||||
exports[`artPlayerPlugin > should work 1`] = `
|
||||
"<p><AudioReader src="/xxx.mp3"></AudioReader> <AudioReader src="/xxx.mp3"></AudioReader></p>
|
||||
<p><AudioReader src="/xxx.mp3">title</AudioReader></p>
|
||||
<p><AudioReader src="/xxx.mp3" :start-time="0" :end-time="99" :volume="0.55"></AudioReader></p>
|
||||
<p>xxx <AudioReader src="/xxx.mp3" type="audio/mp3"></AudioReader> xxx</p>
|
||||
"<p><AudioReader src="/xxx.mp3" /> <AudioReader src="/xxx.mp3" /></p>
|
||||
<p><AudioReader src="/xxx.mp3" autoplay title="title" /></p>
|
||||
<p><AudioReader src="/xxx.mp3" autoplay :start-time="0" :end-time="99" :volume="0.55" /></p>
|
||||
<p>xxx <AudioReader src="/xxx.mp3" type="audio/mp3" /> xxx</p>
|
||||
"
|
||||
`;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`bilibiliPlugin > should not work 1`] = `
|
||||
"<VideoBilibili src="https://player.bilibili.com/player.html?autoplay=0&high_quality=1" width="100%" height="" ratio="" title="undefined" /><p>@[bilibili]xxx</p>
|
||||
"<VideoBilibili src="https://player.bilibili.com/player.html?autoplay=0&high_quality=1" width="100%" /><p>@[bilibili]xxx</p>
|
||||
<p>@[ bilibili]BV12345</p>
|
||||
<p>@[bilibili](BV12345</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`bilibiliPlugin > should work 1`] = `"<VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&autoplay=0&high_quality=1" width="100%" height="" ratio="" title="undefined" /><VideoBilibili src="https://player.bilibili.com/player.html?aid=12432&cid=12345&autoplay=0&high_quality=1" width="100%" height="" ratio="" title="undefined" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&aid=12343&cid=45678&autoplay=0&high_quality=1" width="100%" height="" ratio="" title="undefined" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&t=1&autoplay=1&high_quality=1" width="100%" height="" ratio="" title="undefined" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&autoplay=1&high_quality=1" width="100%" height="600px" ratio="" title="undefined" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&autoplay=1&high_quality=1" width="100%" height="" ratio="16:9" title="undefined" />"`;
|
||||
exports[`bilibiliPlugin > should work 1`] = `"<VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&autoplay=0&high_quality=1" width="100%" /><VideoBilibili src="https://player.bilibili.com/player.html?aid=12432&cid=12345&autoplay=0&high_quality=1" width="100%" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&aid=12343&cid=45678&autoplay=0&high_quality=1" width="100%" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&t=1&autoplay=1&high_quality=1" width="100%" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&autoplay=1&high_quality=1" width="100%" height="600px" /><VideoBilibili src="https://player.bilibili.com/player.html?bvid=BV12345&p=1&autoplay=1&high_quality=1" width="100%" ratio="16:9" />"`;
|
||||
|
||||
@ -37,7 +37,7 @@ exports[`caniusePlugin > should not work 8`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`caniusePlugin > should work 1`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="1" />"`;
|
||||
exports[`caniusePlugin > should work 1`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="1" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work 2`] = `
|
||||
"<ClientOnly><p><picture>
|
||||
@ -47,13 +47,13 @@ exports[`caniusePlugin > should work 2`] = `
|
||||
</picture></p></ClientOnly>"
|
||||
`;
|
||||
|
||||
exports[`caniusePlugin > should work 3`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="1" />"`;
|
||||
exports[`caniusePlugin > should work 3`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="1" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work 4`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="0" />"`;
|
||||
exports[`caniusePlugin > should work 4`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="0" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work 5`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="0" /><CanIUseViewer feature="feature" meta="test-id" past="2" future="0" />"`;
|
||||
exports[`caniusePlugin > should work 5`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="0" /><CanIUseViewer feature="feature" meta="test-id" :past="2" :future="0" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work 6`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="0" />"`;
|
||||
exports[`caniusePlugin > should work 6`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="0" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work with options 1`] = `
|
||||
"<ClientOnly><p><picture>
|
||||
@ -63,13 +63,13 @@ exports[`caniusePlugin > should work with options 1`] = `
|
||||
</picture></p></ClientOnly>"
|
||||
`;
|
||||
|
||||
exports[`caniusePlugin > should work with options 2`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="1" />"`;
|
||||
exports[`caniusePlugin > should work with options 2`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="1" />"`;
|
||||
|
||||
exports[`caniusePlugin > should work with options 3`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="0" />"`;
|
||||
exports[`caniusePlugin > should work with options 3`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="0" />"`;
|
||||
|
||||
exports[`legacyCaniuse > should work 1`] = `"<CanIUseViewer feature="feature" meta="test-id" past="2" future="1" />"`;
|
||||
exports[`legacyCaniuse > should work 1`] = `"<CanIUseViewer feature="feature" meta="test-id" :past="2" :future="1" />"`;
|
||||
|
||||
exports[`legacyCaniuse > should work 2`] = `"<CanIUseViewer feature="feature{-2,4}" meta="test-id" past="2" future="0" />"`;
|
||||
exports[`legacyCaniuse > should work 2`] = `"<CanIUseViewer feature="feature{-2,4}" meta="test-id" :past="2" :future="0" />"`;
|
||||
|
||||
exports[`legacyCaniuse > should work 3`] = `""`;
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`codeSandboxPlugin > should not work 1`] = `
|
||||
"<CodeSandboxViewer title="" height="500px" width="100%" user="" id="" type="embed" filepath="" :console=false :navbar=true layout="" /><p>@[codesandbox]xxx</p>
|
||||
"<CodeSandboxViewer width="100%" height="500px" user="" id="" title="" navbar layout="" type="embed" filepath="" /><p>@[codesandbox]xxx</p>
|
||||
<p>@[codesandbox embed](</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`codeSandboxPlugin > should work 1`] = `"<CodeSandboxViewer title="" height="500px" width="100%" user="user" id="id" type="embed" filepath="" :console=false :navbar=true layout="" /><CodeSandboxViewer title="" height="500px" width="100%" user="user" id="id" type="embed" filepath="" :console=false :navbar=true layout="" /><CodeSandboxViewer title="" height="500px" width="100%" user="user" id="id" type="button" filepath="" :console=false :navbar=true layout="" /><CodeSandboxViewer title="xxx" height="500px" width="100%" user="user" id="slash" type="embed" filepath="filepath" :console=false :navbar=false layout="Editor+Preview" />"`;
|
||||
exports[`codeSandboxPlugin > should work 1`] = `"<CodeSandboxViewer width="100%" height="500px" user="user" id="id" title="" navbar layout="" type="embed" filepath="" /><CodeSandboxViewer width="100%" height="500px" user="user" id="id" title="" navbar layout="" type="embed" filepath="" /><CodeSandboxViewer width="100%" height="500px" user="user" id="id" title="" navbar layout="" type="button" filepath="" /><CodeSandboxViewer width="100%" height="500px" user="user" id="slash" title="xxx" layout="Editor+Preview" type="embed" filepath="filepath" />"`;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`codepenPlugin > should not work 1`] = `
|
||||
"<CodePenViewer user="" slash="undefined" title="Code Pen" tab="result" width="100%" height="400px" /><p>@[codepen]xxx</p>
|
||||
"<CodePenViewer title="Code Pen" tab="result" width="100%" height="400px" user="" /><p>@[codepen]xxx</p>
|
||||
<p>@[codepen preview](</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`codepenPlugin > should work 1`] = `"<CodePenViewer user="user" slash="slash" title="Code Pen" tab="result" width="100%" height="400px" /><CodePenViewer user="user" slash="slash" title="Code Pen" preview tab="result" width="100%" height="400px" /><CodePenViewer user="user" slash="slash" title="codepen" preview editable tab="css,result" theme="dark" width="100%" height="400px" />"`;
|
||||
exports[`codepenPlugin > should work 1`] = `"<CodePenViewer title="Code Pen" tab="result" width="100%" height="400px" user="user" slash="slash" /><CodePenViewer title="Code Pen" tab="result" width="100%" height="400px" user="user" slash="slash" preview /><CodePenViewer title="codepen" tab="css,result" width="100%" height="400px" user="user" slash="slash" preview editable theme="dark" />"`;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`codeSandboxPlugin > should not work 1`] = `
|
||||
"<JSFiddleViewer source="" title="JS Fiddle" tab="js,css,html,result" width="100%" height="400px" /><p>@[jsfiddle]xxx</p>
|
||||
"<JSFiddleViewer width="100%" height="400px" source="" title="JS Fiddle" tab="js,css,html,result" /><p>@[jsfiddle]xxx</p>
|
||||
<p>@[jsfiddle](</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`codeSandboxPlugin > should work 1`] = `"<JSFiddleViewer source="user/id" title="JS Fiddle" tab="js,css,html,result" width="100%" height="400px" /><JSFiddleViewer source="user/id" title="JS Fiddle" tab="js,css,html,result" width="100%" height="400px" /><JSFiddleViewer source="user/id" title="JS Fiddle" tab="js,css,html,result" width="100%" height="400px" theme="light" /><JSFiddleViewer source="user/id" title="xxx" tab="js,css,html,result" width="100%" height="500px" theme="dark" />"`;
|
||||
exports[`codeSandboxPlugin > should work 1`] = `"<JSFiddleViewer width="100%" height="400px" source="user/id" title="JS Fiddle" tab="js,css,html,result" /><JSFiddleViewer width="100%" height="400px" source="user/id" title="JS Fiddle" tab="js,css,html,result" /><JSFiddleViewer width="100%" height="400px" source="user/id" title="JS Fiddle" tab="js,css,html,result" theme="light" /><JSFiddleViewer width="100%" height="500px" source="user/id" title="xxx" tab="js,css,html,result" theme="dark" />"`;
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`langReplPlugin > should work with custom options 1`] = `
|
||||
"<CodeRepl title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
"<CodeRepl title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title=" title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl editable title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl>"
|
||||
`;
|
||||
@ -45,21 +45,21 @@ exports[`langReplPlugin > should work with custom options 2`] = `
|
||||
`;
|
||||
|
||||
exports[`langReplPlugin > should work with custom theme 1`] = `
|
||||
"<CodeRepl title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
"<CodeRepl title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="go playground"><pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="kotlin playground"><pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title="rust playground"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl><CodeRepl editable title=" title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</CodeRepl><CodeRepl editable title="title"><pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
</CodeRepl>"
|
||||
`;
|
||||
@ -85,7 +85,7 @@ exports[`langReplPlugin > should work with default options 1`] = `
|
||||
<pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
<p>::: go-repl#editable</p>
|
||||
<p>::: go-repl editable</p>
|
||||
<pre><code class="language-go"><div class="language-go"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
@ -93,7 +93,7 @@ exports[`langReplPlugin > should work with default options 1`] = `
|
||||
<pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
<p>::: kotlin-repl#editable</p>
|
||||
<p>::: kotlin-repl editable</p>
|
||||
<pre><code class="language-kotlin"><div class="language-kotlin"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
@ -101,15 +101,15 @@ exports[`langReplPlugin > should work with default options 1`] = `
|
||||
<pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
<p>::: rust-repl#editable</p>
|
||||
<p>::: rust-repl editable</p>
|
||||
<pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
<p>::: rust-repl title</p>
|
||||
<p>::: rust-repl title="title"</p>
|
||||
<pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
<p>::: rust-repl#editable title</p>
|
||||
<p>::: rust-repl editable title="title"</p>
|
||||
<pre><code class="language-rust"><div class="language-rust"><pre><code>const a = 1
|
||||
</code></pre></div></code></pre>
|
||||
<p>:::</p>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`pdfPlugin > should not work 1`] = `
|
||||
"<PDFViewer src="" title="" :page="1" :no-toolbar="false" width="100%" height="" ratio="" :zoom="50" /><p>@[pdf]xxx</p>
|
||||
"<PDFViewer src="" :page="1" :zoom="50" width="100%" height="" ratio="" title="" /><p>@[pdf]xxx</p>
|
||||
<p>@<a href=""> pdf</a></p>
|
||||
<p>@[pdf]</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`pdfPlugin > should work 1`] = `"<PDFViewer src="foo.pdf" title="foo.pdf" :page="1" :no-toolbar="false" width="100%" height="" ratio="" :zoom="50" />"`;
|
||||
exports[`pdfPlugin > should work 1`] = `"<PDFViewer src="foo.pdf" :page="1" :zoom="50" width="100%" height="" ratio="" title="foo.pdf" />"`;
|
||||
|
||||
exports[`pdfPlugin > should work 2`] = `"<PDFViewer src="foo.pdf" title="foo.pdf" :page="1" :no-toolbar="false" width="100%" height="" ratio="" :zoom="50" /><PDFViewer src="foo.pdf" title="foo.pdf" :page="1" :no-toolbar="true" width="100%" height="" ratio="" :zoom="50" /><PDFViewer src="foo.pdf" title="foo.pdf" :page="2" :no-toolbar="false" width="100%" height="" ratio="" :zoom="50" /><PDFViewer src="foo.pdf" title="foo.pdf" :page="2" :no-toolbar="true" width="100%" height="" ratio="" :zoom="50" /><PDFViewer src="foo.pdf" title="foo.pdf" :page="2" :no-toolbar="true" width="100%" height="600px" ratio="" :zoom="1" /><PDFViewer src="foo.pdf" title="foo.pdf" :page="2" :no-toolbar="true" width="100%" height="" ratio="1:1" :zoom="1" />"`;
|
||||
exports[`pdfPlugin > should work 2`] = `"<PDFViewer src="foo.pdf" :page="1" :zoom="50" width="100%" height="" ratio="" title="foo.pdf" /><PDFViewer src="foo.pdf" :page="1" no-toolbar :zoom="50" width="100%" height="" ratio="" title="foo.pdf" /><PDFViewer src="foo.pdf" :page="2" :zoom="50" width="100%" height="" ratio="" title="foo.pdf" /><PDFViewer src="foo.pdf" :page="2" no-toolbar :zoom="50" width="100%" height="" ratio="" title="foo.pdf" /><PDFViewer src="foo.pdf" :page="2" no-toolbar :zoom="1" width="100%" height="600px" ratio="" title="foo.pdf" /><PDFViewer src="foo.pdf" :page="2" no-toolbar :zoom="1" width="100%" height="" ratio="1:1" title="foo.pdf" />"`;
|
||||
|
||||
@ -4,7 +4,7 @@ exports[`timeline > timelinePlugin() > should work 1`] = `
|
||||
"<VPTimeline :card="undefined"><VPTimelineItem :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem :card="undefined"><template #title>这是标题
|
||||
这也是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline horizontal card line="dashed"><VPTimelineItem time="q1" :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline horizontal line="dashed" card><VPTimelineItem time="q1" :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
@ -16,9 +16,9 @@ exports[`timeline > timelinePlugin() > should work 1`] = `
|
||||
</li>
|
||||
</ul>
|
||||
</VPTimelineItem><VPTimelineItem time="q2" color="red"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="right"><VPTimelineItem type="warning" icon="xxx" card><template #icon><VPIcon name="xxx"/></template><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline placement="right" :card="undefined"><VPTimelineItem icon="xxx" card type="warning"><template #icon><VPIcon name="xxx"/></template><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem type="danger" line="dotted" :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="between"><VPTimelineItem card placement="right"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline placement="between" :card="undefined"><VPTimelineItem card placement="right"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem card placement="left"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline>"
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`youtubePlugin > should not work 1`] = `
|
||||
"<VideoYoutube src="https://www.youtube.com/embed//?" width="100%" height="" ratio="" title="undefined" /><p>@[youtube]xxx</p>
|
||||
"<VideoYoutube src="https://www.youtube.com/embed//?" width="100%" /><p>@[youtube]xxx</p>
|
||||
<p>@[ youtube]123456</p>
|
||||
<p>@<a href="123456"> youtube</a></p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`youtubePlugin > should work 1`] = `"<VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" height="" ratio="" title="undefined" /><VideoYoutube src="https://www.youtube.com/embed//123456?autoplay=1&loop=1" width="100%" height="" ratio="" title="test" /><VideoYoutube src="https://www.youtube.com/embed//123456?autoplay=1&start=40&end=80" width="100%" height="" ratio="" title="undefined" /><VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" height="600px" ratio="" title="undefined" /><VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" height="" ratio="16:9" title="undefined" />"`;
|
||||
exports[`youtubePlugin > should work 1`] = `"<VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" /><VideoYoutube src="https://www.youtube.com/embed//123456?autoplay=1&loop=1" width="100%" title="test" /><VideoYoutube src="https://www.youtube.com/embed//123456?autoplay=1&start=40&end=80" width="100%" /><VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" height="600px" /><VideoYoutube src="https://www.youtube.com/embed//123456?" width="100%" ratio="16:9" />"`;
|
||||
|
||||
@ -59,7 +59,7 @@ const a = 1
|
||||
${FENCE}
|
||||
:::
|
||||
|
||||
::: go-repl#editable
|
||||
::: go-repl editable
|
||||
${FENCE}go
|
||||
const a = 1
|
||||
${FENCE}
|
||||
@ -71,7 +71,7 @@ const a = 1
|
||||
${FENCE}
|
||||
:::
|
||||
|
||||
::: kotlin-repl#editable
|
||||
::: kotlin-repl editable
|
||||
${FENCE}kotlin
|
||||
const a = 1
|
||||
${FENCE}
|
||||
@ -83,19 +83,19 @@ const a = 1
|
||||
${FENCE}
|
||||
:::
|
||||
|
||||
::: rust-repl#editable
|
||||
::: rust-repl editable
|
||||
${FENCE}rust
|
||||
const a = 1
|
||||
${FENCE}
|
||||
:::
|
||||
|
||||
::: rust-repl title
|
||||
::: rust-repl title="title"
|
||||
${FENCE}rust
|
||||
const a = 1
|
||||
${FENCE}
|
||||
:::
|
||||
|
||||
::: rust-repl#editable title
|
||||
::: rust-repl editable title="title"
|
||||
${FENCE}rust
|
||||
const a = 1
|
||||
${FENCE}
|
||||
|
||||
@ -3,9 +3,9 @@ import { resolveAttrs } from '../src/node/utils/resolveAttrs.js'
|
||||
|
||||
describe('resolveAttrs(info)', () => {
|
||||
it('should resolve attrs', () => {
|
||||
expect(resolveAttrs('')).toMatchObject({ rawAttrs: '', attrs: {} })
|
||||
expect(resolveAttrs('')).toEqual({ rawAttrs: '', attrs: {} })
|
||||
|
||||
expect(resolveAttrs('a="1"')).toMatchObject({
|
||||
expect(resolveAttrs('a="1"')).toEqual({
|
||||
rawAttrs: 'a="1"',
|
||||
attrs: { a: '1' },
|
||||
})
|
||||
@ -15,21 +15,21 @@ describe('resolveAttrs(info)', () => {
|
||||
attrs: { a: '1', b: '2' },
|
||||
})
|
||||
|
||||
expect(resolveAttrs('a="1" b="2" c')).toMatchObject({
|
||||
expect(resolveAttrs('a="1" b="2" c')).toEqual({
|
||||
rawAttrs: 'a="1" b="2" c',
|
||||
attrs: { a: '1', b: '2', c: true },
|
||||
})
|
||||
|
||||
expect(resolveAttrs('a b="true" c="false"')).toMatchObject({
|
||||
expect(resolveAttrs('a b="true" c="false"')).toEqual({
|
||||
rawAttrs: 'a b="true" c="false"',
|
||||
attrs: { a: true, b: true, c: false },
|
||||
})
|
||||
})
|
||||
|
||||
it('should resolve attrs with include `-`', () => {
|
||||
expect(resolveAttrs('foo-bar="1" fizz-buzz')).toMatchObject({
|
||||
expect(resolveAttrs('foo-bar="1" fizz-buzz')).toEqual({
|
||||
rawAttrs: 'foo-bar="1" fizz-buzz',
|
||||
attrs: { 'fooBar': '1', 'fizzBuzz': true, 'foo-bar': '1', 'fizz-buzz': true },
|
||||
attrs: { fooBar: '1', fizzBuzz: true },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
47
plugins/plugin-md-power/__test__/stringifyAttrs.spec.ts
Normal file
47
plugins/plugin-md-power/__test__/stringifyAttrs.spec.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { stringifyAttrs } from '../src/node/utils/stringifyAttrs.js'
|
||||
|
||||
describe('stringifyAttrs', () => {
|
||||
it('should handle empty attributes', () => {
|
||||
expect(stringifyAttrs({})).toBe('')
|
||||
})
|
||||
|
||||
it('should handle single attribute', () => {
|
||||
expect(stringifyAttrs({ id: 'test' })).toBe(' id="test"')
|
||||
})
|
||||
|
||||
it('should handle multiple attributes', () => {
|
||||
expect(stringifyAttrs({ id: 'test', class: 'my-class' })).toBe(' id="test" class="my-class"')
|
||||
})
|
||||
|
||||
it('should handle boolean attributes', () => {
|
||||
expect(stringifyAttrs({ disabled: true, readonly: false, checked: 'true', selected: 'false' })).toBe(' disabled checked')
|
||||
})
|
||||
|
||||
it('should handle null and undefined values', () => {
|
||||
expect(stringifyAttrs({ id: null, class: undefined })).toBe('')
|
||||
expect(stringifyAttrs({ id: null, class: undefined, foo: 'undefined', bar: 'null' }, true)).toBe(' :id="null" :class="undefined" :foo="undefined" :bar="null"')
|
||||
})
|
||||
|
||||
it('should handle mixed attribute types', () => {
|
||||
expect(stringifyAttrs({ id: 'test', disabled: true, title: 'hello' })).toBe(' id="test" disabled title="hello"')
|
||||
})
|
||||
|
||||
it('should ignore prototype properties', () => {
|
||||
const attrs = Object.create({ prototypeProp: 'value' })
|
||||
attrs.id = 'test'
|
||||
expect(stringifyAttrs(attrs)).toBe(' id="test"')
|
||||
})
|
||||
|
||||
it('should handle number attributes', () => {
|
||||
expect(stringifyAttrs({ id: 1, class: 2 })).toBe(' :id="1" :class="2"')
|
||||
})
|
||||
|
||||
it('should handle like json string values', () => {
|
||||
expect(stringifyAttrs({ id: '{ "foo": "bar", baz: 1 }', class: '["a", "b"]' })).toBe(' :id="{ \'foo\': \'bar\', baz: 1 }" :class="[\'a\', \'b\']"')
|
||||
})
|
||||
|
||||
it('should handle kebabCase keys', () => {
|
||||
expect(stringifyAttrs({ 'data-foo': 'bar', 'data-baz': 1, 'fooBaz': 'bar' })).toBe(' data-foo="bar" :data-baz="1" foo-baz="bar"')
|
||||
})
|
||||
})
|
||||
@ -14,12 +14,12 @@ interface MessageData {
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
feature: string
|
||||
past?: string
|
||||
future?: string
|
||||
past?: number
|
||||
future?: number
|
||||
meta?: string
|
||||
}>(), {
|
||||
past: '2',
|
||||
future: '1',
|
||||
past: 2,
|
||||
future: 1,
|
||||
meta: '',
|
||||
})
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import { resolveAttrs } from '.././utils/resolveAttrs.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
interface CardAttrs {
|
||||
@ -21,8 +22,7 @@ export function cardPlugin(md: Markdown) {
|
||||
createContainerPlugin(md, 'card', {
|
||||
before(info) {
|
||||
const { attrs } = resolveAttrs<CardAttrs>(info)
|
||||
const { title, icon } = attrs
|
||||
return `<VPCard${title ? ` title="${title}"` : ''}${icon ? ` icon="${icon}"` : ''}>`
|
||||
return `<VPCard${stringifyAttrs(attrs)}>`
|
||||
},
|
||||
after: () => '</VPCard>',
|
||||
})
|
||||
@ -55,13 +55,12 @@ export function cardPlugin(md: Markdown) {
|
||||
createContainerPlugin(md, 'card-masonry', {
|
||||
before: (info) => {
|
||||
const { attrs } = resolveAttrs<CardMasonryAttrs>(info)
|
||||
let cols!: string | number
|
||||
if (attrs.cols) {
|
||||
cols = attrs.cols[0] === '{' ? attrs.cols : Number.parseInt(`${attrs.cols}`)
|
||||
}
|
||||
const gap = Number.parseInt(`${attrs.gap}`)
|
||||
if (attrs.cols)
|
||||
attrs.cols = attrs.cols[0] === '{' ? attrs.cols : Number.parseInt(`${attrs.cols}`)
|
||||
if (attrs.gap)
|
||||
attrs.gap = Number(attrs.gap)
|
||||
|
||||
return `<VPCardMasonry${cols ? ` :cols="${cols}"` : ''}${gap >= 0 ? ` :gap="${gap}"` : ''}>`
|
||||
return `<VPCardMasonry${stringifyAttrs(attrs)}>`
|
||||
},
|
||||
after: () => '</VPCardMasonry>',
|
||||
})
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
*/
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import { resolveAttrs } from '.././utils/resolveAttrs.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
interface CollapseMeta {
|
||||
@ -28,14 +29,14 @@ export function collapsePlugin(md: Markdown): void {
|
||||
const idx = parseCollapse(tokens, index, attrs)
|
||||
const { accordion } = attrs
|
||||
|
||||
return `<VPCollapse${accordion ? ' accordion' : ''}${idx !== undefined ? ` :index="${idx}"` : ''}>`
|
||||
return `<VPCollapse${stringifyAttrs({ accordion, index: idx })}>`
|
||||
},
|
||||
after: () => `</VPCollapse>`,
|
||||
})
|
||||
md.renderer.rules.collapse_item_open = (tokens, idx) => {
|
||||
const token = tokens[idx]
|
||||
const { expand, index } = token.meta as CollapseItemMeta
|
||||
return `<VPCollapseItem${expand ? ' expand' : ''}${` :index="${index}"`}>`
|
||||
return `<VPCollapseItem${stringifyAttrs({ expand, index })}>`
|
||||
}
|
||||
md.renderer.rules.collapse_item_close = () => '</VPCollapseItem>'
|
||||
md.renderer.rules.collapse_item_title_open = () => '<template #title>'
|
||||
|
||||
@ -18,10 +18,10 @@ export function createContainerPlugin(
|
||||
const token = tokens[index]
|
||||
const info = token.info.trim().slice(type.length).trim() || ''
|
||||
if (token.nesting === 1) {
|
||||
return before?.(info, tokens, index, options, env) || `<div class="custom-container ${type}">`
|
||||
return before?.(info, tokens, index, options, env) ?? `<div class="custom-container ${type}">`
|
||||
}
|
||||
else {
|
||||
return after?.(info, tokens, index, options, env) || '</div>'
|
||||
return after?.(info, tokens, index, options, env) ?? '</div>'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,32 +1,16 @@
|
||||
import type markdownIt from 'markdown-it'
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { App } from 'vuepress/core'
|
||||
import type { ReplEditorData, ReplOptions } from '../../shared/index.js'
|
||||
import { promises as fs } from 'node:fs'
|
||||
import { resolveModule } from 'local-pkg'
|
||||
import container from 'markdown-it-container'
|
||||
import { colors, logger, path } from 'vuepress/utils'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
const RE_INFO = /^(#editable)?(.*)$/
|
||||
|
||||
function createReplContainer(md: markdownIt, lang: string) {
|
||||
const type = `${lang}-repl`
|
||||
const validate = (info: string): boolean => info.trim().startsWith(type)
|
||||
|
||||
const render = (tokens: Token[], index: number): string => {
|
||||
const token = tokens[index]
|
||||
const info = token.info.trim().slice(type.length).trim() || ''
|
||||
// :::lang-repl#editable title
|
||||
const [, editable, title] = info.match(RE_INFO)!
|
||||
|
||||
if (token.nesting === 1)
|
||||
return `<CodeRepl ${editable ? 'editable' : ''} title="${title || `${lang} playground`}">`
|
||||
|
||||
else
|
||||
return '</CodeRepl>'
|
||||
}
|
||||
|
||||
md.use(container, type, { validate, render })
|
||||
interface CodeReplMeta {
|
||||
editable?: boolean
|
||||
title?: string
|
||||
}
|
||||
|
||||
export async function langReplPlugin(app: App, md: markdownIt, {
|
||||
@ -35,15 +19,24 @@ export async function langReplPlugin(app: App, md: markdownIt, {
|
||||
kotlin = false,
|
||||
rust = false,
|
||||
}: ReplOptions) {
|
||||
if (kotlin) {
|
||||
createReplContainer(md, 'kotlin')
|
||||
}
|
||||
if (go) {
|
||||
createReplContainer(md, 'go')
|
||||
}
|
||||
if (rust) {
|
||||
createReplContainer(md, 'rust')
|
||||
}
|
||||
const container = (lang: string): void => createContainerPlugin(md, `${lang}-repl`, {
|
||||
before(info) {
|
||||
const { attrs } = resolveAttrs<CodeReplMeta>(info)
|
||||
const { editable, title } = attrs
|
||||
return `<CodeRepl${stringifyAttrs({ editable, title: title || `${lang} playground` })}>`
|
||||
},
|
||||
after: () => '</CodeRepl>',
|
||||
})
|
||||
|
||||
if (kotlin)
|
||||
container('kotlin')
|
||||
|
||||
if (go)
|
||||
container('go')
|
||||
|
||||
if (rust)
|
||||
container('rust')
|
||||
|
||||
theme ??= { light: 'github-light', dark: 'github-dark' }
|
||||
|
||||
const data: ReplEditorData = { grammars: {} } as ReplEditorData
|
||||
|
||||
@ -22,198 +22,41 @@
|
||||
* ```
|
||||
* :::
|
||||
*/
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { Markdown, MarkdownEnv } from 'vuepress/markdown'
|
||||
import type { NpmToOptions, NpmToPackageManager } from '../../shared/index.js'
|
||||
import type { CommandConfig, CommandConfigItem } from './npmToPreset.js'
|
||||
import { isArray } from '@vuepress/helper'
|
||||
import container from 'markdown-it-container'
|
||||
import { colors } from 'vuepress/utils'
|
||||
import { cleanMarkdownEnv } from '../utils/cleanMarkdownEnv.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
|
||||
type PackageCommand = 'install' | 'add' | 'remove' | 'run' | 'create' | 'init' | 'npx' | 'ci'
|
||||
interface CommandConfigItem {
|
||||
cli: string
|
||||
flags?: Record<string, string>
|
||||
}
|
||||
type CommandConfig = Record<Exclude<NpmToPackageManager, 'npm'>, CommandConfigItem | false>
|
||||
type CommandConfigs = Record<PackageCommand, { pattern: RegExp } & CommandConfig>
|
||||
|
||||
const ALLOW_LIST = ['npm', 'pnpm', 'yarn', 'bun', 'deno'] as const
|
||||
const BOOL_FLAGS: string[] = ['--no-save', '-B', '--save-bundle', '--save-dev', '-D', '--save-prod', '-P', '--save-peer', '-O', '--save-optional', '-E', '--save-exact', '-y', '--yes', '-g', '--global']
|
||||
|
||||
const DEFAULT_TABS: NpmToPackageManager[] = ['npm', 'pnpm', 'yarn']
|
||||
|
||||
const MANAGERS_CONFIG: CommandConfigs = {
|
||||
install: {
|
||||
pattern: /(?:^|\s)npm\s+(?:install|i)$/,
|
||||
pnpm: { cli: 'pnpm install' },
|
||||
yarn: { cli: 'yarn' },
|
||||
bun: { cli: 'bun install' },
|
||||
deno: { cli: 'deno install' },
|
||||
},
|
||||
add: {
|
||||
pattern: /(?:^|\s)npm\s+(?:install|i|add)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm add',
|
||||
flags: {
|
||||
'--no-save': '', // unsupported
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn add',
|
||||
flags: {
|
||||
'--save-dev': '--dev',
|
||||
'--save-prod': '--prod',
|
||||
'-P': '', // in npm, `-P` same as `--save-prod`. but in yarn, `-P` same as `--peer`
|
||||
'--save-peer': '--peer',
|
||||
'--save-optional': '--optional',
|
||||
'--no-save': '', // unsupported
|
||||
'--save-exact': '--exact',
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun add',
|
||||
flags: {
|
||||
'--save-dev': '--development',
|
||||
'-P': '', // it's default
|
||||
'--save-prod': '', // it's default
|
||||
'--save-peer': '', // unsupported
|
||||
'-O': '--optional',
|
||||
'--save-optional': '--optional',
|
||||
'--no-save': '', // unsupported
|
||||
'--save-exact': '--exact',
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno add',
|
||||
flags: {
|
||||
'-g': '', // unsupported
|
||||
'--global': '', // unsupported
|
||||
'--save-dev': '--dev',
|
||||
'-P': '', // unsupported
|
||||
'--save-prod': '', // unsupported
|
||||
'--save-peer': '', // unsupported
|
||||
'-O': '', // unsupported
|
||||
'--save-optional': '', // unsupported
|
||||
'--no-save': '', // unsupported
|
||||
'-E': '', // unsupported
|
||||
'--save-exact': '', // unsupported
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
},
|
||||
run: {
|
||||
pattern: /(?:^|\s)npm\s+(?:run|run-script|rum|urn)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm',
|
||||
flags: {
|
||||
'-w': '-F', // same as `--workspace`
|
||||
'--workspace': '--filter', // filter by workspaces
|
||||
'--': '', // scripts flags
|
||||
},
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn',
|
||||
flags: {
|
||||
'-w': '', // unsupported
|
||||
'--workspace': '', // unsupported
|
||||
},
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun run',
|
||||
flags: {
|
||||
'-w': '--filter', // same as `--workspace`
|
||||
'--workspace': '--filter', // filter by workspaces
|
||||
},
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno run',
|
||||
flags: {
|
||||
'-w': '', // unsupported
|
||||
'--workspace': '', // unsupported
|
||||
},
|
||||
},
|
||||
},
|
||||
create: {
|
||||
pattern: /(?:^|\s)npm\s+create\s/,
|
||||
pnpm: { cli: 'pnpm create', flags: { '-y': '', '--yes': '' } },
|
||||
yarn: { cli: 'yarn create', flags: { '-y': '', '--yes': '' } },
|
||||
bun: { cli: 'bun create', flags: { '-y': '', '--yes': '' } },
|
||||
deno: { cli: 'deno run -A ', flags: { '-y': '', '--yes': '' } },
|
||||
},
|
||||
init: {
|
||||
pattern: /(?:^|\s)npm\s+init/,
|
||||
pnpm: { cli: 'pnpm init', flags: { '-y': '', '--yes': '' } },
|
||||
yarn: { cli: 'yarn init', flags: { '-y': '', '--yes': '' } },
|
||||
bun: { cli: 'bun init', flags: { '-y': '', '--yes': '' } },
|
||||
deno: { cli: 'deno init', flags: { '-y': '', '--yes': '' } },
|
||||
},
|
||||
npx: {
|
||||
pattern: /(?:^|\s)npx\s+/,
|
||||
pnpm: { cli: 'pnpm dlx' },
|
||||
yarn: { cli: 'yarn dlx' },
|
||||
bun: { cli: 'bunx' },
|
||||
deno: { cli: 'deno run -A' },
|
||||
},
|
||||
remove: {
|
||||
pattern: /(?:^|\s)npm\s+(?:uninstall|r|rm|remove|unlink|un)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm remove',
|
||||
flags: { '--no-save': '', '--save': '', '-S': '' },
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn remove',
|
||||
flags: { '--save-dev': '--dev', '--save': '', '-S': '', '-g': '', '--global': '' },
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun remove',
|
||||
flags: { '--save-dev': '--development', '--save': '', '-S': '', '-g': '', '--global': '' },
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno uninstall',
|
||||
flags: { '--save-dev': '--dev', '--save': '', '-S': '' },
|
||||
},
|
||||
},
|
||||
ci: {
|
||||
pattern: /(?:^|\s)npm\s+ci$/,
|
||||
pnpm: { cli: 'pnpm install --frozen-lockfile' },
|
||||
yarn: { cli: 'yarn install --immutable' },
|
||||
bun: { cli: 'bun install --frozen-lockfile' },
|
||||
deno: { cli: 'deno install --frozen' },
|
||||
},
|
||||
}
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
import { ALLOW_LIST, BOOL_FLAGS, DEFAULT_TABS, MANAGERS_CONFIG } from './npmToPreset.js'
|
||||
|
||||
export function npmToPlugins(md: Markdown, options: NpmToOptions = {}): void {
|
||||
const type = 'npm-to'
|
||||
|
||||
const opt = isArray(options) ? { tabs: options } : options
|
||||
const defaultTabs = opt.tabs?.length ? opt.tabs : DEFAULT_TABS
|
||||
|
||||
const render = (tokens: Token[], idx: number): string => {
|
||||
const { attrs } = resolveAttrs(tokens[idx].info.trim().slice(type.length))
|
||||
const tabs = (attrs.tabs ? attrs.tabs.split(/,\s*/) : defaultTabs) as NpmToPackageManager[]
|
||||
if (tokens[idx].nesting === 1) {
|
||||
createContainerPlugin(md, 'npm-to', {
|
||||
before: (info, tokens, idx, _opt, env: MarkdownEnv) => {
|
||||
const { attrs } = resolveAttrs<{ tabs?: string }>(info)
|
||||
const tabs = (attrs.tabs ? attrs.tabs.split(/,\s*/) : defaultTabs) as NpmToPackageManager[]
|
||||
const token = tokens[idx + 1]
|
||||
const info = token.info.trim()
|
||||
if (token.type === 'fence') {
|
||||
const content = token.content
|
||||
token.hidden = true
|
||||
token.type = 'text'
|
||||
token.content = ''
|
||||
const lines = content.split(/(\n|\s*&&\s*)/)
|
||||
return md.render(resolveNpmTo(lines, info, idx, tabs), {})
|
||||
return md.render(
|
||||
resolveNpmTo(lines, token.info.trim(), idx, tabs),
|
||||
cleanMarkdownEnv(env),
|
||||
)
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
md.use(container, type, { render })
|
||||
console.warn(`${colors.yellow('[vuepress-plugin-md-power]')} Invalid npm-to container in ${colors.gray(env.filePathRelative || env.filePath)}`)
|
||||
return ''
|
||||
},
|
||||
after: () => '',
|
||||
})
|
||||
}
|
||||
|
||||
function resolveNpmTo(lines: string[], info: string, idx: number, tabs: NpmToPackageManager[]): string {
|
||||
@ -279,6 +122,7 @@ interface LineParsed {
|
||||
}
|
||||
|
||||
const LINE_REG = /(.*)(npm|npx)\s+(.*)/
|
||||
|
||||
export function parseLine(line: string): false | LineParsed {
|
||||
const match = line.match(LINE_REG)
|
||||
if (!match)
|
||||
|
||||
165
plugins/plugin-md-power/src/node/container/npmToPreset.ts
Normal file
165
plugins/plugin-md-power/src/node/container/npmToPreset.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import type { NpmToPackageManager } from '../../shared/index.js'
|
||||
|
||||
export type PackageCommand = 'install' | 'add' | 'remove' | 'run' | 'create' | 'init' | 'npx' | 'ci'
|
||||
|
||||
export interface CommandConfigItem {
|
||||
cli: string
|
||||
flags?: Record<string, string>
|
||||
}
|
||||
|
||||
export type CommandConfig = Record<Exclude<NpmToPackageManager, 'npm'>, CommandConfigItem | false>
|
||||
|
||||
export type CommandConfigs = Record<PackageCommand, { pattern: RegExp } & CommandConfig>
|
||||
|
||||
export const ALLOW_LIST = ['npm', 'pnpm', 'yarn', 'bun', 'deno'] as const
|
||||
|
||||
export const BOOL_FLAGS: string[] = ['--no-save', '-B', '--save-bundle', '--save-dev', '-D', '--save-prod', '-P', '--save-peer', '-O', '--save-optional', '-E', '--save-exact', '-y', '--yes', '-g', '--global']
|
||||
|
||||
export const DEFAULT_TABS: NpmToPackageManager[] = ['npm', 'pnpm', 'yarn']
|
||||
|
||||
export const MANAGERS_CONFIG: CommandConfigs = {
|
||||
install: {
|
||||
pattern: /(?:^|\s)npm\s+(?:install|i)$/,
|
||||
pnpm: { cli: 'pnpm install' },
|
||||
yarn: { cli: 'yarn' },
|
||||
bun: { cli: 'bun install' },
|
||||
deno: { cli: 'deno install' },
|
||||
},
|
||||
add: {
|
||||
pattern: /(?:^|\s)npm\s+(?:install|i|add)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm add',
|
||||
flags: {
|
||||
'--no-save': '', // unsupported
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn add',
|
||||
flags: {
|
||||
'--save-dev': '--dev',
|
||||
'--save-prod': '--prod',
|
||||
'-P': '', // in npm, `-P` same as `--save-prod`. but in yarn, `-P` same as `--peer`
|
||||
'--save-peer': '--peer',
|
||||
'--save-optional': '--optional',
|
||||
'--no-save': '', // unsupported
|
||||
'--save-exact': '--exact',
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun add',
|
||||
flags: {
|
||||
'--save-dev': '--development',
|
||||
'-P': '', // it's default
|
||||
'--save-prod': '', // it's default
|
||||
'--save-peer': '', // unsupported
|
||||
'-O': '--optional',
|
||||
'--save-optional': '--optional',
|
||||
'--no-save': '', // unsupported
|
||||
'--save-exact': '--exact',
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno add',
|
||||
flags: {
|
||||
'-g': '', // unsupported
|
||||
'--global': '', // unsupported
|
||||
'--save-dev': '--dev',
|
||||
'-P': '', // unsupported
|
||||
'--save-prod': '', // unsupported
|
||||
'--save-peer': '', // unsupported
|
||||
'-O': '', // unsupported
|
||||
'--save-optional': '', // unsupported
|
||||
'--no-save': '', // unsupported
|
||||
'-E': '', // unsupported
|
||||
'--save-exact': '', // unsupported
|
||||
'-B': '', // unsupported
|
||||
'--save-bundle': '', // unsupported
|
||||
},
|
||||
},
|
||||
},
|
||||
run: {
|
||||
pattern: /(?:^|\s)npm\s+(?:run|run-script|rum|urn)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm',
|
||||
flags: {
|
||||
'-w': '-F', // same as `--workspace`
|
||||
'--workspace': '--filter', // filter by workspaces
|
||||
'--': '', // scripts flags
|
||||
},
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn',
|
||||
flags: {
|
||||
'-w': '', // unsupported
|
||||
'--workspace': '', // unsupported
|
||||
},
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun run',
|
||||
flags: {
|
||||
'-w': '--filter', // same as `--workspace`
|
||||
'--workspace': '--filter', // filter by workspaces
|
||||
},
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno run',
|
||||
flags: {
|
||||
'-w': '', // unsupported
|
||||
'--workspace': '', // unsupported
|
||||
},
|
||||
},
|
||||
},
|
||||
create: {
|
||||
pattern: /(?:^|\s)npm\s+create\s/,
|
||||
pnpm: { cli: 'pnpm create', flags: { '-y': '', '--yes': '' } },
|
||||
yarn: { cli: 'yarn create', flags: { '-y': '', '--yes': '' } },
|
||||
bun: { cli: 'bun create', flags: { '-y': '', '--yes': '' } },
|
||||
deno: { cli: 'deno run -A ', flags: { '-y': '', '--yes': '' } },
|
||||
},
|
||||
init: {
|
||||
pattern: /(?:^|\s)npm\s+init/,
|
||||
pnpm: { cli: 'pnpm init', flags: { '-y': '', '--yes': '' } },
|
||||
yarn: { cli: 'yarn init', flags: { '-y': '', '--yes': '' } },
|
||||
bun: { cli: 'bun init', flags: { '-y': '', '--yes': '' } },
|
||||
deno: { cli: 'deno init', flags: { '-y': '', '--yes': '' } },
|
||||
},
|
||||
npx: {
|
||||
pattern: /(?:^|\s)npx\s+/,
|
||||
pnpm: { cli: 'pnpm dlx' },
|
||||
yarn: { cli: 'yarn dlx' },
|
||||
bun: { cli: 'bunx' },
|
||||
deno: { cli: 'deno run -A' },
|
||||
},
|
||||
remove: {
|
||||
pattern: /(?:^|\s)npm\s+(?:uninstall|r|rm|remove|unlink|un)(?:\s|$)/,
|
||||
pnpm: {
|
||||
cli: 'pnpm remove',
|
||||
flags: { '--no-save': '', '--save': '', '-S': '' },
|
||||
},
|
||||
yarn: {
|
||||
cli: 'yarn remove',
|
||||
flags: { '--save-dev': '--dev', '--save': '', '-S': '', '-g': '', '--global': '' },
|
||||
},
|
||||
bun: {
|
||||
cli: 'bun remove',
|
||||
flags: { '--save-dev': '--development', '--save': '', '-S': '', '-g': '', '--global': '' },
|
||||
},
|
||||
deno: {
|
||||
cli: 'deno uninstall',
|
||||
flags: { '--save-dev': '--dev', '--save': '', '-S': '' },
|
||||
},
|
||||
},
|
||||
ci: {
|
||||
pattern: /(?:^|\s)npm\s+ci$/,
|
||||
pnpm: { cli: 'pnpm install --frozen-lockfile' },
|
||||
yarn: { cli: 'yarn install --immutable' },
|
||||
bun: { cli: 'bun install --frozen-lockfile' },
|
||||
deno: { cli: 'deno install --frozen' },
|
||||
},
|
||||
}
|
||||
@ -16,6 +16,7 @@ import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import { isEmptyObject } from '@pengzhanbo/utils'
|
||||
import { resolveAttrs } from '.././utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
export interface TimelineAttrs {
|
||||
@ -45,36 +46,18 @@ export function timelinePlugin(md: Markdown) {
|
||||
parseTimeline(tokens, index)
|
||||
|
||||
const { attrs } = resolveAttrs<TimelineAttrs>(info)
|
||||
const { horizontal, card, placement, line } = attrs
|
||||
return `<VPTimeline${
|
||||
horizontal ? ' horizontal' : ''
|
||||
}${
|
||||
card ? ' card' : ' :card="undefined"'
|
||||
}${
|
||||
placement ? ` placement="${placement}"` : ''
|
||||
}${
|
||||
line ? ` line="${line}"` : ''
|
||||
}>`
|
||||
attrs.card ??= undefined
|
||||
return `<VPTimeline${stringifyAttrs(attrs, true)}>`
|
||||
},
|
||||
after: () => '</VPTimeline>',
|
||||
})
|
||||
|
||||
md.renderer.rules.timeline_item_open = (tokens, idx) => {
|
||||
const token = tokens[idx]
|
||||
const { time, type, icon, color, line, card, placement } = token.meta as TimelineItemMeta
|
||||
return `<VPTimelineItem${
|
||||
time ? ` time="${time}"` : ''
|
||||
}${
|
||||
type ? ` type="${type}"` : ''
|
||||
}${
|
||||
color ? ` color="${color}"` : ''
|
||||
}${
|
||||
line ? ` line="${line}"` : ''
|
||||
}${icon ? ` icon="${icon}"` : ''}${
|
||||
card === 'true' ? ' card' : card === 'false' ? '' : ' :card="undefined"'
|
||||
}${
|
||||
placement ? ` placement="${placement}"` : ''
|
||||
}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ''}`
|
||||
const attrs = token.meta as TimelineItemMeta
|
||||
attrs.card ??= undefined
|
||||
const icon = attrs.icon
|
||||
return `<VPTimelineItem${stringifyAttrs(attrs, true)}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ''}`
|
||||
}
|
||||
|
||||
md.renderer.rules.timeline_item_close = () => '</VPTimelineItem>'
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { App } from 'vuepress'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { DemoContainerRender, DemoFile, DemoMeta, MarkdownDemoEnv } from '../../shared/demo.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { findFile, readFileSync } from './supports/file.js'
|
||||
|
||||
export function markdownEmbed(
|
||||
@ -23,19 +24,19 @@ export function markdownEmbed(
|
||||
env.demoFiles.push(demo)
|
||||
}
|
||||
|
||||
return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>
|
||||
return `<VPDemoBasic${stringifyAttrs({ type: 'markdown', title, desc, expanded })}>
|
||||
${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
|
||||
<template #code>
|
||||
${md.render(`\`\`\`md ${codeSetting}\n${code}\n\`\`\``, {})}
|
||||
</template>
|
||||
</VPDemoBasic>`
|
||||
</VPDemoBasic$>`
|
||||
}
|
||||
|
||||
export const markdownContainerRender: DemoContainerRender = {
|
||||
before(app, md, env, meta, codeMap) {
|
||||
const { title, desc, expanded = false } = meta
|
||||
const code = codeMap.md || ''
|
||||
return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>
|
||||
return `<VPDemoBasic${stringifyAttrs({ type: 'markdown', title, desc, expanded })}>
|
||||
${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
|
||||
<template #code>`
|
||||
},
|
||||
|
||||
@ -3,6 +3,7 @@ import type { Markdown } from 'vuepress/markdown'
|
||||
import type { DemoContainerRender, DemoFile, DemoMeta, MarkdownDemoEnv } from '../../shared/demo.js'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { compileScript, compileStyle } from './supports/compiler.js'
|
||||
import { findFile, readFileSync, writeFileSync } from './supports/file.js'
|
||||
import { insertSetupScript } from './supports/insertScript.js'
|
||||
@ -126,9 +127,9 @@ export function normalEmbed(
|
||||
insertSetupScript({ ...demo, path: output }, env)
|
||||
}
|
||||
|
||||
return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>
|
||||
return `<VPDemoNormal${stringifyAttrs({ config: name, title, desc, expanded })}>
|
||||
${codeToHtml(md, source, codeSetting)}
|
||||
</VPDemoNormal>`
|
||||
</VPDemoNormal$>`
|
||||
}
|
||||
|
||||
export const normalContainerRender: DemoContainerRender = {
|
||||
@ -148,7 +149,7 @@ export const normalContainerRender: DemoContainerRender = {
|
||||
const source = parseContainerCode(codeMap)
|
||||
compileCode(source, output)
|
||||
|
||||
return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>`
|
||||
return `<VPDemoNormal${stringifyAttrs({ config: name, title, desc, expanded })}>`
|
||||
},
|
||||
|
||||
after: () => '</VPDemoNormal>',
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
# demo 嵌入
|
||||
|
||||
demo 目前主要聚焦于实现 vue component demo,不考虑其他场景。
|
||||
|
||||
此功能提供两种方式来嵌入 demo。
|
||||
|
||||
方式一 嵌入语法:
|
||||
|
||||
@[demo vue](/xxx.vue)
|
||||
|
||||
方式二 容器语法:
|
||||
|
||||
::: demo vue
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>1</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
``
|
||||
:::
|
||||
@ -2,6 +2,7 @@ import type { App } from 'vuepress'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { DemoContainerRender, DemoFile, DemoMeta, MarkdownDemoEnv } from '../../shared/demo.js'
|
||||
import path from 'node:path'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { findFile, readFileSync, writeFileSync } from './supports/file.js'
|
||||
import { insertSetupScript } from './supports/insertScript.js'
|
||||
|
||||
@ -30,12 +31,12 @@ export function vueEmbed(
|
||||
insertSetupScript(demo, env)
|
||||
}
|
||||
|
||||
return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>
|
||||
return `<VPDemoBasic${stringifyAttrs({ type: 'vue', title, desc, expanded })}>
|
||||
<${name} />
|
||||
<template #code>
|
||||
${md.render(`\`\`\`${ext}${codeSetting}\n${code}\n\`\`\``, {})}
|
||||
</template>
|
||||
</VPDemoBasic>`
|
||||
</VPDemoBasic$>`
|
||||
}
|
||||
|
||||
const target = 'md-power/demo/vue'
|
||||
@ -101,7 +102,7 @@ export const vueContainerRender: DemoContainerRender = {
|
||||
}
|
||||
}
|
||||
|
||||
return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ''}${desc ? ` desc="${desc}"` : ''}${expanded ? ' expanded' : ''}>
|
||||
return `<VPDemoBasic${stringifyAttrs({ type: 'vue', title, desc, expanded })}>
|
||||
<${componentName} />
|
||||
<template #code>\n`
|
||||
},
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { RuleInline } from 'markdown-it/lib/parser_inline.mjs'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
|
||||
interface AudioReaderTokenMeta {
|
||||
src?: string
|
||||
startTime?: number
|
||||
endTime?: number
|
||||
type?: string
|
||||
volume?: number
|
||||
title?: string
|
||||
}
|
||||
|
||||
const audioReader: RuleInline = (state, silent) => {
|
||||
const max = state.posMax
|
||||
@ -52,28 +62,11 @@ const audioReader: RuleInline = (state, silent) => {
|
||||
state.pos = labelStart
|
||||
state.posMax = labelEnd
|
||||
const info = state.src.slice(labelStart, labelEnd).trim()
|
||||
const { attrs } = resolveAttrs(info)
|
||||
const { attrs } = resolveAttrs<AudioReaderTokenMeta>(info)
|
||||
|
||||
const tokenOpen = state.push('audio_reader_open', 'AudioReader', 1)
|
||||
tokenOpen.info = info
|
||||
tokenOpen.attrs = [['src', href]]
|
||||
|
||||
if (attrs.startTime)
|
||||
tokenOpen.attrs.push([':start-time', attrs.startTime])
|
||||
|
||||
if (attrs.endTime)
|
||||
tokenOpen.attrs.push([':end-time', attrs.endTime])
|
||||
|
||||
if (attrs.type)
|
||||
tokenOpen.attrs.push(['type', attrs.type])
|
||||
|
||||
if (attrs.volume)
|
||||
tokenOpen.attrs.push([':volume', attrs.volume])
|
||||
|
||||
if (attrs.title)
|
||||
state.push('text', '', 0).content = attrs.title
|
||||
|
||||
state.push('audio_reader_close', 'AudioReader', -1)
|
||||
const token = state.push('audio_reader', 'AudioReader', 0)
|
||||
token.info = info
|
||||
token.meta = { src: href, ...attrs } as AudioReaderTokenMeta
|
||||
}
|
||||
|
||||
state.pos = pos + 1
|
||||
@ -81,5 +74,20 @@ const audioReader: RuleInline = (state, silent) => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const audioReaderPlugin: PluginWithOptions<never> = md =>
|
||||
export const audioReaderPlugin: PluginWithOptions<never> = (md) => {
|
||||
md.renderer.rules.audio_reader = (tokens, idx) => {
|
||||
const meta = (tokens[idx].meta ?? {}) as AudioReaderTokenMeta
|
||||
if (meta.startTime)
|
||||
meta.startTime = Number(meta.startTime)
|
||||
|
||||
if (meta.endTime)
|
||||
meta.endTime = Number(meta.endTime)
|
||||
|
||||
if (meta.volume)
|
||||
meta.volume = Number(meta.volume)
|
||||
|
||||
return `<AudioReader${stringifyAttrs(meta)} />`
|
||||
}
|
||||
|
||||
md.inline.ruler.before('link', 'audio-reader', audioReader)
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
*/
|
||||
import type { PluginWithOptions } from 'markdown-it'
|
||||
import type MarkdownIt from 'markdown-it'
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { CanIUseMode, CanIUseOptions, CanIUseTokenMeta } from '../../shared/index.js'
|
||||
import container from 'markdown-it-container'
|
||||
import { createContainerPlugin } from '../container/createContainer.js'
|
||||
import { nanoid } from '../utils/nanoid.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from './createEmbedRuleBlock.js'
|
||||
|
||||
const UNDERLINE_RE = /_+/g
|
||||
@ -51,27 +51,14 @@ export function legacyCaniuse(
|
||||
const isMode = (mode: CanIUseMode): boolean => modeMap.includes(mode)
|
||||
|
||||
mode = isMode(mode) ? mode : modeMap[0]
|
||||
const type = 'caniuse'
|
||||
const validateReg = new RegExp(`^${type}`)
|
||||
|
||||
const validate = (info: string): boolean => {
|
||||
return validateReg.test(info.trim())
|
||||
}
|
||||
|
||||
const render = (tokens: Token[], index: number): string => {
|
||||
const token = tokens[index]
|
||||
if (token.nesting === 1) {
|
||||
const info = token.info.trim().slice(type.length).trim() || ''
|
||||
createContainerPlugin(md, 'caniuse', {
|
||||
before: (info) => {
|
||||
const feature = info.split(/\s+/)[0]
|
||||
const versions = info.match(/\{(.*)\}/)?.[1] || ''
|
||||
return feature ? resolveCanIUse({ feature, mode, versions }) : ''
|
||||
}
|
||||
else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
md.use(container, type, { validate, render })
|
||||
},
|
||||
after: () => '',
|
||||
})
|
||||
}
|
||||
|
||||
function resolveCanIUse({ feature, mode, versions }: CanIUseTokenMeta): string {
|
||||
@ -92,7 +79,7 @@ function resolveCanIUse({ feature, mode, versions }: CanIUseTokenMeta): string {
|
||||
const { past, future } = resolveVersions(versions)
|
||||
const meta = nanoid()
|
||||
|
||||
return `<CanIUseViewer feature="${feature}" meta="${meta}" past="${past}" future="${future}" />`
|
||||
return `<CanIUseViewer${stringifyAttrs({ feature, meta, past, future })} />`
|
||||
}
|
||||
|
||||
function resolveVersions(versions: string): { past: number, future: number } {
|
||||
|
||||
@ -7,6 +7,7 @@ import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { CodeSandboxTokenMeta } from '../../../shared/index.js'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
export const codeSandboxPlugin: PluginWithOptions<never> = (md) => {
|
||||
@ -31,8 +32,6 @@ export const codeSandboxPlugin: PluginWithOptions<never> = (md) => {
|
||||
filepath,
|
||||
}
|
||||
},
|
||||
content({ title, height, width, user, id, type, filepath, console, navbar, layout }) {
|
||||
return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type}" filepath="${filepath}" :console=${console} :navbar=${navbar} layout="${layout}" />`
|
||||
},
|
||||
content: meta => `<CodeSandboxViewer${stringifyAttrs(meta)} />`,
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { CodepenTokenMeta } from '../../../shared/index.js'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
export const codepenPlugin: PluginWithOptions<never> = (md) => {
|
||||
@ -14,20 +15,21 @@ export const codepenPlugin: PluginWithOptions<never> = (md) => {
|
||||
type: 'codepen',
|
||||
syntaxPattern: /^@\[codepen([^\]]*)\]\(([^)]*)\)/,
|
||||
meta: ([, info, source]) => {
|
||||
const { width, height, title, tab, ...rest } = resolveAttrs<CodepenTokenMeta>(info).attrs
|
||||
const { width, height, title, tab, preview, editable, theme } = resolveAttrs<CodepenTokenMeta>(info).attrs
|
||||
const [user, slash] = source.split('/')
|
||||
|
||||
return {
|
||||
title: title || 'Code Pen',
|
||||
tab: tab || 'result',
|
||||
width: width ? parseRect(width) : '100%',
|
||||
height: height ? parseRect(height) : '400px',
|
||||
user,
|
||||
slash,
|
||||
title: title || 'Code Pen',
|
||||
tab: tab || 'result',
|
||||
...rest,
|
||||
preview,
|
||||
editable,
|
||||
theme,
|
||||
}
|
||||
},
|
||||
content: ({ title, height, width, user, slash, preview, editable, tab, theme }) =>
|
||||
`<CodePenViewer user="${user}" slash="${slash}" title="${title}"${preview ? ' preview' : ''}${editable ? ' editable' : ''} tab="${tab}"${theme ? ` theme="${theme}"` : ''} width="${width}" height="${height}" />`,
|
||||
content: meta => `<CodePenViewer${stringifyAttrs(meta)} />`,
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { JSFiddleTokenMeta } from '../../../shared/index.js'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
export const jsfiddlePlugin: PluginWithOptions<never> = (md) => {
|
||||
@ -24,7 +25,6 @@ export const jsfiddlePlugin: PluginWithOptions<never> = (md) => {
|
||||
theme,
|
||||
}
|
||||
},
|
||||
content: ({ title, height, width, source, tab, theme }) =>
|
||||
`<JSFiddleViewer source="${source}" title="${title}" tab="${tab}" width="${width}" height="${height}"${theme ? ` theme="${theme}"` : ''} />`,
|
||||
content: meta => `<JSFiddleViewer${stringifyAttrs(meta)} />`,
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { ReplitTokenMeta } from '../../../shared/index.js'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
export const replitPlugin: PluginWithOptions<never> = (md) => {
|
||||
@ -23,8 +24,6 @@ export const replitPlugin: PluginWithOptions<never> = (md) => {
|
||||
theme: attrs.theme || '',
|
||||
}
|
||||
},
|
||||
content({ title, height, width, source, theme }) {
|
||||
return `<ReplitViewer title="${title || ''}" height="${height}" width="${width}" source="${source}" theme="${theme}" />`
|
||||
},
|
||||
content: meta => `<ReplitViewer${stringifyAttrs(meta)} />`,
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import type { PDFTokenMeta } from '../../shared/index.js'
|
||||
import { path } from 'vuepress/utils'
|
||||
import { parseRect } from '../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from './createEmbedRuleBlock.js'
|
||||
|
||||
export const pdfPlugin: PluginWithOptions<never> = (md) => {
|
||||
@ -28,8 +29,6 @@ export const pdfPlugin: PluginWithOptions<never> = (md) => {
|
||||
title: path.basename(src || ''),
|
||||
}
|
||||
},
|
||||
content({ title, src, page, noToolbar, width, height, ratio, zoom }) {
|
||||
return `<PDFViewer src="${src}" title="${title}" :page="${page}" :no-toolbar="${noToolbar}" width="${width}" height="${height}" ratio="${ratio}" :zoom="${zoom}" />`
|
||||
},
|
||||
content: meta => `<PDFViewer${stringifyAttrs(meta)} />`,
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { isPackageExists } from 'local-pkg'
|
||||
import { colors } from 'vuepress/utils'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
const installed = {
|
||||
@ -29,6 +30,8 @@ export const artPlayerPlugin: PluginWithOptions<never> = (md) => {
|
||||
checkSupportType(attrs.type ?? url.split('.').pop())
|
||||
|
||||
return {
|
||||
url,
|
||||
type: attrs.type,
|
||||
autoplay: attrs.autoplay ?? false,
|
||||
muted: attrs.muted ?? attrs.autoplay ?? false,
|
||||
autoMini: attrs.autoMini ?? false,
|
||||
@ -36,28 +39,13 @@ export const artPlayerPlugin: PluginWithOptions<never> = (md) => {
|
||||
volume: typeof attrs.volume !== 'undefined' ? Number(attrs.volume) : 0.75,
|
||||
poster: attrs.poster,
|
||||
width: attrs.width ? parseRect(attrs.width) : '100%',
|
||||
height: attrs.height ? parseRect(attrs.height) : '',
|
||||
ratio: attrs.ratio ? parseRect(`${attrs.ratio}`) : '',
|
||||
type: attrs.type,
|
||||
url,
|
||||
height: attrs.height ? parseRect(attrs.height) : undefined,
|
||||
ratio: attrs.ratio ? parseRect(`${attrs.ratio}`) : undefined,
|
||||
}
|
||||
},
|
||||
content({ autoMini, autoplay, loop, muted, poster, url, type, volume, width, height, ratio }) {
|
||||
return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip ${
|
||||
loop ? ' loop' : ''
|
||||
}${
|
||||
type ? ` type="${type}"` : ''
|
||||
}${
|
||||
autoMini ? ' auto-min' : ''
|
||||
}${autoplay ? ' autoplay' : ''}${
|
||||
muted || autoplay ? ' muted' : ''
|
||||
}${
|
||||
poster ? ` poster="${poster}"` : ''
|
||||
} :volume="${volume}" width="${width}"${
|
||||
height ? ` height="${height}"` : ''
|
||||
}${
|
||||
ratio ? ` ratio="${ratio}"` : ''
|
||||
}/>`
|
||||
content({ url, ...meta }) {
|
||||
meta.muted = meta.muted || meta.autoplay
|
||||
return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip${stringifyAttrs(meta)}/>`
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import type { BilibiliTokenMeta } from '../../../shared/index.js'
|
||||
import { URLSearchParams } from 'node:url'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { timeToSeconds } from '../../utils/timeToSeconds.js'
|
||||
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
|
||||
|
||||
@ -35,39 +36,35 @@ export const bilibiliPlugin: PluginWithOptions<never> = (md) => {
|
||||
time: timeToSeconds(attrs.time),
|
||||
title: attrs.title,
|
||||
width: attrs.width ? parseRect(attrs.width) : '100%',
|
||||
height: attrs.height ? parseRect(attrs.height) : '',
|
||||
ratio: attrs.ratio ? parseRect(attrs.ratio) : '',
|
||||
height: attrs.height ? parseRect(attrs.height) : undefined,
|
||||
ratio: attrs.ratio ? parseRect(attrs.ratio) : undefined,
|
||||
}
|
||||
},
|
||||
content(meta) {
|
||||
const params = new URLSearchParams()
|
||||
|
||||
if (meta.bvid) {
|
||||
if (meta.bvid)
|
||||
params.set('bvid', meta.bvid)
|
||||
}
|
||||
|
||||
if (meta.aid) {
|
||||
if (meta.aid)
|
||||
params.set('aid', meta.aid)
|
||||
}
|
||||
|
||||
if (meta.cid) {
|
||||
if (meta.cid)
|
||||
params.set('cid', meta.cid)
|
||||
}
|
||||
|
||||
if (meta.page) {
|
||||
if (meta.page)
|
||||
params.set('p', meta.page.toString())
|
||||
}
|
||||
|
||||
if (meta.time) {
|
||||
if (meta.time)
|
||||
params.set('t', meta.time.toString())
|
||||
}
|
||||
|
||||
params.set('autoplay', meta.autoplay ? '1' : '0')
|
||||
params.set('high_quality', '1')
|
||||
|
||||
const source = `${BILIBILI_LINK}?${params.toString()}`
|
||||
const { width, height, ratio, title } = meta
|
||||
|
||||
return `<VideoBilibili src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`
|
||||
return `<VideoBilibili${stringifyAttrs({ src: source, width, height, ratio, title })} />`
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import type { YoutubeTokenMeta } from '../../../shared/index.js'
|
||||
import { URLSearchParams } from 'node:url'
|
||||
import { parseRect } from '../../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../../utils/resolveAttrs.js'
|
||||
import { stringifyAttrs } from '../../utils/stringifyAttrs.js'
|
||||
import { timeToSeconds } from '../../utils/timeToSeconds.js'
|
||||
import { createEmbedRuleBlock } from '..//createEmbedRuleBlock.js'
|
||||
|
||||
@ -27,32 +28,29 @@ export const youtubePlugin: PluginWithOptions<never> = (md) => {
|
||||
end: timeToSeconds(attrs.end),
|
||||
title: attrs.title,
|
||||
width: attrs.width ? parseRect(attrs.width) : '100%',
|
||||
height: attrs.height ? parseRect(attrs.height) : '',
|
||||
ratio: attrs.ratio ? parseRect(attrs.ratio) : '',
|
||||
height: attrs.height ? parseRect(attrs.height) : undefined,
|
||||
ratio: attrs.ratio ? parseRect(attrs.ratio) : undefined,
|
||||
}
|
||||
},
|
||||
content(meta) {
|
||||
const params = new URLSearchParams()
|
||||
|
||||
if (meta.autoplay) {
|
||||
if (meta.autoplay)
|
||||
params.set('autoplay', '1')
|
||||
}
|
||||
|
||||
if (meta.loop) {
|
||||
if (meta.loop)
|
||||
params.set('loop', '1')
|
||||
}
|
||||
|
||||
if (meta.start) {
|
||||
if (meta.start)
|
||||
params.set('start', meta.start.toString())
|
||||
}
|
||||
|
||||
if (meta.end) {
|
||||
if (meta.end)
|
||||
params.set('end', meta.end.toString())
|
||||
}
|
||||
|
||||
const source = `${YOUTUBE_LINK}/${meta.id}?${params.toString()}`
|
||||
const { width, height, ratio, title } = meta
|
||||
|
||||
return `<VideoYoutube src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`
|
||||
return `<VideoYoutube${stringifyAttrs({ src: source, width, height, ratio, title })} />`
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -167,7 +167,8 @@ export const annotationPlugin: PluginSimple = (md) => {
|
||||
data.sources.map((source, i) => {
|
||||
const annotation = data.rendered[i] ??= md.render(source, env)
|
||||
return `<template #item-${i}>${annotation}</template>`
|
||||
}).join('')}</Annotation>`
|
||||
}).join('')
|
||||
}</Annotation>`
|
||||
}
|
||||
|
||||
md.inline.ruler.before('image', 'annotation_ref', annotationRef)
|
||||
|
||||
@ -4,78 +4,76 @@
|
||||
import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { RuleInline } from 'markdown-it/lib/parser_inline.mjs'
|
||||
|
||||
export const plotPlugin: PluginWithOptions<never> = md =>
|
||||
md.inline.ruler.before('emphasis', 'plot', createTokenizer())
|
||||
const plotDef: RuleInline = (state, silent) => {
|
||||
let found = false
|
||||
const max = state.posMax
|
||||
const start = state.pos
|
||||
|
||||
function createTokenizer(): RuleInline {
|
||||
return (state, silent) => {
|
||||
let found = false
|
||||
const max = state.posMax
|
||||
const start = state.pos
|
||||
|
||||
if (
|
||||
state.src.charCodeAt(start) !== 0x21
|
||||
|| state.src.charCodeAt(start + 1) !== 0x21
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const next = state.src.charCodeAt(start + 2)
|
||||
|
||||
// - !! xxx | !!!xxx
|
||||
// ^ | ^
|
||||
if (next === 0x20 || next === 0x21)
|
||||
return false
|
||||
|
||||
/* istanbul ignore if -- @preserve */
|
||||
if (silent)
|
||||
return false
|
||||
|
||||
// - !!!!
|
||||
if (max - start < 5)
|
||||
return false
|
||||
|
||||
state.pos = start + 2
|
||||
|
||||
while (state.pos < max) {
|
||||
if (state.src.charCodeAt(state.pos) === 0x21
|
||||
&& state.src.charCodeAt(state.pos + 1) === 0x21) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
state.md.inline.skipToken(state)
|
||||
}
|
||||
|
||||
if (
|
||||
!found
|
||||
|| start + 2 === state.pos
|
||||
// - !!xxx !!
|
||||
// ^
|
||||
|| state.src.charCodeAt(state.pos - 1) === 0x20
|
||||
) {
|
||||
state.pos = start
|
||||
|
||||
return false
|
||||
}
|
||||
const content = state.src.slice(start + 2, state.pos)
|
||||
|
||||
// found!
|
||||
state.posMax = state.pos
|
||||
state.pos = start + 2
|
||||
|
||||
const open = state.push('plot_open', 'Plot', 1)
|
||||
open.markup = '!!'
|
||||
|
||||
const text = state.push('text', '', 0)
|
||||
text.content = content
|
||||
|
||||
const close = state.push('plot_close', 'Plot', -1)
|
||||
close.markup = '!!'
|
||||
|
||||
state.pos = state.posMax + 2
|
||||
state.posMax = max
|
||||
|
||||
return true
|
||||
if (
|
||||
state.src.charCodeAt(start) !== 0x21
|
||||
|| state.src.charCodeAt(start + 1) !== 0x21
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const next = state.src.charCodeAt(start + 2)
|
||||
|
||||
// - !! xxx | !!!xxx
|
||||
// ^ | ^
|
||||
if (next === 0x20 || next === 0x21)
|
||||
return false
|
||||
|
||||
/* istanbul ignore if -- @preserve */
|
||||
if (silent)
|
||||
return false
|
||||
|
||||
// - !!!!
|
||||
if (max - start < 5)
|
||||
return false
|
||||
|
||||
state.pos = start + 2
|
||||
|
||||
while (state.pos < max) {
|
||||
if (state.src.charCodeAt(state.pos) === 0x21
|
||||
&& state.src.charCodeAt(state.pos + 1) === 0x21) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
state.md.inline.skipToken(state)
|
||||
}
|
||||
|
||||
if (
|
||||
!found
|
||||
|| start + 2 === state.pos
|
||||
// - !!xxx !!
|
||||
// ^
|
||||
|| state.src.charCodeAt(state.pos - 1) === 0x20
|
||||
) {
|
||||
state.pos = start
|
||||
|
||||
return false
|
||||
}
|
||||
const content = state.src.slice(start + 2, state.pos)
|
||||
|
||||
// found!
|
||||
state.posMax = state.pos
|
||||
state.pos = start + 2
|
||||
|
||||
const token = state.push('plot_inline', 'Plot', 0)
|
||||
token.markup = '!!'
|
||||
token.content = content
|
||||
|
||||
state.pos = state.posMax + 2
|
||||
state.posMax = max
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const plotPlugin: PluginWithOptions<never> = (md) => {
|
||||
md.renderer.rules.plot_inline = (tokens, idx) => {
|
||||
const token = tokens[idx]
|
||||
return `<Plot>${token.content}</Plot>`
|
||||
}
|
||||
md.inline.ruler.before('emphasis', 'plot', plotDef)
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { camelCase } from '@pengzhanbo/utils'
|
||||
|
||||
const RE_ATTR_VALUE = /(?:^|\s+)(?<attr>[\w-]+)(?:=\s*(?<quote>['"])(?<value>.+?)\k<quote>)?(?:\s+|$)/
|
||||
|
||||
export function resolveAttrs<T extends Record<string, any> = Record<string, any>>(info: string): {
|
||||
@ -16,26 +18,16 @@ export function resolveAttrs<T extends Record<string, any> = Record<string, any>
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (matched = info.match(RE_ATTR_VALUE)) {
|
||||
const { attr, value } = matched.groups!
|
||||
attrs[attr] = value ?? true
|
||||
const { attr, value = true } = matched.groups!
|
||||
let v = typeof value === 'string' ? value.trim() : value
|
||||
if (v === 'true')
|
||||
v = true
|
||||
else if (v === 'false')
|
||||
v = false
|
||||
attrs[camelCase(attr)] = v
|
||||
|
||||
info = info.slice(matched[0].length)
|
||||
}
|
||||
|
||||
Object.keys(attrs).forEach((key) => {
|
||||
let value = attrs[key]
|
||||
value = typeof value === 'string' ? value.trim() : value
|
||||
if (value === 'true')
|
||||
value = true
|
||||
else if (value === 'false')
|
||||
value = false
|
||||
|
||||
attrs[key] = value
|
||||
|
||||
if (key.includes('-')) {
|
||||
const _key = key.replace(/-(\w)/g, (_, c) => c.toUpperCase())
|
||||
attrs[_key] = value
|
||||
}
|
||||
})
|
||||
|
||||
return { attrs: attrs as T, rawAttrs }
|
||||
}
|
||||
|
||||
37
plugins/plugin-md-power/src/node/utils/stringifyAttrs.ts
Normal file
37
plugins/plugin-md-power/src/node/utils/stringifyAttrs.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { isBoolean, isNull, isNumber, isString, isUndefined, kebabCase } from '@pengzhanbo/utils'
|
||||
|
||||
export function stringifyAttrs<T extends object = object>(
|
||||
attrs: T,
|
||||
withUndefined = false,
|
||||
): string {
|
||||
const result = Object.entries(attrs)
|
||||
.map(([key, value]) => {
|
||||
const k = kebabCase(String(key))
|
||||
if (isUndefined(value) || value === 'undefined')
|
||||
return withUndefined ? `:${k}="undefined"` : ''
|
||||
|
||||
if (isNull(value) || value === 'null')
|
||||
return withUndefined ? `:${k}="null"` : ''
|
||||
|
||||
if (value === 'true')
|
||||
value = true
|
||||
if (value === 'false')
|
||||
value = false
|
||||
|
||||
if (isBoolean(value))
|
||||
return value ? `${k}` : ''
|
||||
|
||||
if (isNumber(value))
|
||||
return `:${k}="${value}"`
|
||||
|
||||
// like object or array
|
||||
if (isString(value) && (value[0] === '{' || value[0] === '['))
|
||||
return `:${k}="${value.replaceAll('\"', '\'')}"`
|
||||
|
||||
return `${k}="${String(value)}"`
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
return result ? ` ${result}` : ''
|
||||
}
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -177,8 +177,8 @@ catalogs:
|
||||
specifier: ^0.16.0
|
||||
version: 0.16.0
|
||||
'@pengzhanbo/utils':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
'@vueuse/core':
|
||||
specifier: ^13.1.0
|
||||
version: 13.1.0
|
||||
@ -469,7 +469,7 @@ importers:
|
||||
version: 0.10.1
|
||||
'@pengzhanbo/utils':
|
||||
specifier: catalog:prod
|
||||
version: 2.0.0
|
||||
version: 2.1.0
|
||||
cac:
|
||||
specifier: catalog:prod
|
||||
version: 6.7.14
|
||||
@ -599,7 +599,7 @@ importers:
|
||||
version: 0.16.0(markdown-it@14.1.0)
|
||||
'@pengzhanbo/utils':
|
||||
specifier: catalog:prod
|
||||
version: 2.0.0
|
||||
version: 2.1.0
|
||||
'@vuepress/helper':
|
||||
specifier: catalog:vuepress
|
||||
version: 2.0.0-rc.94(typescript@5.8.3)(vuepress@2.0.0-rc.21(@vuepress/bundler-vite@2.0.0-rc.21(@types/node@22.14.1)(jiti@2.4.2)(less@4.3.0)(sass-embedded@1.86.3)(sass@1.86.3)(stylus@0.64.0)(typescript@5.8.3)(yaml@2.7.0))(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)))
|
||||
@ -732,7 +732,7 @@ importers:
|
||||
version: 4.3.0(vue@3.5.13(typescript@5.8.3))
|
||||
'@pengzhanbo/utils':
|
||||
specifier: catalog:prod
|
||||
version: 2.0.0
|
||||
version: 2.1.0
|
||||
'@vuepress-plume/plugin-fonts':
|
||||
specifier: workspace:*
|
||||
version: link:../plugins/plugin-fonts
|
||||
@ -1957,8 +1957,8 @@ packages:
|
||||
'@pengzhanbo/utils@1.2.0':
|
||||
resolution: {integrity: sha512-M3sN7SQs6PY/J9lB8U6meyUMhv8qs4iIOU/sG6QWRp4nm9ySM8nvX9GOJpo+RuVGcgcH3CO8qlQugBUa5qADSw==}
|
||||
|
||||
'@pengzhanbo/utils@2.0.0':
|
||||
resolution: {integrity: sha512-CGMZYQm4TSvaKxFKJ2JMUxz/GjiHPquf6T18Pr/hVMhzatAdwyfleqOMcUaVy/dxLXpE4Lp6ONY2H4rgylWyNg==}
|
||||
'@pengzhanbo/utils@2.1.0':
|
||||
resolution: {integrity: sha512-mdcNoYZ6S9EhRqAIpjnD2dcFxaP7E9JdMrP2z5uXuEesddNcmQ4GvEs/wcyxKmFXqeFdL88fJu7l8a6hNN4zPQ==}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
@ -8273,7 +8273,7 @@ snapshots:
|
||||
|
||||
'@pengzhanbo/utils@1.2.0': {}
|
||||
|
||||
'@pengzhanbo/utils@2.0.0': {}
|
||||
'@pengzhanbo/utils@2.1.0': {}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
@ -75,7 +75,7 @@ catalogs:
|
||||
'@mdit/plugin-sup': ^0.16.0
|
||||
'@mdit/plugin-tab': ^0.16.0
|
||||
'@mdit/plugin-tasklist': ^0.16.0
|
||||
'@pengzhanbo/utils': ^2.0.0
|
||||
'@pengzhanbo/utils': ^2.1.0
|
||||
'@vueuse/core': ^13.1.0
|
||||
'@vueuse/integrations': ^13.1.0
|
||||
bcrypt-ts: ^6.0.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user