Skip to content

Commit 26ecff7

Browse files
znckulivz
authored andcommitted
feat: add support to import files as code fence (#538)
1 parent 9cb174d commit 26ecff7

9 files changed

+112
-0
lines changed

docs/guide/markdown.md

+12
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,18 @@ export default {
224224
}
225225
```
226226

227+
## Import Code Snippets
228+
229+
**Input**
230+
231+
```
232+
<<< @/test/markdown/fragments/snippet.js{2}
233+
```
234+
235+
**Output**
236+
237+
<<< @/test/markdown/fragments/snippet.js{2}
238+
227239
## Advanced Configuration
228240

229241
VuePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vuepress/config.js`:

lib/markdown/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const component = require('./component')
66
const hoistScriptStyle = require('./hoist')
77
const convertRouterLink = require('./link')
88
const containers = require('./containers')
9+
const snippet = require('./snippet')
910
const emoji = require('markdown-it-emoji')
1011
const anchor = require('markdown-it-anchor')
1112
const toc = require('markdown-it-table-of-contents')
@@ -24,6 +25,7 @@ module.exports = ({ markdown = {}} = {}) => {
2425
.use(component)
2526
.use(highlightLines)
2627
.use(preWrapper)
28+
.use(snippet)
2729
.use(convertRouterLink, Object.assign({
2830
target: '_blank',
2931
rel: 'noopener noreferrer'

lib/markdown/snippet.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const fs = require('fs')
2+
3+
module.exports = function snippet (md, options = {}) {
4+
const root = options.root || process.cwd()
5+
function parser (state, startLine, endLine, silent) {
6+
const CH = '<'.charCodeAt(0)
7+
const pos = state.bMarks[startLine] + state.tShift[startLine]
8+
const max = state.eMarks[startLine]
9+
10+
// if it's indented more than 3 spaces, it should be a code block
11+
if (state.sCount[startLine] - state.blkIndent >= 4) {
12+
return false
13+
}
14+
15+
for (let i = 0; i < 3; ++i) {
16+
const ch = state.src.charCodeAt(pos + i)
17+
if (ch !== CH || pos + i >= max) return false
18+
}
19+
20+
if (silent) {
21+
return true
22+
}
23+
24+
const start = pos + 3
25+
const end = state.skipSpacesBack(max, pos)
26+
const rawPath = state.src.slice(start, end).trim().replace(/^@/, root)
27+
const filename = rawPath.split(/[{:\s]/).shift()
28+
const content = fs.existsSync(filename) ? fs.readFileSync(filename).toString() : 'Not found: ' + filename
29+
const meta = rawPath.replace(filename, '')
30+
31+
state.line = startLine + 1
32+
33+
const token = state.push('fence', 'code', 0)
34+
token.info = filename.split('.').pop() + meta
35+
token.content = content
36+
token.markup = '```'
37+
token.map = [startLine, startLine + 1]
38+
39+
return true
40+
}
41+
42+
md.block.ruler.before('fence', 'snippet', parser)
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`snippet import snippet 1`] = `
4+
<pre><code class="language-js">export default function () {
5+
// ..
6+
}</code></pre>
7+
`;
8+
9+
exports[`snippet import snippet with highlight multiple lines 1`] = `
10+
<div class="highlight-lines">
11+
<div class="highlighted">&nbsp;</div>
12+
<div class="highlighted">&nbsp;</div>
13+
<div class="highlighted">&nbsp;</div>
14+
</div>export default function () { // .. }
15+
`;
16+
17+
exports[`snippet import snippet with highlight single line 1`] = `
18+
<div class="highlight-lines">
19+
<div class="highlighted">&nbsp;</div>
20+
<br>
21+
<div class="highlighted">&nbsp;</div>
22+
</div>export default function () { // .. }
23+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<<< @/test/markdown/fragments/snippet.js{1-3}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<<< @/test/markdown/fragments/snippet.js{1,3}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<<< @/test/markdown/fragments/snippet.js

test/markdown/fragments/snippet.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function () {
2+
// ..
3+
}

test/markdown/snippet.spec.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Md, getFragment } from './util'
2+
import snippet from '@/markdown/snippet.js'
3+
import highlightLines from '@/markdown/highlightLines.js'
4+
5+
const md = Md().use(snippet)
6+
const mdH = Md().use(snippet).use(highlightLines)
7+
8+
describe('snippet', () => {
9+
test('import snippet', async () => {
10+
const input = await getFragment('code-snippet')
11+
const output = md.render(input)
12+
expect(output).toMatchSnapshot()
13+
})
14+
15+
test('import snippet with highlight single line', async () => {
16+
const input = await getFragment('code-snippet-highlightLines-single')
17+
const output = mdH.render(input)
18+
expect(output).toMatchSnapshot()
19+
})
20+
21+
test('import snippet with highlight multiple lines', async () => {
22+
const input = await getFragment('code-snippet-highlightLines-multiple')
23+
const output = mdH.render(input)
24+
expect(output).toMatchSnapshot()
25+
})
26+
})

0 commit comments

Comments
 (0)