126 lines
3.0 KiB
JavaScript
126 lines
3.0 KiB
JavaScript
import { resolve, relative, dirname } from 'path'
|
|
import { existsSync } from 'fs'
|
|
import visit from 'unist-util-visit'
|
|
import { readFileSync, hash } from './util'
|
|
import { render } from './page'
|
|
import { parseComponent } from 'vue-template-compiler'
|
|
import { escape } from 'lodash'
|
|
import { RE_LOCALE } from './i18n'
|
|
|
|
const DOCS_DIR = resolve(__dirname, '../docs')
|
|
|
|
export default function attacher () {
|
|
return (tree, file) => {
|
|
let { path, data: fileData } = file
|
|
visit(tree, 'shortcode', node => {
|
|
let {
|
|
identifier,
|
|
data: nodeData,
|
|
attributes: { src, browser } = {}
|
|
} = node
|
|
if (identifier !== 'demo' || !src) {
|
|
return
|
|
}
|
|
|
|
if (!nodeData) {
|
|
node.data = nodeData = {}
|
|
}
|
|
if (!fileData) {
|
|
file.data = fileData = {}
|
|
}
|
|
if (!fileData.demos) {
|
|
fileData.demos = {}
|
|
}
|
|
if (!fileData.deps) {
|
|
fileData.deps = {}
|
|
}
|
|
|
|
let demoPath =
|
|
src.indexOf('/') === 0
|
|
? resolve(DOCS_DIR, src.slice(1))
|
|
: resolve(dirname(path), src)
|
|
|
|
if (!existsSync(demoPath)) {
|
|
console.warn(`Demo not found at '${demoPath}'`)
|
|
return
|
|
}
|
|
|
|
fileData.deps[demoPath] = true
|
|
|
|
let name = getComponentName(demoPath)
|
|
nodeData.hName = name
|
|
|
|
let localPath = `/${relative(DOCS_DIR, path)}`
|
|
let [, locale] = localPath.match(RE_LOCALE) || []
|
|
|
|
let { content, doc } = extractDoc(demoPath, { locale })
|
|
fileData.demos[name] = {
|
|
path: demoPath,
|
|
browser,
|
|
code: render('```vue\n' + content + '\n```', demoPath).contents,
|
|
desc: render(doc, demoPath).contents
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
function getComponentName (path) {
|
|
return `one-demo-${hash(path)}`
|
|
}
|
|
|
|
function extractDoc (file, { locale }) {
|
|
let content = readFileSync(file)
|
|
let vueComponent = parseComponent(content)
|
|
let { customBlocks } = vueComponent
|
|
let i = customBlocks.findIndex(({ type, attrs }) => {
|
|
return ((locale && locale === attrs.locale) || !locale) && type === 'docs'
|
|
})
|
|
|
|
let doc = null
|
|
if (i !== -1) {
|
|
doc = customBlocks[i].content
|
|
}
|
|
|
|
return {
|
|
content: stringifyVueComponent(vueComponent),
|
|
doc
|
|
}
|
|
}
|
|
|
|
function stringifyVueComponent (component) {
|
|
let content = []
|
|
let { template, script, styles } = component
|
|
if (template) {
|
|
content.push(
|
|
`<template${stringifyAttrs(template.attrs)}>${
|
|
template.content
|
|
}</template>`
|
|
)
|
|
}
|
|
if (script) {
|
|
content.push(
|
|
`<script${stringifyAttrs(script.attrs)}>${script.content}</script>`
|
|
)
|
|
}
|
|
styles.filter(({ attrs }) => !attrs.docs).forEach(style => {
|
|
content.push(
|
|
`<style${stringifyAttrs(style.attrs)}>${style.content}</style>`
|
|
)
|
|
})
|
|
return content.join('\n\n')
|
|
}
|
|
|
|
function stringifyAttrs (attrs) {
|
|
let result = Object.keys(attrs)
|
|
.map(key => {
|
|
let val = attrs[key]
|
|
if (typeof val !== 'boolean') {
|
|
return `${escape(key)}="${escape(val)}"`
|
|
}
|
|
return val ? `${escape(key)}` : ''
|
|
})
|
|
.join(' ')
|
|
|
|
return result ? ` ${result}` : ''
|
|
}
|