UNPKG

@docfy/ember-vite

Version:

Vite plugin for Docfy Ember integration with @embroider/vite

131 lines (130 loc) 4.05 kB
import u from 'unist-builder'; /** * Creates all the Nodes necessary to render a Demo Component. * * It will render something like the follwing: * ```hbs * <DocfyDemo as |demo|> * <demo.Example> * <ComponentName /> * </demo.Example> * <demo.Description @title="Heading depth 1" @editUrl="url"> * Demo markdown content * </demo.Description> * <demo.Snippets as |Snippet|> * <Snippet @name="component"> * Code Snippet (with any highlight applied from remark) * </Snippet> * </demo.Snippets> * </DocfyDemo> * ``` */ export function createDemoNodes(component) { const nodes = [ u('html', `<DocfyDemo @id="${component.name.dashCase}" as |demo|>`) ]; if (component.description) { nodes.push(u('html', `<demo.Description ${component.description.title ? `@title="${component.description.title}" ` : ''}${component.description.editUrl ? `@editUrl="${component.description.editUrl}"` : ''}>`), component.description.ast, u('html', '</demo.Description>')); } nodes.push(u('html', '<demo.Example>'), u('html', `<${component.name.pascalCase} />`), u('html', '</demo.Example>')); if (component.chunks.length > 1) { nodes.push(u('html', '<demo.Snippets as |Snippet|>')); component.chunks.forEach((chunk) => { nodes.push(u('html', `<Snippet @name="${chunk.type}">`), chunk.snippet, u('html', '</Snippet>')); }); nodes.push(u('html', '</demo.Snippets>')); } else { component.chunks.forEach((chunk) => { nodes.push(u('html', `<demo.Snippet @name="${chunk.type}">`), chunk.snippet, u('html', '</demo.Snippet>')); }); } nodes.push(u('html', '</DocfyDemo>')); return nodes; } const MAP_LANG_TO_EXT = { javascript: 'js', typescript: 'ts', handlebars: 'hbs', 'html.hbs': 'hbs', 'html.handlebars': 'hbs' }; /* * It returns the file extension from a lang string. */ export function getExt(lang) { lang = lang.toLowerCase(); return MAP_LANG_TO_EXT[lang] || lang; } /* * Delete a node from a list of nodes */ export function deleteNode(nodes, nodeToDelete) { if (!nodeToDelete) { return; } if (Array.isArray(nodes)) { const index = nodes.findIndex((item) => item === nodeToDelete); if (index !== -1) { nodes.splice(index, 1); } } } /* * Replace a node from a list of nodes */ export function replaceNode(nodes, nodeToDelete, ...newNodes) { if (Array.isArray(nodes)) { const index = nodes.findIndex((item) => item === nodeToDelete); if (index !== -1) { nodes.splice(index, 1, ...newNodes); } } } /* * Generate the component name from the source path of the demo * * It returns both dash case and pastal case. * The dash-case can be used for the file name and the PascalCase for the * rendering of the component. */ export function generateDemoComponentName(identifier, seenNames, tentativeCount = 1) { const dashCase = identifier .split('.')[0] .toLowerCase() .replace(/\/|\\/g, '-') .replace(/[^a-zA-Z0-9|-]/g, ''); const pascalCase = dashCase .replace(/(\w)(\w*)/g, function (_, g1, g2) { return `${g1.toUpperCase()}${g2.toLowerCase()}`; }) .replace(/-(\d+)/g, function (_, g1) { return `_${g1}`; }) .replace(/-/g, ''); if (seenNames.has(dashCase)) { return generateDemoComponentName(`${dashCase}${tentativeCount}`, seenNames, tentativeCount + 1); } seenNames.add(dashCase); return { dashCase, pascalCase }; } /** * Checks if a property is of type DemoComponent[] */ export function isDemoComponents(components) { if (Array.isArray(components) && typeof components[0] == 'object' && {}.hasOwnProperty.call(components[0], 'name') && {}.hasOwnProperty.call(components[0], 'chunks')) { return true; } return false; }