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