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.content
}`
)
}
if (script) {
content.push(
``
)
}
styles.filter(({ attrs }) => !attrs.docs).forEach(style => {
content.push(
``
)
})
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}` : ''
}