UNPKG

@docfy/ember-vite

Version:

Vite plugin for Docfy Ember integration with @embroider/vite

155 lines (154 loc) 6.27 kB
import { generateComponentFiles } from './component-generator.js'; import { getComponentImport } from './import-map.js'; import debugFactory from 'debug'; const debug = debugFactory('@docfy/ember-vite:template-generator'); /** * Generate the template path for a markdown page URL * This mirrors the existing Ember CLI behavior from DocfyBroccoli.build() * Templates should be in app/templates/ for Ember to find them */ function generateTemplatePath(url) { const parts = ['app', 'templates', ...url.split('/').filter(Boolean)]; // Handle index routes - if URL ends with '/', add 'index' if (url.endsWith('/')) { parts.push('index'); } return `${parts.join('/')}.gjs`; } /** * Get the import path for a component relative to the page template */ function getComponentImportPath(pageUrl, componentName, ext = 'gjs') { // Convert page URL to component path const cleanUrl = pageUrl.replace(/^\/+|\/+$/g, ''); const parts = cleanUrl.split('/').filter(Boolean); if (pageUrl.endsWith('/')) { parts.push('index'); } // Add _gen suffix to the last part (page name) const lastPart = parts.pop() || 'index'; // Create relative path from template to component // templates/docs/ember/writing-demos.gjs -> ./writing-demos_gen/componentname.ext return `./${lastPart}_gen/${componentName.toLowerCase()}.${ext}`; } /** * Process all imports for a page template * Combines component generation, plugin imports, and frontmatter imports * Returns the complete imports string ready for template generation */ function processPageImports(page) { debug('Processing page imports', { url: page.meta.url }); const structuredImports = []; const pluginData = page.pluginData; const demoComponents = pluginData?.demoComponents; // Generate imports for demo components if (demoComponents?.length) { demoComponents.forEach(demo => { // For GJS/GTS files, import directly; otherwise import the JS file const gtsGjsChunk = demo.chunks.find(c => ['gjs', 'gts'].includes(c.ext)); let ext = 'js'; // default to JS import if (gtsGjsChunk) { ext = gtsGjsChunk.ext; // Use GJS/GTS file directly } const componentPath = getComponentImportPath(page.meta.url, demo.name.dashCase, ext); structuredImports.push({ name: demo.name.pascalCase, path: componentPath, isDefault: true, }); }); // Add DocfyDemo import if we have demo components structuredImports.push(getComponentImport('DocfyDemo')); } // Process plugin imports (e.g., from replace-internal-links-with-docfy-link plugin) if (pluginData?.imports?.length) { pluginData.imports.forEach((imp) => { structuredImports.push({ name: imp.name, path: imp.path, isDefault: imp.isDefault ?? true, namedImports: imp.namedImports, }); }); } // Generate structured imports section const structuredImportsSection = structuredImports.length > 0 ? structuredImports.map(imp => generateImportStatement(imp)).join('\n') : ''; // Handle raw imports from frontmatter const frontmatterImports = page.meta.frontmatter.imports; let rawImportsSection = ''; if (frontmatterImports) { if (typeof frontmatterImports === 'string') { // Single import string rawImportsSection = frontmatterImports; } else if (Array.isArray(frontmatterImports)) { // Array of import strings rawImportsSection = frontmatterImports .filter((imp) => typeof imp === 'string') .join('\n'); } } // Combine all imports into final string const allImportsSections = [structuredImportsSection, rawImportsSection].filter(section => section.length > 0); const finalImportsString = allImportsSections.length > 0 ? allImportsSections.join('\n') + '\n\n' : ''; debug('Processed page imports', { url: page.meta.url, imports: finalImportsString, }); return finalImportsString; } /** * Generate an import statement from ImportStatement metadata */ function generateImportStatement(importStmt) { if (importStmt.isDefault && importStmt.namedImports) { // Mixed import: import Default, { named1, named2 } from 'path' return `import ${importStmt.name}, { ${importStmt.namedImports.join(', ')} } from '${importStmt.path}';`; } else if (importStmt.isDefault) { // Default import: import Default from 'path' return `import ${importStmt.name} from '${importStmt.path}';`; } else if (importStmt.namedImports) { // Named imports: import { named1, named2 } from 'path' return `import { ${importStmt.namedImports.join(', ')} } from '${importStmt.path}';`; } else { // Single named import: import { name } from 'path' return `import { ${importStmt.name} } from '${importStmt.path}';`; } } /** * Generate a complete page template with path and content * This is the main entry point for template generation */ export function generatePage(page) { debug('Generating page files', { url: page.meta.url }); const filesToGenerate = []; // Generate the template path const templatePath = generateTemplatePath(page.meta.url); // Generate component files for the page const componentFiles = generateComponentFiles(page); // Process and generate all import statements const importsSection = processPageImports(page); const template = `${importsSection}<template> ${page.rendered} </template>`; // Add template file to the list filesToGenerate.push({ path: templatePath, content: template, }); // Add all component files to the list filesToGenerate.push(...componentFiles); debug('Generated page files', { url: page.meta.url, totalFiles: filesToGenerate.length, templatePath, componentFilesCount: componentFiles.length, importsStringLength: importsSection.length, }); return filesToGenerate; }