Comparing version 0.0.5 to 0.0.6
@@ -0,1 +1,17 @@ | ||
## [0.0.6](https://github.com/ymmooot/markduck/compare/v0.0.5...v0.0.6) (2019-12-21) | ||
* make remark plugin to convert mdast to vue (#10) ([efdaf48](https://github.com/ymmooot/markduck/commit/efdaf483d277d718c9f3825515535955cdd3e524)), closes [#10](https://github.com/ymmooot/markduck/issues/10) | ||
### BREAKING CHANGES | ||
* 🧨 change options interface | ||
* refactor: remove mdast-util-to-hast | ||
* docs: update readme | ||
## [0.0.5](https://github.com/ymmooot/markduck/compare/v0.0.4...v0.0.5) (2019-12-21) | ||
@@ -2,0 +18,0 @@ |
@@ -1,17 +0,12 @@ | ||
import { VueConstructor, CreateElement, VNode as VueVNode } from 'vue'; | ||
import { CreateElement } from 'vue'; | ||
import { Plugin, Settings } from 'unified'; | ||
import { VNode } from 'virtual-dom'; | ||
declare type ComponentRegisterFunc = (node: VNode, parentNode?: VNode) => VueConstructor<Vue> | undefined; | ||
declare type ComponentRegisterOption = { | ||
[keyof: string]: VueConstructor<Vue> | ComponentRegisterFunc; | ||
}; | ||
declare type UnifiedPlugin = { | ||
plugin: Plugin; | ||
config: Settings; | ||
} | Plugin; | ||
import { ComponentRegisterOption } from './rehype-vue'; | ||
declare type PluginOption = Plugin | [Plugin, Settings]; | ||
export declare type Option = { | ||
components: ComponentRegisterOption; | ||
remarkPlugins: UnifiedPlugin[]; | ||
components?: ComponentRegisterOption; | ||
sanitizeScheme?: object; | ||
remarkPlugins?: PluginOption[]; | ||
rehypePlugins?: PluginOption[]; | ||
}; | ||
declare const convert: (createElement: CreateElement, markdown: string, option: Option) => (string | VueVNode)[]; | ||
declare const convert: (createElement: CreateElement, markdown: string, option: Option) => any; | ||
export default convert; |
@@ -8,53 +8,30 @@ "use strict"; | ||
const remark_parse_1 = __importDefault(require("remark-parse")); | ||
const remark_vdom_1 = __importDefault(require("remark-vdom")); | ||
const markdownToVDom = (markdown, plugins) => { | ||
const p = [remark_parse_1.default, ...plugins, remark_vdom_1.default]; | ||
const u = p.reduce((acc, plugin) => { | ||
if (plugin.name) { | ||
return acc.use(plugin); | ||
const remark_rehype_1 = __importDefault(require("remark-rehype")); | ||
const rehype_vue_1 = __importDefault(require("./rehype-vue")); | ||
const convert = (createElement, markdown, option) => { | ||
var _a, _b; | ||
const remarkPlugins = ((_a = option) === null || _a === void 0 ? void 0 : _a.remarkPlugins) || []; | ||
const rehypePlugins = ((_b = option) === null || _b === void 0 ? void 0 : _b.rehypePlugins) || []; | ||
const remarkVueOption = { | ||
createElement, | ||
components: option.components, | ||
sanitizeScheme: option.sanitizeScheme, | ||
}; | ||
// prettier-ignore | ||
const plugins = [ | ||
remark_parse_1.default, | ||
...remarkPlugins, | ||
remark_rehype_1.default, | ||
...rehypePlugins, | ||
[rehype_vue_1.default, remarkVueOption] | ||
]; | ||
const processor = plugins.reduce((pipe, plugin) => { | ||
if (Array.isArray(plugin)) { | ||
return pipe.use(plugin[0], plugin[1] || {}); | ||
} | ||
return acc.use(plugin.plugin, plugin.config); | ||
return pipe.use(plugin); | ||
}, unified_1.default()); | ||
const file = u.processSync(markdown); | ||
return file.contents; | ||
const { contents } = processor.processSync(markdown); | ||
return contents; | ||
}; | ||
const isFunc = (customComponent) => typeof customComponent === 'function'; | ||
const isVText = (vdom) => vdom.type === 'VirtualText'; | ||
const isVNode = (vdom) => vdom.type === 'VirtualNode'; | ||
const vdomToVNode = (createElement, vdoms, parent, option) => { | ||
var _a, _b, _c; | ||
const nodes = []; | ||
for (let index = 0; index < vdoms.length; index++) { | ||
const vdom = vdoms[index]; | ||
// VirtualText has no tag | ||
if (isVText(vdom)) { | ||
nodes.push(vdom.text); | ||
continue; | ||
} | ||
if (!isVNode(vdom)) { | ||
continue; | ||
} | ||
const children = ((_a = vdom.children) === null || _a === void 0 ? void 0 : _a.length) > 0 ? vdomToVNode(createElement, vdom.children, vdom, option) : []; | ||
// get custom component | ||
const tagName = (_b = vdom.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase(); | ||
const customComponentOpt = option.components[tagName]; | ||
const customComponent = isFunc(customComponentOpt) ? customComponentOpt(vdom, parent) : customComponentOpt; | ||
if (customComponent) { | ||
const node = createElement(customComponent, { | ||
props: vdom.properties.attributes, | ||
}, children); | ||
nodes.push(node); | ||
continue; | ||
} | ||
const node = createElement(tagName, { | ||
attrs: (_c = vdom.properties) === null || _c === void 0 ? void 0 : _c.attributes, | ||
}, children); | ||
nodes.push(node); | ||
} | ||
return nodes; | ||
}; | ||
const convert = (createElement, markdown, option) => { | ||
const tree = markdownToVDom(markdown, option.remarkPlugins); | ||
return vdomToVNode(createElement, [tree], undefined, option); | ||
}; | ||
exports.default = convert; |
@@ -20,30 +20,24 @@ "use strict"; | ||
const mockH = jest.fn().mockImplementation((...args) => args); | ||
const vnodes = convert_1.default(mockH, markdown, { components: {}, remarkPlugins: [] }); | ||
const vnodes = convert_1.default(mockH, markdown, {}); | ||
expect(vnodes).toEqual([ | ||
'div', | ||
{}, | ||
[ | ||
'div', | ||
{ attrs: undefined }, | ||
['h1', {}, ['title']], | ||
'\n', | ||
['p', {}, ['plain text.']], | ||
'\n', | ||
['h2', {}, ['sub title']], | ||
'\n', | ||
[ | ||
['h1', { attrs: undefined }, ['title']], | ||
'\n', | ||
['p', { attrs: undefined }, ['plain text.']], | ||
'\n', | ||
['h2', { attrs: undefined }, ['sub title']], | ||
'\n', | ||
'ul', | ||
{}, | ||
[ | ||
'ul', | ||
{ attrs: undefined }, | ||
[ | ||
'\n', | ||
['li', { attrs: undefined }, ['list1']], | ||
'\n', | ||
[ | ||
'li', | ||
{ attrs: undefined }, | ||
['list2 with ', ['img', { attrs: { alt: 'image', src: 'https://example.com/hoge.jpg' } }, []]], | ||
], | ||
'\n', | ||
['li', { attrs: undefined }, ['list3']], | ||
'\n', | ||
], | ||
'\n', | ||
['li', {}, ['list1']], | ||
'\n', | ||
['li', {}, ['list2 with ', ['img', { alt: 'image', src: 'https://example.com/hoge.jpg' }, undefined]]], | ||
'\n', | ||
['li', {}, ['list3']], | ||
'\n', | ||
], | ||
@@ -50,0 +44,0 @@ ], |
import Vue from 'vue'; | ||
import { Option } from './convert'; | ||
declare const _default: (_option?: Option) => import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, { | ||
declare const _default: (option?: Option) => import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, { | ||
markdown: string; | ||
}>; | ||
export default _default; |
@@ -8,8 +8,3 @@ "use strict"; | ||
const convert_1 = __importDefault(require("./convert")); | ||
exports.default = (_option) => { | ||
var _a, _b; | ||
const option = { | ||
remarkPlugins: ((_a = _option) === null || _a === void 0 ? void 0 : _a.remarkPlugins) || [], | ||
components: ((_b = _option) === null || _b === void 0 ? void 0 : _b.components) || {}, | ||
}; | ||
exports.default = (option) => { | ||
return vue_1.default.extend({ | ||
@@ -19,6 +14,5 @@ name: 'markduck-root', | ||
render(h) { | ||
const nodes = convert_1.default(h, this.markdown, option); | ||
return h('div', nodes); | ||
return convert_1.default(h, this.markdown, option); | ||
}, | ||
}); | ||
}; |
{ | ||
"name": "markduckjs", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "Render markdown with your Vue components.", | ||
@@ -36,6 +36,10 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@types/virtual-dom": "^2.1.0", | ||
"@mapbox/hast-util-table-cell-style": "^0.1.3", | ||
"@mapbox/rehype-prism": "^0.3.1", | ||
"hast-to-hyperscript": "^7.0.4", | ||
"hast-util-sanitize": "^2.0.1", | ||
"remark-parse": "^7.0.2", | ||
"remark-vdom": "^8.0.0", | ||
"remark-rehype": "^5.0.0", | ||
"unified": "^8.4.2", | ||
"unist-util-visit": "^2.0.1", | ||
"vue": "^2.6.11", | ||
@@ -42,0 +46,0 @@ "vue-hot-reload-api": "^2.3.4" |
@@ -36,2 +36,4 @@ <div align="center"> | ||
import gemojiToEmoji from 'remark-gemoji-to-emoji'; | ||
import rehypePrism from '@mapbox/rehype-prism'; | ||
import 'prismjs/themes/prism.css'; | ||
@@ -41,3 +43,3 @@ export default { | ||
return { | ||
markdown: '# your markdown' | ||
markdown: '# your markdown :duck:', | ||
}; | ||
@@ -49,7 +51,8 @@ }, | ||
remarkPlugins: [gemojiToEmoji], | ||
rehypePlugins: [rehypePrism], | ||
components: { | ||
ul: UnorderedList, // register your components! | ||
ul: UnorderedList, | ||
li: ListItem, | ||
img: (vdom, parent) => { // you can register it via function | ||
if (vdom.properties.attributes.alt) { | ||
img: nodeData => { | ||
if (nodeData.attrs.alt) { | ||
return FigureImage; | ||
@@ -77,3 +80,3 @@ } | ||
```ts | ||
type ComponentRegisterFunc = (node: VNode, parentNode?: VNode) => VueConstructor<Vue> | undefined; | ||
type ComponentRegisterFunc = (data: VNodeData) => VueConstructor<Vue> | undefined; | ||
@@ -96,3 +99,3 @@ type ComponentRegisterOption = { | ||
`Array` of `Plugin` or `{ plugin: Plugin, config: Settings }` | ||
`Array` of `Plugin` or `[Plugin, Settings]` | ||
(`Plugin` and `Settings` are from [Unified](https://github.com/unifiedjs/unified).) | ||
@@ -104,2 +107,9 @@ | ||
### rehypePlugins | ||
Same as remarkPlugins. | ||
Rehype plugins will run after remarkPlugins. | ||
### sanitizeScheme | ||
## Demo | ||
@@ -112,1 +122,10 @@ | ||
``` | ||
## Flow of conversion from markdown to Vue | ||
``` | ||
remark-parser remark-rehype createElement | ||
your markdown -> mdast -> hast -> vue | ||
↑ ↑ | ||
your remark plugin your rehype plugin | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18036
19
259
125
10
1
+ Added@mapbox/rehype-prism@^0.3.1
+ Addedhast-to-hyperscript@^7.0.4
+ Addedhast-util-sanitize@^2.0.1
+ Addedremark-rehype@^5.0.0
+ Addedunist-util-visit@^2.0.1
+ Added@mapbox/hast-util-table-cell-style@0.1.3(transitive)
+ Added@mapbox/rehype-prism@0.3.1(transitive)
+ Addedclipboard@2.0.11(transitive)
+ Addeddelegate@3.2.0(transitive)
+ Addedgood-listener@1.2.2(transitive)
+ Addedhast-util-parse-selector@2.2.5(transitive)
+ Addedhast-util-to-string@1.0.4(transitive)
+ Addedhastscript@5.1.2(transitive)
+ Addedprismjs@1.17.1(transitive)
+ Addedrefractor@2.10.1(transitive)
+ Addedremark-rehype@5.0.0(transitive)
+ Addedselect@1.1.2(transitive)
+ Addedtiny-emitter@2.1.0(transitive)
+ Addedunist-util-is@4.1.0(transitive)
+ Addedunist-util-visit@2.0.3(transitive)
+ Addedunist-util-visit-parents@3.1.1(transitive)
- Removed@types/virtual-dom@^2.1.0
- Removedremark-vdom@^8.0.0
- Removed@types/virtual-dom@2.1.4(transitive)
- Removedbrowser-split@0.0.1(transitive)
- Removedcamelize@1.0.1(transitive)
- Removeddom-walk@0.1.2(transitive)
- Removederror@4.4.0(transitive)
- Removedev-store@7.0.0(transitive)
- Removedglobal@4.4.0(transitive)
- Removedindividual@3.0.0(transitive)
- Removedis-object@1.0.2(transitive)
- Removedmin-document@2.19.0(transitive)
- Removednext-tick@0.2.2(transitive)
- Removedprocess@0.11.10(transitive)
- Removedremark-vdom@8.0.0(transitive)
- Removedstring-template@0.2.1(transitive)
- Removedvirtual-dom@2.1.1(transitive)
- Removedx-is-array@0.1.0(transitive)
- Removedx-is-string@0.1.0(transitive)