Skip to content

Commit 28bbac8

Browse files
authored
Merge pull request #7 from vue-styleguidist/feat-requirestuff
feature: allow use of requires and imports
2 parents f90696d + 61905a1 commit 28bbac8

File tree

8 files changed

+117
-7619
lines changed

8 files changed

+117
-7619
lines changed

docs/.vuepress/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports = {
44
title: "VuePress Live",
55
description: "Demo site of the VuePress-live plugin",
66
themeConfig: {
7-
repo: "vue-styleguidist/vuepress-live",
7+
repo: "vue-styleguidist/vuepress-plugin-live",
88
editLinks: true,
99
docsDir: "docs",
1010
search: false,

docs/README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Using the [@vuepress/register-components](https://www.npmjs.com/package/@vuepres
3232
Here you can see the [vue-slider-component](https://www.npmjs.com/package/vue-slider-component) in action.
3333

3434
```jsx live
35-
let value = 72;
35+
let value = 72
3636

3737
<div>value: {{ value }}</div>
3838
<vue-slider
@@ -41,3 +41,15 @@ let value = 72;
4141
:order="false"
4242
/>
4343
```
44+
45+
You can even require external libraries in your examples.
46+
```jsx live
47+
const _ = require("lodash")
48+
const anu = [2, 5, 7]
49+
const newArray = []
50+
_.each(anu, a => {
51+
newArray.push(`number: ${a}`)
52+
})
53+
54+
<div>value: {{ newArray.join(",") }}</div>
55+
```

getAst.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const { Parser } = require("acorn");
2+
3+
const ACORN_OPTIONS = {
4+
ecmaVersion: 2019,
5+
sourceType: "module"
6+
};
7+
8+
/**
9+
* Parse source code with Acorn and return AST, returns undefined in case of errors
10+
*/
11+
module.exports = function getAst(code, plugins = []) {
12+
const parser = Parser.extend(...plugins);
13+
14+
try {
15+
return parser.parse(code, ACORN_OPTIONS);
16+
} catch (err) {
17+
return undefined;
18+
}
19+
};

getImports.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const acornJsx = require("acorn-jsx");
2+
const walkes = require("walkes");
3+
const getAst = require("./getAst");
4+
5+
/**
6+
* Returns a list of all strings used in import statements or require() calls
7+
*/
8+
module.exports = function getImports(code) {
9+
// Parse example source code, but ignore errors:
10+
// 1. Adjacent JSX elements must be wrapped in an enclosing tag (<X/><Y/>) -
11+
// imports/requires are not allowed in this case, and we'll wrap the code
12+
// in React.Fragment on the frontend
13+
// 2. All other errors - we'll deal with them on the frontend
14+
const ast = getAst(code, [acornJsx()]);
15+
if (!ast) {
16+
return [];
17+
}
18+
19+
const imports = [];
20+
walkes(ast, {
21+
// import foo from '
22+
// import 'foo'
23+
ImportDeclaration(node) {
24+
if (node.source) {
25+
imports.push(node.source.value);
26+
}
27+
},
28+
// require('foo')
29+
CallExpression(node) {
30+
if (
31+
node.callee &&
32+
node.callee.name === "require" &&
33+
node.arguments &&
34+
node.arguments[0].value
35+
) {
36+
imports.push(node.arguments[0].value);
37+
}
38+
}
39+
});
40+
return imports;
41+
};

markDownPlugin.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
const { parseComponent } = require("vue-template-compiler");
2+
const { isCodeVueSfc } = require("vue-inbrowser-compiler");
3+
const getImports = require("./getImports");
4+
15
const addVueLive = md => {
26
const fence = md.renderer.rules.fence;
37
md.renderer.rules.fence = (...args) => {
@@ -10,11 +14,29 @@ const addVueLive = md => {
1014
return fence(...args);
1115
}
1216

17+
const getScript = code => {
18+
// script is at the beginning of a line after a return
19+
// In case we are loading a vue component as an example, extract script tag
20+
if (isCodeVueSfc(code)) {
21+
const parts = parseComponent(code);
22+
return parts && parts.script ? parts.script.content : "";
23+
}
24+
//else it could be the weird almost jsx of vue-styleguidist
25+
return code.split(/\n[\t ]*</)[0];
26+
};
27+
1328
const code = token.content;
14-
// TODO: analyze code here to find requires
29+
30+
// analyze code to find requires
1531
// put all requires into a "requires" object
1632
// add this as a prop
17-
return `<vue-live :code="\`${md.utils.escapeHtml(code)}\`" />`;
33+
const scr = getScript(code);
34+
const requires = getImports(scr).map(mod => `${mod}: require('${mod}')`);
35+
36+
return `<vue-live :code="\`${md.utils
37+
.escapeHtml(code)
38+
.replace(/\`/g, "\\`")
39+
.replace(/\$/g, "\\$")}\`" :requires="{${requires.join(",")}}"/>`;
1840
};
1941
};
2042

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@
2626
"homepage": "http://vuepress-live.surge.sh/",
2727
"devDependencies": {
2828
"@vuepress/plugin-register-components": "^1.0.0-alpha.48",
29+
"lodash": "^4.17.11",
2930
"remark": "^10.0.1",
3031
"unist-util-visit": "^1.4.0",
32+
"validate-commit-msg": "^2.14.0",
3133
"vue-slider-component": "^3.0.31",
32-
"vuepress": "^1.0.0-alpha.48",
33-
"validate-commit-msg": "^2.14.0"
34+
"vuepress": "^1.0.0-alpha.48"
3435
},
3536
"dependencies": {
36-
"vue-live": "^0.4.8"
37+
"acorn": "^6.1.1",
38+
"acorn-jsx": "^5.0.1",
39+
"vue-inbrowser-compiler": "^3.13.8",
40+
"vue-live": "^0.4.8",
41+
"walkes": "^0.2.1"
3742
}
3843
}

0 commit comments

Comments
 (0)