From 26ecff7d7a50c3dbe5b3a1577b8b7936ed163c36 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Sat, 2 Jun 2018 21:16:29 +0530 Subject: [PATCH] feat: add support to import files as code fence (#538) --- docs/guide/markdown.md | 12 ++++++ lib/markdown/index.js | 2 + lib/markdown/snippet.js | 43 +++++++++++++++++++ .../__snapshots__/snippet.spec.js.snap | 23 ++++++++++ .../code-snippet-highlightLines-multiple.md | 1 + .../code-snippet-highlightLines-single.md | 1 + test/markdown/fragments/code-snippet.md | 1 + test/markdown/fragments/snippet.js | 3 ++ test/markdown/snippet.spec.js | 26 +++++++++++ 9 files changed, 112 insertions(+) create mode 100644 lib/markdown/snippet.js create mode 100644 test/markdown/__snapshots__/snippet.spec.js.snap create mode 100644 test/markdown/fragments/code-snippet-highlightLines-multiple.md create mode 100644 test/markdown/fragments/code-snippet-highlightLines-single.md create mode 100644 test/markdown/fragments/code-snippet.md create mode 100644 test/markdown/fragments/snippet.js create mode 100644 test/markdown/snippet.spec.js diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md index 7741d77b97..98513bd585 100644 --- a/docs/guide/markdown.md +++ b/docs/guide/markdown.md @@ -224,6 +224,18 @@ export default { } ``` +## Import Code Snippets + +**Input** + +``` +<<< @/test/markdown/fragments/snippet.js{2} +``` + +**Output** + +<<< @/test/markdown/fragments/snippet.js{2} + ## Advanced Configuration 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`: diff --git a/lib/markdown/index.js b/lib/markdown/index.js index 872df7bbc4..370cee617f 100644 --- a/lib/markdown/index.js +++ b/lib/markdown/index.js @@ -6,6 +6,7 @@ const component = require('./component') const hoistScriptStyle = require('./hoist') const convertRouterLink = require('./link') const containers = require('./containers') +const snippet = require('./snippet') const emoji = require('markdown-it-emoji') const anchor = require('markdown-it-anchor') const toc = require('markdown-it-table-of-contents') @@ -24,6 +25,7 @@ module.exports = ({ markdown = {}} = {}) => { .use(component) .use(highlightLines) .use(preWrapper) + .use(snippet) .use(convertRouterLink, Object.assign({ target: '_blank', rel: 'noopener noreferrer' diff --git a/lib/markdown/snippet.js b/lib/markdown/snippet.js new file mode 100644 index 0000000000..a677e12f77 --- /dev/null +++ b/lib/markdown/snippet.js @@ -0,0 +1,43 @@ +const fs = require('fs') + +module.exports = function snippet (md, options = {}) { + const root = options.root || process.cwd() + function parser (state, startLine, endLine, silent) { + const CH = '<'.charCodeAt(0) + const pos = state.bMarks[startLine] + state.tShift[startLine] + const max = state.eMarks[startLine] + + // if it's indented more than 3 spaces, it should be a code block + if (state.sCount[startLine] - state.blkIndent >= 4) { + return false + } + + for (let i = 0; i < 3; ++i) { + const ch = state.src.charCodeAt(pos + i) + if (ch !== CH || pos + i >= max) return false + } + + if (silent) { + return true + } + + const start = pos + 3 + const end = state.skipSpacesBack(max, pos) + const rawPath = state.src.slice(start, end).trim().replace(/^@/, root) + const filename = rawPath.split(/[{:\s]/).shift() + const content = fs.existsSync(filename) ? fs.readFileSync(filename).toString() : 'Not found: ' + filename + const meta = rawPath.replace(filename, '') + + state.line = startLine + 1 + + const token = state.push('fence', 'code', 0) + token.info = filename.split('.').pop() + meta + token.content = content + token.markup = '```' + token.map = [startLine, startLine + 1] + + return true + } + + md.block.ruler.before('fence', 'snippet', parser) +} diff --git a/test/markdown/__snapshots__/snippet.spec.js.snap b/test/markdown/__snapshots__/snippet.spec.js.snap new file mode 100644 index 0000000000..aee3947c97 --- /dev/null +++ b/test/markdown/__snapshots__/snippet.spec.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`snippet import snippet 1`] = ` +
export default function () {
+  // ..
+}
+`; + +exports[`snippet import snippet with highlight multiple lines 1`] = ` +
+
 
+
 
+
 
+
export default function () { // .. } +`; + +exports[`snippet import snippet with highlight single line 1`] = ` +
+
 
+
+
 
+
export default function () { // .. } +`; diff --git a/test/markdown/fragments/code-snippet-highlightLines-multiple.md b/test/markdown/fragments/code-snippet-highlightLines-multiple.md new file mode 100644 index 0000000000..01aef2de27 --- /dev/null +++ b/test/markdown/fragments/code-snippet-highlightLines-multiple.md @@ -0,0 +1 @@ +<<< @/test/markdown/fragments/snippet.js{1-3} diff --git a/test/markdown/fragments/code-snippet-highlightLines-single.md b/test/markdown/fragments/code-snippet-highlightLines-single.md new file mode 100644 index 0000000000..1916b68411 --- /dev/null +++ b/test/markdown/fragments/code-snippet-highlightLines-single.md @@ -0,0 +1 @@ +<<< @/test/markdown/fragments/snippet.js{1,3} diff --git a/test/markdown/fragments/code-snippet.md b/test/markdown/fragments/code-snippet.md new file mode 100644 index 0000000000..65e9148549 --- /dev/null +++ b/test/markdown/fragments/code-snippet.md @@ -0,0 +1 @@ +<<< @/test/markdown/fragments/snippet.js diff --git a/test/markdown/fragments/snippet.js b/test/markdown/fragments/snippet.js new file mode 100644 index 0000000000..575039d1ec --- /dev/null +++ b/test/markdown/fragments/snippet.js @@ -0,0 +1,3 @@ +export default function () { + // .. +} diff --git a/test/markdown/snippet.spec.js b/test/markdown/snippet.spec.js new file mode 100644 index 0000000000..0131132916 --- /dev/null +++ b/test/markdown/snippet.spec.js @@ -0,0 +1,26 @@ +import { Md, getFragment } from './util' +import snippet from '@/markdown/snippet.js' +import highlightLines from '@/markdown/highlightLines.js' + +const md = Md().use(snippet) +const mdH = Md().use(snippet).use(highlightLines) + +describe('snippet', () => { + test('import snippet', async () => { + const input = await getFragment('code-snippet') + const output = md.render(input) + expect(output).toMatchSnapshot() + }) + + test('import snippet with highlight single line', async () => { + const input = await getFragment('code-snippet-highlightLines-single') + const output = mdH.render(input) + expect(output).toMatchSnapshot() + }) + + test('import snippet with highlight multiple lines', async () => { + const input = await getFragment('code-snippet-highlightLines-multiple') + const output = mdH.render(input) + expect(output).toMatchSnapshot() + }) +})