@docfy/ember-vite
Version:
Vite plugin for Docfy Ember integration with @embroider/vite
124 lines (123 loc) • 4.51 kB
JavaScript
import debugFactory from 'debug';
const debug = debugFactory('@docfy/ember-vite-plugin:process-demos');
/**
* Process demo components and convert them to inline components
*/
export function processPageDemos(page) {
debug('Processing page demos', { url: page.meta.url });
const inlineComponents = [];
const imports = [];
// Check if the page has demo components from the core plugins
const pluginData = page.pluginData || {};
const pluginDemoComponents = (pluginData.demoComponents || []);
if (Array.isArray(pluginDemoComponents) && pluginDemoComponents.length > 0) {
pluginDemoComponents.forEach((demoComponent) => {
if (demoComponent.name && demoComponent.chunks) {
const component = convertDemoToInlineComponent(demoComponent);
if (component) {
inlineComponents.push(component);
// Add any imports that the component might need
if (component.imports) {
imports.push(...component.imports);
}
}
}
});
}
debug('Processed demos', {
url: page.meta.url,
demoCount: pluginDemoComponents.length,
inlineComponentsCount: inlineComponents.length
});
return { inlineComponents, imports };
}
/**
* Convert a demo component to an inline component
*/
function convertDemoToInlineComponent(demoComponent) {
const { name, chunks } = demoComponent;
// Find template and script chunks
const templateChunk = chunks.find(chunk => chunk.ext === 'hbs' || chunk.ext === 'html' || chunk.type === 'template');
const scriptChunk = chunks.find(chunk => ['js', 'ts', 'gjs', 'gts'].includes(chunk.ext) || chunk.type === 'component');
if (!templateChunk) {
debug('No template chunk found for demo component', { name: name.dashCase });
return null;
}
// Determine component type and generate appropriate inline component
if (templateChunk && scriptChunk) {
// Component has both template and logic
return {
name: name.pascalCase,
type: 'class-based',
template: templateChunk.code,
script: scriptChunk.code,
imports: extractImportsFromScript(scriptChunk.code)
};
}
else if (templateChunk) {
// Template-only component
return {
name: name.pascalCase,
type: 'const-template',
template: templateChunk.code,
imports: extractImportsFromTemplate(templateChunk.code)
};
}
return null;
}
/**
* Extract imports from script code
*/
function extractImportsFromScript(script) {
const imports = [];
// Basic import extraction - this can be enhanced later
const importRegex = /import\s+(?:(\w+)(?:\s*,\s*)?)?(?:\{([^}]+)\})?\s+from\s+['"]([^'"]+)['"]/g;
let match;
while ((match = importRegex.exec(script)) !== null) {
const [, defaultImport, namedImports, path] = match;
if (defaultImport) {
imports.push({
type: 'other',
name: defaultImport,
path: path,
isDefault: true
});
}
if (namedImports) {
const names = namedImports.split(',').map(name => name.trim());
imports.push({
type: 'other',
name: names[0],
path: path,
isDefault: false,
namedImports: names
});
}
}
return imports;
}
/**
* Extract imports from template code (e.g., components used in template)
*/
function extractImportsFromTemplate(template) {
const imports = [];
// Extract component usage from template
const componentRegex = /<([A-Z][a-zA-Z0-9]*)/g;
let match;
while ((match = componentRegex.exec(template)) !== null) {
const componentName = match[1];
// Skip known HTML elements
if (!['HTML', 'HEAD', 'BODY', 'DIV', 'SPAN', 'P', 'A', 'IMG', 'BR', 'HR'].includes(componentName)) {
// Check if we already have this import
if (!imports.find(imp => imp.name === componentName)) {
imports.push({
type: 'component',
name: componentName,
path: `../${componentName.toLowerCase()}`,
isDefault: true
});
}
}
}
return imports;
}