@see-ms/converter 0.1.0 ā 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +562 -19
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +20 -10
- package/dist/index.mjs +563 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/converter.ts","../src/filesystem.ts","../src/parser.ts","../src/config-updater.ts","../src/boilerplate.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI for @see-ms/converter\n * Usage: cms convert <input-dir> <output-dir> [options]\n */\n\nimport { Command } from 'commander';\nimport pc from 'picocolors';\nimport { convertWebflowExport } from './converter';\n\nconst program = new Command();\n\nprogram\n .name('cms')\n .description('SeeMS - Webflow to CMS converter')\n .version('0.1.0');\n\nprogram\n .command('convert')\n .description('Convert Webflow export to Nuxt 3 project')\n .argument('<input>', 'Path to Webflow export directory')\n .argument('<output>', 'Path to output Nuxt project directory')\n .option('-b, --boilerplate <source>', 'Boilerplate source (GitHub URL or local path)')\n .option('-o, --overrides <path>', 'Path to overrides JSON file')\n .option('--generate-schemas', 'Generate CMS schemas immediately')\n .option('--cms <type>', 'CMS backend type (strapi|contentful|sanity)', 'strapi')\n .action(async (input, output, options) => {\n try {\n await convertWebflowExport({\n inputDir: input,\n outputDir: output,\n boilerplate: options.boilerplate,\n overridesPath: options.overrides,\n generateStrapi: options.generateSchemas,\n cmsBackend: options.cms,\n });\n } catch (error) {\n console.error(pc.red('Conversion failed'));\n process.exit(1);\n }\n });\n\nprogram\n .command('generate')\n .description('Generate CMS schemas from manifest')\n .argument('<manifest>', 'Path to cms-manifest.json')\n .option('-t, --type <cms>', 'CMS type (strapi|contentful|sanity)', 'strapi')\n .option('-o, --output <dir>', 'Output directory for schemas')\n .action(async (manifest, _options) => {\n console.log(pc.cyan('šļø SeeMS Schema Generator'));\n console.log(pc.dim(`Generating schemas from: ${manifest}`));\n \n // TODO: Implementation in Sprint 3\n console.log(pc.yellow('ā ļø Schema generation logic to be implemented'));\n });\n\nprogram.parse();\n","/**\n * Main conversion logic\n */\n\nimport type { ConversionOptions } from '@see-ms/types';\nimport pc from 'picocolors';\nimport fs from 'fs-extra';\nimport {\n scanAssets,\n copyAllAssets,\n findHTMLFiles,\n readHTMLFile,\n writeVueComponent,\n formatVueFiles,\n} from './filesystem';\nimport { parseHTML, transformForNuxt, htmlToVueComponent, deduplicateStyles } from './parser';\nimport {\n writeWebflowAssetPlugin,\n updateNuxtConfig,\n writeEmbeddedStyles,\n} from './config-updater';\nimport { setupBoilerplate } from './boilerplate';\n\nexport async function convertWebflowExport(options: ConversionOptions): Promise<void> {\n const { inputDir, outputDir, boilerplate } = options;\n\n console.log(pc.cyan('š Starting Webflow to Nuxt conversion...'));\n console.log(pc.dim(`Input: ${inputDir}`));\n console.log(pc.dim(`Output: ${outputDir}`));\n\n try {\n // Step 0: Setup boilerplate first\n await setupBoilerplate(boilerplate, outputDir);\n\n // Step 1: Verify input directory exists\n const inputExists = await fs.pathExists(inputDir);\n if (!inputExists) {\n throw new Error(`Input directory not found: ${inputDir}`);\n }\n\n // Step 2: Scan for assets\n console.log(pc.blue('\\nš Scanning assets...'));\n const assets = await scanAssets(inputDir);\n console.log(pc.green(` ā Found ${assets.css.length} CSS files`));\n console.log(pc.green(` ā Found ${assets.images.length} images`));\n console.log(pc.green(` ā Found ${assets.fonts.length} fonts`));\n console.log(pc.green(` ā Found ${assets.js.length} JS files`));\n\n // Step 3: Copy assets to output\n console.log(pc.blue('\\nš¦ Copying assets...'));\n await copyAllAssets(inputDir, outputDir, assets);\n console.log(pc.green(' ā Assets copied successfully'));\n\n // Step 4: Find all HTML files (including in subfolders)\n console.log(pc.blue('\\nš Finding HTML files...'));\n const htmlFiles = await findHTMLFiles(inputDir);\n console.log(pc.green(` ā Found ${htmlFiles.length} HTML files`));\n\n // Step 5: Convert HTML files to Vue components\n console.log(pc.blue('\\nāļø Converting HTML to Vue components...'));\n let allEmbeddedStyles = '';\n\n for (const htmlFile of htmlFiles) {\n const html = await readHTMLFile(inputDir, htmlFile);\n const parsed = parseHTML(html, htmlFile);\n\n // Collect embedded styles\n if (parsed.embeddedStyles) {\n allEmbeddedStyles += `\\n/* From ${htmlFile} */\\n${parsed.embeddedStyles}\\n`;\n }\n\n // Transform HTML for Nuxt\n const transformed = transformForNuxt(parsed.htmlContent);\n\n // Convert to Vue component\n const pageName = htmlFile.replace('.html', '').replace(/\\//g, '-');\n const vueComponent = htmlToVueComponent(transformed, pageName);\n\n // Write to pages directory (this will overwrite existing files)\n await writeVueComponent(outputDir, htmlFile, vueComponent);\n console.log(pc.green(` ā Created ${htmlFile.replace('.html', '.vue')}`));\n }\n\n // Step 6: Format Vue files with Prettier\n await formatVueFiles(outputDir);\n\n // Step 7: Deduplicate and write embedded styles to main.css\n if (allEmbeddedStyles.trim()) {\n console.log(pc.blue('\\n⨠Writing embedded styles...'));\n const dedupedStyles = deduplicateStyles(allEmbeddedStyles);\n await writeEmbeddedStyles(outputDir, dedupedStyles);\n console.log(pc.green(' ā Embedded styles added to main.css'));\n }\n\n // Step 8: Generate/overwrite webflow-assets.ts\n console.log(pc.blue('\\nš§ Generating webflow-assets.ts plugin...'));\n await writeWebflowAssetPlugin(outputDir, assets.css);\n console.log(pc.green(' ā Plugin generated (existing file overwritten)'));\n\n // Step 9: Update nuxt.config.ts\n console.log(pc.blue('\\nāļø Updating nuxt.config.ts...'));\n try {\n await updateNuxtConfig(outputDir, assets.css);\n console.log(pc.green(' ā Config updated'));\n } catch (error) {\n console.log(pc.yellow(' ā Could not update nuxt.config.ts automatically'));\n console.log(pc.dim(' Please add CSS files manually'));\n }\n\n // Success!\n console.log(pc.green('\\nā
Conversion completed successfully!'));\n console.log(pc.cyan('\\nš Next steps:'));\n console.log(pc.dim(` 1. cd ${outputDir}`));\n console.log(pc.dim(' 2. pnpm install'));\n console.log(pc.dim(' 3. pnpm dev'));\n } catch (error) {\n console.error(pc.red('\\nā Conversion failed:'));\n console.error(pc.red(error instanceof Error ? error.message : String(error)));\n throw error;\n }\n}\n","/**\n * File system utilities for copying Webflow assets\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport { execSync } from 'child_process';\nimport pc from 'picocolors';\n\nexport interface AssetPaths {\n css: string[]; // Goes to assets/css/\n images: string[]; // Goes to public/assets/images/\n fonts: string[]; // Goes to public/assets/fonts/\n js: string[]; // Goes to public/assets/js/\n}\n\n/**\n * Scan Webflow export directory for assets\n */\nexport async function scanAssets(webflowDir: string): Promise<AssetPaths> {\n const assets: AssetPaths = {\n css: [],\n images: [],\n fonts: [],\n js: [],\n };\n\n // Find CSS files\n const cssFiles = await glob('css/**/*.css', { cwd: webflowDir });\n assets.css = cssFiles;\n\n // Find images\n const imageFiles = await glob('images/**/*', { cwd: webflowDir });\n assets.images = imageFiles;\n\n // Find fonts\n const fontFiles = await glob('fonts/**/*', { cwd: webflowDir });\n assets.fonts = fontFiles;\n\n // Find JS files\n const jsFiles = await glob('js/**/*.js', { cwd: webflowDir });\n assets.js = jsFiles;\n\n return assets;\n}\n\n/**\n * Copy CSS files to assets/css/\n */\nexport async function copyCSSFiles(\n webflowDir: string,\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'assets', 'css');\n await fs.ensureDir(targetDir);\n\n for (const file of cssFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy images to public/assets/images/\n */\nexport async function copyImages(\n webflowDir: string,\n outputDir: string,\n imageFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'images');\n await fs.ensureDir(targetDir);\n\n for (const file of imageFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy fonts to public/assets/fonts/\n */\nexport async function copyFonts(\n webflowDir: string,\n outputDir: string,\n fontFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'fonts');\n await fs.ensureDir(targetDir);\n\n for (const file of fontFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy JS files to public/assets/js/\n */\nexport async function copyJSFiles(\n webflowDir: string,\n outputDir: string,\n jsFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'js');\n await fs.ensureDir(targetDir);\n\n for (const file of jsFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy all assets to their proper locations\n */\nexport async function copyAllAssets(\n webflowDir: string,\n outputDir: string,\n assets: AssetPaths\n): Promise<void> {\n await copyCSSFiles(webflowDir, outputDir, assets.css);\n await copyImages(webflowDir, outputDir, assets.images);\n await copyFonts(webflowDir, outputDir, assets.fonts);\n await copyJSFiles(webflowDir, outputDir, assets.js);\n}\n\n/**\n * Find all HTML files in Webflow export (including subfolders)\n */\nexport async function findHTMLFiles(webflowDir: string): Promise<string[]> {\n // Find all HTML files recursively\n const htmlFiles = await glob('**/*.html', { cwd: webflowDir });\n return htmlFiles;\n}\n\n/**\n * Read HTML file content\n */\nexport async function readHTMLFile(webflowDir: string, fileName: string): Promise<string> {\n const filePath = path.join(webflowDir, fileName);\n return await fs.readFile(filePath, 'utf-8');\n}\n\n/**\n * Write Vue component to pages directory\n * Handles nested paths (e.g., press-release/article.html -> pages/press-release/article.vue)\n */\nexport async function writeVueComponent(\n outputDir: string,\n fileName: string,\n content: string\n): Promise<void> {\n const pagesDir = path.join(outputDir, 'pages');\n \n // Convert HTML path to Vue path\n // e.g., press-release/article.html -> press-release/article.vue\n const vueName = fileName.replace('.html', '.vue');\n const targetPath = path.join(pagesDir, vueName);\n\n // Ensure the directory exists\n await fs.ensureDir(path.dirname(targetPath));\n\n await fs.writeFile(targetPath, content, 'utf-8');\n}\n\n/**\n * Format Vue files with Prettier\n */\nexport async function formatVueFiles(outputDir: string): Promise<void> {\n const pagesDir = path.join(outputDir, 'pages');\n \n try {\n console.log(pc.blue('\\n⨠Formatting Vue files with Prettier...'));\n \n // Check if prettier is available\n execSync('npx prettier --version', { stdio: 'ignore' });\n \n // Format all Vue files in pages directory\n execSync(`npx prettier --write \"${pagesDir}/**/*.vue\"`, { \n cwd: outputDir,\n stdio: 'inherit' \n });\n \n console.log(pc.green(' ā Vue files formatted'));\n } catch (error) {\n console.log(pc.yellow(' ā Prettier not available, skipping formatting'));\n }\n}\n","/**\n * HTML Parser for Webflow exports\n * Handles conversion to Vue/Nuxt format\n */\n\nimport * as cheerio from 'cheerio';\nimport path from 'path';\n\nexport interface ParsedPage {\n fileName: string;\n title: string;\n htmlContent: string;\n cssFiles: string[];\n embeddedStyles: string;\n images: string[];\n links: string[];\n}\n\n/**\n * Normalize a path to absolute format\n * Examples:\n * - index.html -> /\n * - about.html -> /about\n * - ../index.html -> /\n * - press-release/article.html -> /press-release/article\n */\nfunction normalizeRoute(href: string): string {\n // Remove .html extension\n let route = href.replace('.html', '');\n\n // Handle various index patterns\n if (route === 'index' || route === '/index' || route.endsWith('/index')) {\n return '/';\n }\n\n // Handle parent directory references\n if (route === '..' || route === '../' || route === '/..' || route === '../index') {\n return '/';\n }\n\n // Remove all relative path indicators\n route = route.replace(/\\.\\.\\//g, '').replace(/\\.\\//g, '');\n\n // Normalize the path\n const normalized = path.posix.normalize(route);\n\n // Ensure it starts with /\n if (!normalized.startsWith('/')) {\n return '/' + normalized;\n }\n\n // If it became just '.' after normalization, return '/'\n if (normalized === '.' || normalized === '') {\n return '/';\n }\n\n return normalized;\n}\n\n/**\n * Normalize asset path to absolute\n * Examples:\n * - images/logo.svg -> /assets/images/logo.svg\n * - ../images/logo.svg -> /assets/images/logo.svg\n * - /assets/../images/logo.svg -> /assets/images/logo.svg\n */\nfunction normalizeAssetPath(src: string): string {\n if (!src || src.startsWith('http') || src.startsWith('https')) {\n return src;\n }\n\n // Remove any ../ or ./ at the start\n let normalized = src.replace(/^(\\.\\.\\/)+/, '').replace(/^\\.\\//, '');\n\n // If it already starts with /assets/, clean up any ../ in the middle\n if (normalized.startsWith('/assets/')) {\n normalized = normalized.replace(/\\/\\.\\.\\//g, '/');\n return normalized;\n }\n\n // Otherwise, add /assets/ prefix\n return `/assets/${normalized}`;\n}\n\n/**\n * Parse a Webflow HTML file\n */\nexport function parseHTML(html: string, fileName: string): ParsedPage {\n const $ = cheerio.load(html);\n\n // Extract page title\n const title = $('title').text() || fileName.replace('.html', '');\n\n // Find all CSS files\n const cssFiles: string[] = [];\n $('link[rel=\"stylesheet\"]').each((_, el) => {\n const href = $(el).attr('href');\n if (href) {\n cssFiles.push(href);\n }\n });\n\n // Extract embedded styles (from .global-embed or style tags in body)\n let embeddedStyles = '';\n\n // Get styles from .global-embed class\n $('.global-embed style').each((_, el) => {\n embeddedStyles += $(el).html() + '\\n';\n });\n\n // Get style tags before closing body\n $('body > style').each((_, el) => {\n embeddedStyles += $(el).html() + '\\n';\n });\n\n // Remove the global-embed elements and body style tags from DOM\n $('.global-embed').remove();\n $('body > style').remove();\n\n // Remove all script tags from body\n $('body script').remove();\n\n // Get all images for asset mapping\n const images: string[] = [];\n $('img').each((_, el) => {\n const src = $(el).attr('src');\n if (src) {\n images.push(src);\n }\n });\n\n // Get all links\n const links: string[] = [];\n $('a').each((_, el) => {\n const href = $(el).attr('href');\n if (href) {\n links.push(href);\n }\n });\n\n // Get ONLY the body's inner content (not the body tag itself)\n const htmlContent = $('body').html() || '';\n\n return {\n fileName,\n title,\n htmlContent,\n cssFiles,\n embeddedStyles,\n images,\n links,\n };\n}\n\n/**\n * Transform HTML content for Nuxt/Vue\n * - Convert <a> to <NuxtLink>\n * - Fix image paths (add /assets/ prefix for public folder)\n * - Remove any remaining html/head/body tags\n * - Remove srcset and sizes attributes from images\n */\nexport function transformForNuxt(html: string): string {\n const $ = cheerio.load(html);\n\n // Remove any html, head, body tags that might have leaked through\n $('html, head, body').each((_, el) => {\n const $el = $(el);\n $el.replaceWith($el.html() || '');\n });\n\n // Remove all script tags\n $('script').remove();\n\n // 1. Convert <a> tags to <NuxtLink>\n $('a').each((_, el) => {\n const $el = $(el);\n const href = $el.attr('href');\n\n if (!href) return;\n\n // Check if it's an internal link\n const isExternal = href.startsWith('http://') ||\n href.startsWith('https://') ||\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('#');\n\n if (!isExternal) {\n // Normalize the route\n const route = normalizeRoute(href);\n\n $el.attr('to', route);\n $el.removeAttr('href');\n\n // Change tag name to NuxtLink\n const content = $el.html();\n const classes = $el.attr('class') || '';\n\n $el.replaceWith(`<nuxt-link to=\"${route}\" class=\"${classes}\">${content}</nuxt-link>`);\n }\n });\n\n // 2. Fix image paths and remove srcset/sizes\n $('img').each((_, el) => {\n const $el = $(el);\n const src = $el.attr('src');\n\n if (src) {\n // Normalize the asset path\n const normalizedSrc = normalizeAssetPath(src);\n $el.attr('src', normalizedSrc);\n }\n\n // Remove srcset and sizes attributes\n $el.removeAttr('srcset');\n $el.removeAttr('sizes');\n });\n\n // Note: CSS background-image paths are NOT changed here\n // They will be handled by the webflow-assets.ts Vite plugin\n\n return $.html();\n}\n\n/**\n * Convert transformed HTML to Vue component\n */\nexport function htmlToVueComponent(html: string, pageName: string): string {\n return `\n<script setup lang=\"ts\">\n// Page: ${pageName}\n</script>\n\n<template>\n <div>\n ${html}\n </div>\n</template>\n`;\n}\n\n/**\n * Deduplicate styles - remove duplicate CSS rules\n */\nexport function deduplicateStyles(styles: string): string {\n if (!styles.trim()) return '';\n\n // Split by comments that indicate file sources\n const sections = styles.split(/\\/\\* From .+ \\*\\//);\n\n // Keep only unique style content\n const uniqueStyles = new Set<string>();\n\n for (const section of sections) {\n const trimmed = section.trim();\n if (trimmed) {\n uniqueStyles.add(trimmed);\n }\n }\n\n return Array.from(uniqueStyles).join('\\n\\n');\n}\n","/**\n * Utilities to update Nuxt config and generate webflow-assets.ts\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * Generate the webflow-assets.ts Vite plugin\n */\nexport function generateWebflowAssetPlugin(cssFiles: string[]): string {\n // Convert css/normalize.css to /assets/css/normalize.css\n const webflowFiles = cssFiles.map(file => `/assets/css/${path.basename(file)}`);\n\n return `import type { Plugin } from 'vite'\n\nconst webflowFiles = [${webflowFiles.map(f => `'${f}'`).join(', ')}]\nconst replacements = [\n ['../images/', '/assets/images/'],\n ['../fonts/', '/assets/fonts/']\n]\n\nconst webflowURLReset = (): Plugin => ({\n name: 'webflowURLReset',\n config: () => ({\n build: {\n rollupOptions: {\n external: [/\\\\.\\\\.\\\\/fonts\\\\//, /\\\\.\\\\.\\\\/images\\\\//]\n }\n }\n }),\n transform: (code, id) => {\n if (webflowFiles.some((path) => id.includes(path))) {\n replacements.forEach(([search, replace]) => {\n code = code.replaceAll(search, replace)\n })\n }\n\n return { code, id, map: null }\n }\n})\n\nexport default webflowURLReset\n`;\n}\n\n/**\n * Write webflow-assets.ts to utils folder (overwrites existing)\n */\nexport async function writeWebflowAssetPlugin(\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const utilsDir = path.join(outputDir, 'utils');\n await fs.ensureDir(utilsDir);\n\n const content = generateWebflowAssetPlugin(cssFiles);\n const targetPath = path.join(utilsDir, 'webflow-assets.ts');\n\n // This will overwrite if it exists\n await fs.writeFile(targetPath, content, 'utf-8');\n}\n\n/**\n * Update nuxt.config.ts to add CSS files\n */\nexport async function updateNuxtConfig(\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const configPath = path.join(outputDir, 'nuxt.config.ts');\n\n // Check if config exists\n const configExists = await fs.pathExists(configPath);\n if (!configExists) {\n throw new Error('nuxt.config.ts not found in output directory');\n }\n\n // Read existing config\n let config = await fs.readFile(configPath, 'utf-8');\n\n // Generate CSS array entries\n const cssEntries = cssFiles.map(file => ` '~/assets/css/${path.basename(file)}'`);\n\n // Check if css array exists\n if (config.includes('css:')) {\n // Find the css array and add our files\n // This is a simple approach - we'll add them at the end of the array\n config = config.replace(\n /css:\\s*\\[/,\n `css: [\\n${cssEntries.join(',\\n')},`\n );\n } else {\n // Add css array to the config\n // Find the export default defineNuxtConfig({\n config = config.replace(\n /export default defineNuxtConfig\\(\\{/,\n `export default defineNuxtConfig({\\n css: [\\n${cssEntries.join(',\\n')}\\n ],`\n );\n }\n\n // Write updated config\n await fs.writeFile(configPath, config, 'utf-8');\n}\n\n/**\n * Write embedded styles to main.css\n */\nexport async function writeEmbeddedStyles(\n outputDir: string,\n styles: string\n): Promise<void> {\n if (!styles.trim()) return;\n\n const cssDir = path.join(outputDir, 'assets', 'css');\n await fs.ensureDir(cssDir);\n\n const mainCssPath = path.join(cssDir, 'main.css');\n\n // Check if main.css exists\n const exists = await fs.pathExists(mainCssPath);\n\n if (exists) {\n // Append to existing main.css\n const existing = await fs.readFile(mainCssPath, 'utf-8');\n await fs.writeFile(mainCssPath, `${existing}\\n\\n/* Webflow Embedded Styles */\\n${styles}`, 'utf-8');\n } else {\n // Create new main.css\n await fs.writeFile(mainCssPath, `/* Webflow Embedded Styles */\\n${styles}`, 'utf-8');\n }\n}\n","/**\n * Boilerplate cloning and setup utilities\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { execSync } from 'child_process';\nimport pc from 'picocolors';\n\n/**\n * Check if a string is a GitHub URL\n */\nfunction isGitHubURL(source: string): boolean {\n return source.startsWith('https://github.com/') || \n source.startsWith('git@github.com:') ||\n source.includes('github.com');\n}\n\n/**\n * Clone a GitHub repository\n */\nasync function cloneFromGitHub(repoUrl: string, outputDir: string): Promise<void> {\n console.log(pc.blue(' Cloning from GitHub...'));\n \n try {\n // Clone the repo\n execSync(`git clone ${repoUrl} ${outputDir}`, { stdio: 'inherit' });\n \n // Remove .git directory to start fresh\n const gitDir = path.join(outputDir, '.git');\n await fs.remove(gitDir);\n \n console.log(pc.green(' ā Boilerplate cloned successfully'));\n } catch (error) {\n throw new Error(`Failed to clone repository: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * Copy from local directory\n */\nasync function copyFromLocal(sourcePath: string, outputDir: string): Promise<void> {\n console.log(pc.blue(' Copying from local path...'));\n \n const sourceExists = await fs.pathExists(sourcePath);\n if (!sourceExists) {\n throw new Error(`Local boilerplate not found: ${sourcePath}`);\n }\n \n // Copy everything except node_modules, .nuxt, .output, .git\n await fs.copy(sourcePath, outputDir, {\n filter: (src) => {\n const name = path.basename(src);\n return !['node_modules', '.nuxt', '.output', '.git', 'dist'].includes(name);\n },\n });\n \n console.log(pc.green(' ā Boilerplate copied successfully'));\n}\n\n/**\n * Setup boilerplate in output directory\n */\nexport async function setupBoilerplate(\n boilerplateSource: string | undefined,\n outputDir: string\n): Promise<void> {\n if (!boilerplateSource) {\n // No boilerplate specified - create minimal structure\n console.log(pc.blue('\\nš¦ Creating minimal Nuxt structure...'));\n await fs.ensureDir(outputDir);\n await fs.ensureDir(path.join(outputDir, 'pages'));\n await fs.ensureDir(path.join(outputDir, 'assets'));\n await fs.ensureDir(path.join(outputDir, 'public'));\n await fs.ensureDir(path.join(outputDir, 'utils'));\n \n // Create a basic nuxt.config.ts if it doesn't exist\n const configPath = path.join(outputDir, 'nuxt.config.ts');\n const configExists = await fs.pathExists(configPath);\n \n if (!configExists) {\n const basicConfig = `export default defineNuxtConfig({\n devtools: { enabled: true },\n css: [],\n})\n`;\n await fs.writeFile(configPath, basicConfig, 'utf-8');\n }\n \n console.log(pc.green(' ā Structure created'));\n return;\n }\n\n // Check if output directory already exists\n const outputExists = await fs.pathExists(outputDir);\n if (outputExists) {\n throw new Error(`Output directory already exists: ${outputDir}. Please choose a different path or remove it first.`);\n }\n\n console.log(pc.blue('\\nš¦ Setting up boilerplate...'));\n\n if (isGitHubURL(boilerplateSource)) {\n await cloneFromGitHub(boilerplateSource, outputDir);\n } else {\n await copyFromLocal(boilerplateSource, outputDir);\n }\n}\n"],"mappings":"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","names":["pc","pc","fs","path","fs","path","fs","path","execSync","pc","pc","fs","pc"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/converter.ts","../src/filesystem.ts","../src/parser.ts","../src/config-updater.ts","../src/editor-integration.ts","../src/boilerplate.ts","../src/manifest.ts","../src/detector.ts","../src/transformer.ts","../src/schema-writer.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI for @see-ms/converter\n * Usage: cms convert <input-dir> <output-dir> [options]\n */\n\nimport { Command } from 'commander';\nimport pc from 'picocolors';\nimport { convertWebflowExport } from './converter';\n\nconst program = new Command();\n\nprogram\n .name('cms')\n .description('SeeMS - Webflow to CMS converter')\n .version('0.1.0');\n\nprogram\n .command('convert')\n .description('Convert Webflow export to Nuxt 3 project')\n .argument('<input>', 'Path to Webflow export directory')\n .argument('<output>', 'Path to output Nuxt project directory')\n .option('-b, --boilerplate <source>', 'Boilerplate source (GitHub URL or local path)')\n .option('-o, --overrides <path>', 'Path to overrides JSON file')\n .option('--generate-schemas', 'Generate CMS schemas immediately')\n .option('--cms <type>', 'CMS backend type (strapi|contentful|sanity)', 'strapi')\n .action(async (input, output, options) => {\n try {\n await convertWebflowExport({\n inputDir: input,\n outputDir: output,\n boilerplate: options.boilerplate,\n overridesPath: options.overrides,\n generateStrapi: options.generateSchemas,\n cmsBackend: options.cms,\n });\n } catch (error) {\n console.error(pc.red('Conversion failed'));\n process.exit(1);\n }\n });\n\nprogram\n .command('generate')\n .description('Generate CMS schemas from manifest')\n .argument('<manifest>', 'Path to cms-manifest.json')\n .option('-t, --type <cms>', 'CMS type (strapi|contentful|sanity)', 'strapi')\n .option('-o, --output <dir>', 'Output directory for schemas')\n .action(async (manifest, _options) => {\n console.log(pc.cyan('šļø SeeMS Schema Generator'));\n console.log(pc.dim(`Generating schemas from: ${manifest}`));\n \n // TODO: Implementation in Sprint 3\n console.log(pc.yellow('ā ļø Schema generation logic to be implemented'));\n });\n\nprogram.parse();\n","/**\n * Main conversion logic\n */\n\nimport type { ConversionOptions } from '@see-ms/types';\nimport pc from 'picocolors';\nimport path from 'path';\nimport fs from 'fs-extra';\nimport {\n scanAssets,\n copyAllAssets,\n findHTMLFiles,\n readHTMLFile,\n writeVueComponent,\n formatVueFiles,\n} from './filesystem';\nimport { parseHTML, transformForNuxt, htmlToVueComponent, deduplicateStyles } from './parser';\nimport {\n writeWebflowAssetPlugin,\n updateNuxtConfig,\n writeEmbeddedStyles,\n} from './config-updater';\nimport { createEditorPlugin, addEditorDependency, createSaveEndpoint } from './editor-integration';\nimport { setupBoilerplate } from './boilerplate';\nimport { generateManifest, writeManifest } from './manifest';\nimport { manifestToSchemas } from './transformer';\nimport { writeAllSchemas, createStrapiReadme } from './schema-writer';\n\nexport async function convertWebflowExport(options: ConversionOptions): Promise<void> {\n const { inputDir, outputDir, boilerplate } = options;\n\n console.log(pc.cyan('š Starting Webflow to Nuxt conversion...'));\n console.log(pc.dim(`Input: ${inputDir}`));\n console.log(pc.dim(`Output: ${outputDir}`));\n\n try {\n // Step 0: Setup boilerplate first\n await setupBoilerplate(boilerplate, outputDir);\n\n // Step 1: Verify input directory exists\n const inputExists = await fs.pathExists(inputDir);\n if (!inputExists) {\n throw new Error(`Input directory not found: ${inputDir}`);\n }\n\n // Step 2: Scan for assets\n console.log(pc.blue('\\nš Scanning assets...'));\n const assets = await scanAssets(inputDir);\n console.log(pc.green(` ā Found ${assets.css.length} CSS files`));\n console.log(pc.green(` ā Found ${assets.images.length} images`));\n console.log(pc.green(` ā Found ${assets.fonts.length} fonts`));\n console.log(pc.green(` ā Found ${assets.js.length} JS files`));\n\n // Step 3: Copy assets to output\n console.log(pc.blue('\\nš¦ Copying assets...'));\n await copyAllAssets(inputDir, outputDir, assets);\n console.log(pc.green(' ā Assets copied successfully'));\n\n // Step 4: Find all HTML files (including in subfolders)\n console.log(pc.blue('\\nš Finding HTML files...'));\n const htmlFiles = await findHTMLFiles(inputDir);\n console.log(pc.green(` ā Found ${htmlFiles.length} HTML files`));\n\n // Step 5: Convert HTML files to Vue components\n console.log(pc.blue('\\nāļø Converting HTML to Vue components...'));\n let allEmbeddedStyles = '';\n\n for (const htmlFile of htmlFiles) {\n const html = await readHTMLFile(inputDir, htmlFile);\n const parsed = parseHTML(html, htmlFile);\n\n // Collect embedded styles\n if (parsed.embeddedStyles) {\n allEmbeddedStyles += `\\n/* From ${htmlFile} */\\n${parsed.embeddedStyles}\\n`;\n }\n\n // Transform HTML for Nuxt\n const transformed = transformForNuxt(parsed.htmlContent);\n\n // Convert to Vue component\n const pageName = htmlFile.replace('.html', '').replace(/\\//g, '-');\n const vueComponent = htmlToVueComponent(transformed, pageName);\n\n // Write to pages directory (this will overwrite existing files)\n await writeVueComponent(outputDir, htmlFile, vueComponent);\n console.log(pc.green(` ā Created ${htmlFile.replace('.html', '.vue')}`));\n }\n\n // Step 6: Format Vue files with Prettier\n await formatVueFiles(outputDir);\n\n // Step 7: Generate CMS manifest\n console.log(pc.blue('\\nš Analyzing pages for CMS fields...'));\n const pagesDir = path.join(outputDir, 'pages');\n const manifest = await generateManifest(pagesDir);\n await writeManifest(outputDir, manifest);\n\n const totalFields = Object.values(manifest.pages).reduce(\n (sum, page) => sum + Object.keys(page.fields || {}).length,\n 0\n );\n const totalCollections = Object.values(manifest.pages).reduce(\n (sum, page) => sum + Object.keys(page.collections || {}).length,\n 0\n );\n\n console.log(pc.green(` ā Detected ${totalFields} fields across ${Object.keys(manifest.pages).length} pages`));\n console.log(pc.green(` ā Detected ${totalCollections} collections`));\n console.log(pc.green(' ā Generated cms-manifest.json'));\n\n // Step 8: Generate Strapi schemas\n console.log(pc.blue('\\nš Generating Strapi schemas...'));\n const schemas = manifestToSchemas(manifest);\n await writeAllSchemas(outputDir, schemas);\n await createStrapiReadme(outputDir);\n\n console.log(pc.green(` ā Generated ${Object.keys(schemas).length} Strapi content types`));\n console.log(pc.dim(' View schemas in: strapi/src/api/'));\n\n // Step 9: Deduplicate and write embedded styles to main.css\n if (allEmbeddedStyles.trim()) {\n console.log(pc.blue('\\n⨠Writing embedded styles...'));\n const dedupedStyles = deduplicateStyles(allEmbeddedStyles);\n await writeEmbeddedStyles(outputDir, dedupedStyles);\n console.log(pc.green(' ā Embedded styles added to main.css'));\n }\n\n // Step 10: Generate/overwrite webflow-assets.ts\n console.log(pc.blue('\\nš§ Generating webflow-assets.ts plugin...'));\n await writeWebflowAssetPlugin(outputDir, assets.css);\n console.log(pc.green(' ā Plugin generated (existing file overwritten)'));\n\n // Step 11: Update nuxt.config.ts\n console.log(pc.blue('\\nāļø Updating nuxt.config.ts...'));\n try {\n await updateNuxtConfig(outputDir, assets.css);\n console.log(pc.green(' ā Config updated'));\n } catch (error) {\n console.log(pc.yellow(' ā Could not update nuxt.config.ts automatically'));\n console.log(pc.dim(' Please add CSS files manually'));\n }\n\n console.log(pc.blue('\\nšØ Setting up editor overlay...'));\n await createEditorPlugin(outputDir);\n await addEditorDependency(outputDir);\n await createSaveEndpoint(outputDir);\n console.log(pc.green(' ā Editor plugin created'));\n console.log(pc.green(' ā Editor dependency added'));\n console.log(pc.green(' ā Save endpoint created'));\n\n // Success!\n console.log(pc.green('\\nā
Conversion completed successfully!'));\n console.log(pc.cyan('\\nš Next steps:'));\n console.log(pc.dim(` 1. cd ${outputDir}`));\n console.log(pc.dim(' 2. Review cms-manifest.json'));\n console.log(pc.dim(' 3. Copy strapi/ schemas to your Strapi project'));\n console.log(pc.dim(' 4. pnpm install && pnpm dev'));\n console.log(pc.dim(' 5. Visit http://localhost:3000?preview=true to edit inline!'));\n\n } catch (error) {\n console.error(pc.red('\\nā Conversion failed:'));\n console.error(pc.red(error instanceof Error ? error.message : String(error)));\n throw error;\n }\n}\n","/**\n * File system utilities for copying Webflow assets\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport { execSync } from 'child_process';\nimport pc from 'picocolors';\n\nexport interface AssetPaths {\n css: string[]; // Goes to assets/css/\n images: string[]; // Goes to public/assets/images/\n fonts: string[]; // Goes to public/assets/fonts/\n js: string[]; // Goes to public/assets/js/\n}\n\n/**\n * Scan Webflow export directory for assets\n */\nexport async function scanAssets(webflowDir: string): Promise<AssetPaths> {\n const assets: AssetPaths = {\n css: [],\n images: [],\n fonts: [],\n js: [],\n };\n\n // Find CSS files\n const cssFiles = await glob('css/**/*.css', { cwd: webflowDir });\n assets.css = cssFiles;\n\n // Find images\n const imageFiles = await glob('images/**/*', { cwd: webflowDir });\n assets.images = imageFiles;\n\n // Find fonts\n const fontFiles = await glob('fonts/**/*', { cwd: webflowDir });\n assets.fonts = fontFiles;\n\n // Find JS files\n const jsFiles = await glob('js/**/*.js', { cwd: webflowDir });\n assets.js = jsFiles;\n\n return assets;\n}\n\n/**\n * Copy CSS files to assets/css/\n */\nexport async function copyCSSFiles(\n webflowDir: string,\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'assets', 'css');\n await fs.ensureDir(targetDir);\n\n for (const file of cssFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy images to public/assets/images/\n */\nexport async function copyImages(\n webflowDir: string,\n outputDir: string,\n imageFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'images');\n await fs.ensureDir(targetDir);\n\n for (const file of imageFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy fonts to public/assets/fonts/\n */\nexport async function copyFonts(\n webflowDir: string,\n outputDir: string,\n fontFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'fonts');\n await fs.ensureDir(targetDir);\n\n for (const file of fontFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy JS files to public/assets/js/\n */\nexport async function copyJSFiles(\n webflowDir: string,\n outputDir: string,\n jsFiles: string[]\n): Promise<void> {\n const targetDir = path.join(outputDir, 'public', 'assets', 'js');\n await fs.ensureDir(targetDir);\n\n for (const file of jsFiles) {\n const source = path.join(webflowDir, file);\n const target = path.join(targetDir, path.basename(file));\n await fs.copy(source, target);\n }\n}\n\n/**\n * Copy all assets to their proper locations\n */\nexport async function copyAllAssets(\n webflowDir: string,\n outputDir: string,\n assets: AssetPaths\n): Promise<void> {\n await copyCSSFiles(webflowDir, outputDir, assets.css);\n await copyImages(webflowDir, outputDir, assets.images);\n await copyFonts(webflowDir, outputDir, assets.fonts);\n await copyJSFiles(webflowDir, outputDir, assets.js);\n}\n\n/**\n * Find all HTML files in Webflow export (including subfolders)\n */\nexport async function findHTMLFiles(webflowDir: string): Promise<string[]> {\n // Find all HTML files recursively\n const htmlFiles = await glob('**/*.html', { cwd: webflowDir });\n return htmlFiles;\n}\n\n/**\n * Read HTML file content\n */\nexport async function readHTMLFile(webflowDir: string, fileName: string): Promise<string> {\n const filePath = path.join(webflowDir, fileName);\n return await fs.readFile(filePath, 'utf-8');\n}\n\n/**\n * Write Vue component to pages directory\n * Handles nested paths (e.g., press-release/article.html -> pages/press-release/article.vue)\n */\nexport async function writeVueComponent(\n outputDir: string,\n fileName: string,\n content: string\n): Promise<void> {\n const pagesDir = path.join(outputDir, 'pages');\n \n // Convert HTML path to Vue path\n // e.g., press-release/article.html -> press-release/article.vue\n const vueName = fileName.replace('.html', '.vue');\n const targetPath = path.join(pagesDir, vueName);\n\n // Ensure the directory exists\n await fs.ensureDir(path.dirname(targetPath));\n\n await fs.writeFile(targetPath, content, 'utf-8');\n}\n\n/**\n * Format Vue files with Prettier\n */\nexport async function formatVueFiles(outputDir: string): Promise<void> {\n const pagesDir = path.join(outputDir, 'pages');\n \n try {\n console.log(pc.blue('\\n⨠Formatting Vue files with Prettier...'));\n \n // Check if prettier is available\n execSync('npx prettier --version', { stdio: 'ignore' });\n \n // Format all Vue files in pages directory\n execSync(`npx prettier --write \"${pagesDir}/**/*.vue\"`, { \n cwd: outputDir,\n stdio: 'inherit' \n });\n \n console.log(pc.green(' ā Vue files formatted'));\n } catch (error) {\n console.log(pc.yellow(' ā Prettier not available, skipping formatting'));\n }\n}\n","/**\n * HTML Parser for Webflow exports\n * Handles conversion to Vue/Nuxt format\n */\n\nimport * as cheerio from 'cheerio';\nimport path from 'path';\n\nexport interface ParsedPage {\n fileName: string;\n title: string;\n htmlContent: string;\n cssFiles: string[];\n embeddedStyles: string;\n images: string[];\n links: string[];\n}\n\n/**\n * Normalize a path to absolute format\n * Examples:\n * - index.html -> /\n * - about.html -> /about\n * - ../index.html -> /\n * - press-release/article.html -> /press-release/article\n */\nfunction normalizeRoute(href: string): string {\n // Remove .html extension\n let route = href.replace('.html', '');\n\n // Handle various index patterns\n if (route === 'index' || route === '/index' || route.endsWith('/index')) {\n return '/';\n }\n\n // Handle parent directory references\n if (route === '..' || route === '../' || route === '/..' || route === '../index') {\n return '/';\n }\n\n // Remove all relative path indicators\n route = route.replace(/\\.\\.\\//g, '').replace(/\\.\\//g, '');\n\n // Normalize the path\n const normalized = path.posix.normalize(route);\n\n // Ensure it starts with /\n if (!normalized.startsWith('/')) {\n return '/' + normalized;\n }\n\n // If it became just '.' after normalization, return '/'\n if (normalized === '.' || normalized === '') {\n return '/';\n }\n\n return normalized;\n}\n\n/**\n * Normalize asset path to absolute\n * Examples:\n * - images/logo.svg -> /assets/images/logo.svg\n * - ../images/logo.svg -> /assets/images/logo.svg\n * - /assets/../images/logo.svg -> /assets/images/logo.svg\n */\nfunction normalizeAssetPath(src: string): string {\n if (!src || src.startsWith('http') || src.startsWith('https')) {\n return src;\n }\n\n // Remove any ../ or ./ at the start\n let normalized = src.replace(/^(\\.\\.\\/)+/, '').replace(/^\\.\\//, '');\n\n // If it already starts with /assets/, clean up any ../ in the middle\n if (normalized.startsWith('/assets/')) {\n normalized = normalized.replace(/\\/\\.\\.\\//g, '/');\n return normalized;\n }\n\n // Otherwise, add /assets/ prefix\n return `/assets/${normalized}`;\n}\n\n/**\n * Parse a Webflow HTML file\n */\nexport function parseHTML(html: string, fileName: string): ParsedPage {\n const $ = cheerio.load(html);\n\n // Extract page title\n const title = $('title').text() || fileName.replace('.html', '');\n\n // Find all CSS files\n const cssFiles: string[] = [];\n $('link[rel=\"stylesheet\"]').each((_, el) => {\n const href = $(el).attr('href');\n if (href) {\n cssFiles.push(href);\n }\n });\n\n // Extract embedded styles (from .global-embed or style tags in body)\n let embeddedStyles = '';\n\n // Get styles from .global-embed class\n $('.global-embed style').each((_, el) => {\n embeddedStyles += $(el).html() + '\\n';\n });\n\n // Get style tags before closing body\n $('body > style').each((_, el) => {\n embeddedStyles += $(el).html() + '\\n';\n });\n\n // Remove the global-embed elements and body style tags from DOM\n $('.global-embed').remove();\n $('body > style').remove();\n\n // Remove all script tags from body\n $('body script').remove();\n\n // Get all images for asset mapping\n const images: string[] = [];\n $('img').each((_, el) => {\n const src = $(el).attr('src');\n if (src) {\n images.push(src);\n }\n });\n\n // Get all links\n const links: string[] = [];\n $('a').each((_, el) => {\n const href = $(el).attr('href');\n if (href) {\n links.push(href);\n }\n });\n\n // Get ONLY the body's inner content (not the body tag itself)\n const htmlContent = $('body').html() || '';\n\n return {\n fileName,\n title,\n htmlContent,\n cssFiles,\n embeddedStyles,\n images,\n links,\n };\n}\n\n/**\n * Transform HTML content for Nuxt/Vue\n * - Convert <a> to <NuxtLink>\n * - Fix image paths (add /assets/ prefix for public folder)\n * - Remove any remaining html/head/body tags\n * - Remove srcset and sizes attributes from images\n */\nexport function transformForNuxt(html: string): string {\n const $ = cheerio.load(html);\n\n // Remove any html, head, body tags that might have leaked through\n $('html, head, body').each((_, el) => {\n const $el = $(el);\n $el.replaceWith($el.html() || '');\n });\n\n // Remove all script tags\n $('script').remove();\n\n // 1. Convert <a> tags to <NuxtLink>\n $('a').each((_, el) => {\n const $el = $(el);\n const href = $el.attr('href');\n\n if (!href) return;\n\n // Check if it's an internal link\n const isExternal = href.startsWith('http://') ||\n href.startsWith('https://') ||\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('#');\n\n if (!isExternal) {\n // Normalize the route\n const route = normalizeRoute(href);\n\n $el.attr('to', route);\n $el.removeAttr('href');\n\n // Change tag name to NuxtLink\n const content = $el.html();\n const classes = $el.attr('class') || '';\n\n $el.replaceWith(`<nuxt-link to=\"${route}\" class=\"${classes}\">${content}</nuxt-link>`);\n }\n });\n\n // 2. Fix image paths and remove srcset/sizes\n $('img').each((_, el) => {\n const $el = $(el);\n const src = $el.attr('src');\n\n if (src) {\n // Normalize the asset path\n const normalizedSrc = normalizeAssetPath(src);\n $el.attr('src', normalizedSrc);\n }\n\n // Remove srcset and sizes attributes\n $el.removeAttr('srcset');\n $el.removeAttr('sizes');\n });\n\n // Note: CSS background-image paths are NOT changed here\n // They will be handled by the webflow-assets.ts Vite plugin\n\n return $.html();\n}\n\n/**\n * Convert transformed HTML to Vue component\n */\nexport function htmlToVueComponent(html: string, pageName: string): string {\n return `\n<script setup lang=\"ts\">\n// Page: ${pageName}\n</script>\n\n<template>\n <div>\n ${html}\n </div>\n</template>\n`;\n}\n\n/**\n * Deduplicate styles - remove duplicate CSS rules\n */\nexport function deduplicateStyles(styles: string): string {\n if (!styles.trim()) return '';\n\n // Split by comments that indicate file sources\n const sections = styles.split(/\\/\\* From .+ \\*\\//);\n\n // Keep only unique style content\n const uniqueStyles = new Set<string>();\n\n for (const section of sections) {\n const trimmed = section.trim();\n if (trimmed) {\n uniqueStyles.add(trimmed);\n }\n }\n\n return Array.from(uniqueStyles).join('\\n\\n');\n}\n","/**\n * Utilities to update Nuxt config and generate webflow-assets.ts\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * Generate the webflow-assets.ts Vite plugin\n */\nexport function generateWebflowAssetPlugin(cssFiles: string[]): string {\n // Convert css/normalize.css to /assets/css/normalize.css\n const webflowFiles = cssFiles.map(file => `/assets/css/${path.basename(file)}`);\n\n return `import type { Plugin } from 'vite'\n\nconst webflowFiles = [${webflowFiles.map(f => `'${f}'`).join(', ')}]\nconst replacements = [\n ['../images/', '/assets/images/'],\n ['../fonts/', '/assets/fonts/']\n]\n\nconst webflowURLReset = (): Plugin => ({\n name: 'webflowURLReset',\n config: () => ({\n build: {\n rollupOptions: {\n external: [/\\\\.\\\\.\\\\/fonts\\\\//, /\\\\.\\\\.\\\\/images\\\\//]\n }\n }\n }),\n transform: (code, id) => {\n if (webflowFiles.some((path) => id.includes(path))) {\n replacements.forEach(([search, replace]) => {\n code = code.replaceAll(search, replace)\n })\n }\n\n return { code, id, map: null }\n }\n})\n\nexport default webflowURLReset\n`;\n}\n\n/**\n * Write webflow-assets.ts to utils folder (overwrites existing)\n */\nexport async function writeWebflowAssetPlugin(\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const utilsDir = path.join(outputDir, 'utils');\n await fs.ensureDir(utilsDir);\n\n const content = generateWebflowAssetPlugin(cssFiles);\n const targetPath = path.join(utilsDir, 'webflow-assets.ts');\n\n // This will overwrite if it exists\n await fs.writeFile(targetPath, content, 'utf-8');\n}\n\n/**\n * Update nuxt.config.ts to add CSS files\n */\nexport async function updateNuxtConfig(\n outputDir: string,\n cssFiles: string[]\n): Promise<void> {\n const configPath = path.join(outputDir, 'nuxt.config.ts');\n\n // Check if config exists\n const configExists = await fs.pathExists(configPath);\n if (!configExists) {\n throw new Error('nuxt.config.ts not found in output directory');\n }\n\n // Read existing config\n let config = await fs.readFile(configPath, 'utf-8');\n\n // Generate CSS array entries\n const cssEntries = cssFiles.map(file => ` '~/assets/css/${path.basename(file)}'`);\n\n // Check if css array exists\n if (config.includes('css:')) {\n // Find the css array and add our files\n // This is a simple approach - we'll add them at the end of the array\n config = config.replace(\n /css:\\s*\\[/,\n `css: [\\n${cssEntries.join(',\\n')},`\n );\n } else {\n // Add css array to the config\n // Find the export default defineNuxtConfig({\n config = config.replace(\n /export default defineNuxtConfig\\(\\{/,\n `export default defineNuxtConfig({\\n css: [\\n${cssEntries.join(',\\n')}\\n ],`\n );\n }\n\n // Write updated config\n await fs.writeFile(configPath, config, 'utf-8');\n}\n\n/**\n * Write embedded styles to main.css\n */\nexport async function writeEmbeddedStyles(\n outputDir: string,\n styles: string\n): Promise<void> {\n if (!styles.trim()) return;\n\n const cssDir = path.join(outputDir, 'assets', 'css');\n await fs.ensureDir(cssDir);\n\n const mainCssPath = path.join(cssDir, 'main.css');\n\n // Check if main.css exists\n const exists = await fs.pathExists(mainCssPath);\n\n if (exists) {\n // Append to existing main.css\n const existing = await fs.readFile(mainCssPath, 'utf-8');\n await fs.writeFile(mainCssPath, `${existing}\\n\\n/* Webflow Embedded Styles */\\n${styles}`, 'utf-8');\n } else {\n // Create new main.css\n await fs.writeFile(mainCssPath, `/* Webflow Embedded Styles */\\n${styles}`, 'utf-8');\n }\n}\n","/**\n * Integrate editor overlay into Nuxt projects\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * Create a Nuxt plugin to load the editor overlay\n */\nexport async function createEditorPlugin(outputDir: string): Promise<void> {\n const pluginsDir = path.join(outputDir, 'plugins');\n await fs.ensureDir(pluginsDir);\n\n const pluginContent = `/**\n * CMS Editor Overlay Plugin\n * Loads the inline editor when ?preview=true\n */\n\nexport default defineNuxtPlugin(() => {\n // Only run on client side\n if (process.server) return;\n \n // Check for preview mode\n const params = new URLSearchParams(window.location.search);\n \n if (params.get('preview') === 'true') {\n // Dynamically import the editor\n import('@see-ms/editor-overlay').then(({ initEditor, createToolbar }) => {\n const editor = initEditor({\n apiEndpoint: '/api/cms/save',\n richText: true,\n });\n \n editor.enable();\n \n const toolbar = createToolbar(editor);\n document.body.appendChild(toolbar);\n });\n }\n});\n`;\n\n const pluginPath = path.join(pluginsDir, 'cms-editor.client.ts');\n await fs.writeFile(pluginPath, pluginContent, 'utf-8');\n}\n\n/**\n * Add editor overlay as a dependency\n */\nexport async function addEditorDependency(outputDir: string): Promise<void> {\n const packageJsonPath = path.join(outputDir, 'package.json');\n\n if (await fs.pathExists(packageJsonPath)) {\n const packageJson = await fs.readJson(packageJsonPath);\n\n if (!packageJson.dependencies) {\n packageJson.dependencies = {};\n }\n\n packageJson.dependencies['@see-ms/editor-overlay'] = '^0.1.1';\n\n await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });\n }\n}\n\n/**\n * Create API endpoint for saving changes\n */\nexport async function createSaveEndpoint(outputDir: string): Promise<void> {\n const serverDir = path.join(outputDir, 'server', 'api', 'cms');\n await fs.ensureDir(serverDir);\n\n const endpointContent = `/**\n * API endpoint for saving CMS changes\n */\n\nexport default defineEventHandler(async (event) => {\n const body = await readBody(event);\n \n // TODO: Implement actual saving to Strapi\n // For now, just log the changes\n console.log('CMS changes:', body);\n \n // In production, this would:\n // 1. Validate the changes\n // 2. Send to Strapi API\n // 3. Return success/error\n \n return {\n success: true,\n message: 'Changes saved (demo mode)',\n };\n});\n`;\n\n const endpointPath = path.join(serverDir, 'save.post.ts');\n await fs.writeFile(endpointPath, endpointContent, 'utf-8');\n}\n","/**\n * Boilerplate cloning and setup utilities\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { execSync } from 'child_process';\nimport pc from 'picocolors';\n\n/**\n * Check if a string is a GitHub URL\n */\nfunction isGitHubURL(source: string): boolean {\n return source.startsWith('https://github.com/') || \n source.startsWith('git@github.com:') ||\n source.includes('github.com');\n}\n\n/**\n * Clone a GitHub repository\n */\nasync function cloneFromGitHub(repoUrl: string, outputDir: string): Promise<void> {\n console.log(pc.blue(' Cloning from GitHub...'));\n \n try {\n // Clone the repo\n execSync(`git clone ${repoUrl} ${outputDir}`, { stdio: 'inherit' });\n \n // Remove .git directory to start fresh\n const gitDir = path.join(outputDir, '.git');\n await fs.remove(gitDir);\n \n console.log(pc.green(' ā Boilerplate cloned successfully'));\n } catch (error) {\n throw new Error(`Failed to clone repository: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * Copy from local directory\n */\nasync function copyFromLocal(sourcePath: string, outputDir: string): Promise<void> {\n console.log(pc.blue(' Copying from local path...'));\n \n const sourceExists = await fs.pathExists(sourcePath);\n if (!sourceExists) {\n throw new Error(`Local boilerplate not found: ${sourcePath}`);\n }\n \n // Copy everything except node_modules, .nuxt, .output, .git\n await fs.copy(sourcePath, outputDir, {\n filter: (src) => {\n const name = path.basename(src);\n return !['node_modules', '.nuxt', '.output', '.git', 'dist'].includes(name);\n },\n });\n \n console.log(pc.green(' ā Boilerplate copied successfully'));\n}\n\n/**\n * Setup boilerplate in output directory\n */\nexport async function setupBoilerplate(\n boilerplateSource: string | undefined,\n outputDir: string\n): Promise<void> {\n if (!boilerplateSource) {\n // No boilerplate specified - create minimal structure\n console.log(pc.blue('\\nš¦ Creating minimal Nuxt structure...'));\n await fs.ensureDir(outputDir);\n await fs.ensureDir(path.join(outputDir, 'pages'));\n await fs.ensureDir(path.join(outputDir, 'assets'));\n await fs.ensureDir(path.join(outputDir, 'public'));\n await fs.ensureDir(path.join(outputDir, 'utils'));\n \n // Create a basic nuxt.config.ts if it doesn't exist\n const configPath = path.join(outputDir, 'nuxt.config.ts');\n const configExists = await fs.pathExists(configPath);\n \n if (!configExists) {\n const basicConfig = `export default defineNuxtConfig({\n devtools: { enabled: true },\n css: [],\n})\n`;\n await fs.writeFile(configPath, basicConfig, 'utf-8');\n }\n \n console.log(pc.green(' ā Structure created'));\n return;\n }\n\n // Check if output directory already exists\n const outputExists = await fs.pathExists(outputDir);\n if (outputExists) {\n throw new Error(`Output directory already exists: ${outputDir}. Please choose a different path or remove it first.`);\n }\n\n console.log(pc.blue('\\nš¦ Setting up boilerplate...'));\n\n if (isGitHubURL(boilerplateSource)) {\n await cloneFromGitHub(boilerplateSource, outputDir);\n } else {\n await copyFromLocal(boilerplateSource, outputDir);\n }\n}\n","/**\n * Manifest generation\n */\n\nimport type { CMSManifest, PageManifest } from '@see-ms/types';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { analyzeVuePages } from './detector';\n\n/**\n * Generate CMS manifest from analyzed pages\n */\nexport async function generateManifest(pagesDir: string): Promise<CMSManifest> {\n // Analyze all Vue pages\n const analyzed = await analyzeVuePages(pagesDir);\n\n // Build the manifest\n const pages: Record<string, PageManifest> = {};\n\n for (const [pageName, detection] of Object.entries(analyzed)) {\n pages[pageName] = {\n fields: detection.fields,\n collections: detection.collections,\n meta: {\n route: pageName === 'index' ? '/' : `/${pageName}`,\n },\n };\n }\n\n const manifest: CMSManifest = {\n version: '1.0',\n pages,\n };\n\n return manifest;\n}\n\n/**\n * Write manifest to file\n */\nexport async function writeManifest(\n outputDir: string,\n manifest: CMSManifest\n): Promise<void> {\n const manifestPath = path.join(outputDir, 'cms-manifest.json');\n await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n}\n\n/**\n * Read manifest from file\n */\nexport async function readManifest(outputDir: string): Promise<CMSManifest> {\n const manifestPath = path.join(outputDir, 'cms-manifest.json');\n const content = await fs.readFile(manifestPath, 'utf-8');\n return JSON.parse(content);\n}\n","/**\n * Auto-detection of editable fields from Vue components\n */\n\nimport * as cheerio from 'cheerio';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport type { FieldMapping, CollectionMapping } from '@see-ms/types';\n\n/**\n * Clean class name - remove utility prefixes and normalize\n */\nfunction cleanClassName(className: string): string {\n return className\n .split(' ')\n .filter(cls => !cls.startsWith('c-') && !cls.startsWith('w-'))\n .filter(cls => cls.length > 0)\n .map(cls => cls.replace(/-/g, '_'))\n .join(' ');\n}\n\n/**\n * Get primary semantic class from an element\n */\nfunction getPrimaryClass(classAttr: string | undefined): string | null {\n if (!classAttr) return null;\n\n const cleaned = cleanClassName(classAttr);\n const classes = cleaned.split(' ').filter(c => c.length > 0);\n\n return classes[0] || null;\n}\n\n/**\n * Get context modifier from parent classes (cc-* prefixes)\n */\nfunction getContextModifier(_$: cheerio.CheerioAPI, $el: cheerio.Cheerio<any>): string | null {\n // Look up the parent tree for cc-* modifiers\n let $current = $el.parent();\n let depth = 0;\n\n while ($current.length > 0 && depth < 5) {\n const classes = $current.attr('class');\n if (classes) {\n const ccClass = classes.split(' ').find(c => c.startsWith('cc-'));\n if (ccClass) {\n return ccClass.replace('cc-', '').replace(/-/g, '_');\n }\n }\n $current = $current.parent();\n depth++;\n }\n\n return null;\n}\n\n/**\n * Check if element is decorative (shouldn't be editable)\n */\nfunction isDecorativeImage(_$: cheerio.CheerioAPI, $img: cheerio.Cheerio<any>): boolean {\n const $parent = $img.parent();\n const parentClass = $parent.attr('class') || '';\n\n // Skip images in these contexts\n const decorativePatterns = [\n 'nav', 'logo', 'icon', 'arrow', 'button',\n 'quote', 'pagination', 'footer', 'link'\n ];\n\n return decorativePatterns.some(pattern =>\n parentClass.includes(pattern) || parentClass.includes(`${pattern}_`)\n );\n}\n\n/**\n * Check if element is inside a button or link\n */\nfunction isInsideButton($: cheerio.CheerioAPI, el: any): boolean {\n const $el = $(el);\n const $button = $el.closest('button, a, NuxtLink, .c_button, .c_icon_button');\n return $button.length > 0;\n}\n\n/**\n * Analyze a Vue file and extract template content\n */\nexport function extractTemplateFromVue(vueContent: string): string {\n const templateMatch = vueContent.match(/<template>([\\s\\S]*?)<\\/template>/);\n if (!templateMatch) {\n return '';\n }\n return templateMatch[1];\n}\n\n/**\n * Detect editable fields from Vue template content\n */\nexport function detectEditableFields(templateHtml: string): {\n fields: Record<string, FieldMapping>;\n collections: Record<string, CollectionMapping>;\n} {\n const $ = cheerio.load(templateHtml);\n const detectedFields: Record<string, FieldMapping> = {};\n const detectedCollections: Record<string, CollectionMapping> = {};\n\n // Track which elements are part of collections\n const collectionElements = new Set<any>();\n const processedCollectionClasses = new Set<string>();\n\n // 1. Detect collections FIRST\n const potentialCollections = new Map<string, any[]>();\n\n $('[class]').each((_, el) => {\n const primaryClass = getPrimaryClass($(el).attr('class'));\n\n // Only detect top-level collection containers\n if (primaryClass && (\n primaryClass.includes('card') ||\n primaryClass.includes('item') ||\n primaryClass.includes('post') ||\n primaryClass.includes('feature')\n ) && !primaryClass.includes('image') && !primaryClass.includes('inner')) {\n if (!potentialCollections.has(primaryClass)) {\n potentialCollections.set(primaryClass, []);\n }\n potentialCollections.get(primaryClass)?.push(el);\n }\n });\n\n // Process collections\n potentialCollections.forEach((elements, className) => {\n if (elements.length >= 2) {\n const $first = $(elements[0]);\n const collectionFields: Record<string, any> = {};\n\n // Mark this collection as processed\n processedCollectionClasses.add(className);\n\n // Mark all elements in this collection\n elements.forEach(el => {\n collectionElements.add(el);\n $(el).find('*').each((_, child) => {\n collectionElements.add(child);\n });\n });\n\n // Detect fields within collection\n // Images\n // @ts-ignore\n $first.find('img').each((_, img) => {\n if (isInsideButton($, img)) return;\n\n const $img = $(img);\n const $parent = $img.parent();\n const parentClass = getPrimaryClass($parent.attr('class'));\n\n if (parentClass && parentClass.includes('image')) {\n collectionFields.image = `.${parentClass}`;\n return false; // Only first image\n }\n });\n\n // Tags/categories\n // @ts-ignore\n $first.find('div').each((_, el) => {\n const primaryClass = getPrimaryClass($(el).attr('class'));\n if (primaryClass && primaryClass.includes('tag') && !primaryClass.includes('container')) {\n collectionFields.tag = `.${primaryClass}`;\n return false;\n }\n });\n\n // Headings\n $first.find('h1, h2, h3, h4, h5, h6').first().each((_, el) => {\n const primaryClass = getPrimaryClass($(el).attr('class'));\n if (primaryClass) {\n collectionFields.title = `.${primaryClass}`;\n }\n });\n\n // Descriptions\n $first.find('p').first().each((_, el) => {\n const primaryClass = getPrimaryClass($(el).attr('class'));\n if (primaryClass) {\n collectionFields.description = `.${primaryClass}`;\n }\n });\n\n // Links\n // @ts-ignore\n $first.find('a, NuxtLink').not('.c_button, .c_icon_button').each((_, el) => {\n const $link = $(el);\n const linkText = $link.text().trim();\n\n if (linkText) {\n collectionFields.link = `.${getPrimaryClass($link.attr('class')) || 'a'}`;\n return false; // Only first link\n }\n });\n\n if (Object.keys(collectionFields).length > 0) {\n let collectionName = className;\n if (!collectionName.endsWith('s')) {\n collectionName += 's';\n }\n\n detectedCollections[collectionName] = {\n selector: `.${className}`,\n fields: collectionFields,\n };\n }\n }\n });\n\n // 2. Detect individual fields\n const $body = $('body');\n\n // Headings\n $body.find('h1, h2, h3, h4, h5, h6').each((index, el) => {\n if (collectionElements.has(el)) return;\n\n const $el = $(el);\n const text = $el.text().trim();\n const primaryClass = getPrimaryClass($el.attr('class'));\n\n if (text) {\n let fieldName: string;\n\n if (primaryClass && !primaryClass.startsWith('heading_')) {\n // Has semantic class\n fieldName = primaryClass;\n } else {\n // Generic heading - use parent context\n const $parent = $el.closest('[class*=\"header\"], [class*=\"hero\"], [class*=\"cta\"]').first();\n const parentClass = getPrimaryClass($parent.attr('class'));\n const modifier = getContextModifier($, $el);\n\n if (parentClass) {\n fieldName = modifier ? `${modifier}_${parentClass}` : parentClass;\n } else if (modifier) {\n fieldName = `${modifier}_heading`;\n } else {\n fieldName = `heading_${index}`;\n }\n }\n\n detectedFields[fieldName] = {\n selector: primaryClass ? `.${primaryClass}` : el.tagName.toLowerCase(),\n type: 'plain',\n editable: true,\n };\n }\n });\n\n // Paragraphs\n $body.find('p').each((_index, el) => {\n if (collectionElements.has(el)) return;\n\n const $el = $(el);\n const text = $el.text().trim();\n const primaryClass = getPrimaryClass($el.attr('class'));\n\n if (text && text.length > 20 && primaryClass) {\n const hasFormatting = $el.find('strong, em, b, i, a, NuxtLink').length > 0;\n\n detectedFields[primaryClass] = {\n selector: `.${primaryClass}`,\n type: hasFormatting ? 'rich' : 'plain',\n editable: true,\n };\n }\n });\n\n // Content images only (skip decorative)\n $body.find('img').each((_index, el) => {\n if (collectionElements.has(el)) return;\n if (isInsideButton($, el)) return;\n\n const $el = $(el);\n\n // Skip decorative images\n if (isDecorativeImage($, $el)) return;\n\n const $parent = $el.parent();\n const parentClass = getPrimaryClass($parent.attr('class'));\n\n if (parentClass) {\n const fieldName = parentClass.includes('image')\n ? parentClass\n : `${parentClass}_image`;\n\n detectedFields[fieldName] = {\n selector: `.${parentClass}`,\n type: 'image',\n editable: true,\n };\n }\n });\n\n // Button text\n $body.find('NuxtLink.c_button, a.c_button, .c_button').each((_index, el) => {\n if (collectionElements.has(el)) return;\n\n const $el = $(el);\n const text = $el.contents().filter(function() {\n return this.type === 'text' || (this.type === 'tag' && this.name === 'div');\n }).first().text().trim();\n\n if (text && text.length > 2) {\n const $parent = $el.closest('[class*=\"cta\"]').first();\n const parentClass = getPrimaryClass($parent.attr('class')) || 'button';\n\n detectedFields[`${parentClass}_button_text`] = {\n selector: `.c_button`,\n type: 'plain',\n editable: true,\n };\n }\n });\n\n return {\n fields: detectedFields,\n collections: detectedCollections,\n };\n}\n\n/**\n * Analyze all Vue pages in a directory\n */\nexport async function analyzeVuePages(pagesDir: string): Promise<Record<string, {\n fields: Record<string, FieldMapping>;\n collections: Record<string, CollectionMapping>;\n}>> {\n const results: Record<string, any> = {};\n\n const vueFiles = await fs.readdir(pagesDir);\n\n for (const file of vueFiles) {\n if (file.endsWith('.vue')) {\n const filePath = path.join(pagesDir, file);\n const content = await fs.readFile(filePath, 'utf-8');\n const template = extractTemplateFromVue(content);\n\n if (template) {\n const pageName = file.replace('.vue', '');\n results[pageName] = detectEditableFields(template);\n }\n }\n }\n\n return results;\n}\n","/**\n * Transform CMS manifest to Strapi schemas\n */\n\nimport type { CMSManifest, StrapiSchema, FieldMapping } from '@see-ms/types';\n\n/**\n * Map field type to Strapi field type\n */\nfunction mapFieldTypeToStrapi(fieldType: string): string {\n const typeMap: Record<string, string> = {\n plain: 'string',\n rich: 'richtext',\n html: 'richtext',\n image: 'media',\n link: 'string',\n email: 'email',\n phone: 'string',\n };\n\n return typeMap[fieldType] || 'string';\n}\n\n/**\n * Convert a page manifest to a Strapi schema (single type)\n */\nfunction pageToStrapiSchema(pageName: string, fields: Record<string, FieldMapping>): StrapiSchema {\n const attributes: Record<string, any> = {};\n\n // Convert each field\n for (const [fieldName, field] of Object.entries(fields)) {\n attributes[fieldName] = {\n type: mapFieldTypeToStrapi(field.type),\n required: field.required || false,\n };\n\n if (field.default) {\n attributes[fieldName].default = field.default;\n }\n }\n\n // Generate display name\n const displayName = pageName\n .split('-')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n\n return {\n kind: 'singleType',\n collectionName: pageName.replace(/-/g, '_'),\n info: {\n singularName: pageName.replace(/-/g, '_'),\n pluralName: pageName.replace(/-/g, '_'),\n displayName: displayName,\n },\n options: {\n draftAndPublish: true,\n },\n attributes,\n };\n}\n\n/**\n * Convert a collection to a Strapi schema (collection type)\n */\nfunction collectionToStrapiSchema(\n collectionName: string,\n collection: any\n): StrapiSchema {\n const attributes: Record<string, any> = {};\n\n // Convert each field in the collection\n for (const [fieldName, _selector] of Object.entries(collection.fields)) {\n // Determine type based on field name\n let type = 'string';\n\n if (fieldName === 'image' || fieldName.includes('image')) {\n type = 'media';\n } else if (fieldName === 'description' || fieldName === 'content') {\n type = 'richtext';\n } else if (fieldName === 'link' || fieldName === 'url') {\n type = 'string';\n } else if (fieldName === 'title' || fieldName === 'tag') {\n type = 'string';\n }\n\n attributes[fieldName] = {\n type,\n };\n }\n\n // Generate display name\n const displayName = collectionName\n .split(/[-_]/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n\n // Get singular name (remove trailing 's')\n const singularName = collectionName.endsWith('s')\n ? collectionName.slice(0, -1)\n : collectionName;\n\n return {\n kind: 'collectionType',\n collectionName: collectionName.replace(/[-_]/g, '_'),\n info: {\n singularName: singularName.replace(/[-_]/g, '_'),\n pluralName: collectionName.replace(/[-_]/g, '_'),\n displayName: displayName,\n },\n options: {\n draftAndPublish: true,\n },\n attributes,\n };\n}\n\n/**\n * Transform entire manifest to Strapi schemas\n */\nexport function manifestToSchemas(manifest: CMSManifest): Record<string, StrapiSchema> {\n const schemas: Record<string, StrapiSchema> = {};\n\n // Convert pages to single types\n for (const [pageName, page] of Object.entries(manifest.pages)) {\n // Only create schema if page has fields\n if (page.fields && Object.keys(page.fields).length > 0) {\n schemas[pageName] = pageToStrapiSchema(pageName, page.fields);\n }\n\n // Convert collections to collection types\n if (page.collections) {\n for (const [collectionName, collection] of Object.entries(page.collections)) {\n schemas[collectionName] = collectionToStrapiSchema(collectionName, collection);\n }\n }\n }\n\n return schemas;\n}\n","/**\n * Write Strapi schemas to disk\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport type { StrapiSchema } from '@see-ms/types';\n\n/**\n * Write a single Strapi schema to a flat directory\n */\nexport async function writeStrapiSchema(\n outputDir: string,\n name: string,\n schema: StrapiSchema\n): Promise<void> {\n const schemasDir = path.join(outputDir, 'cms-schemas');\n await fs.ensureDir(schemasDir);\n \n const schemaPath = path.join(schemasDir, `${name}.json`);\n await fs.writeFile(schemaPath, JSON.stringify(schema, null, 2), 'utf-8');\n}\n\n/**\n * Write all schemas\n */\nexport async function writeAllSchemas(\n outputDir: string,\n schemas: Record<string, StrapiSchema>\n): Promise<void> {\n for (const [name, schema] of Object.entries(schemas)) {\n await writeStrapiSchema(outputDir, name, schema);\n }\n}\n\n/**\n * Create a README for the CMS schemas\n */\nexport async function createStrapiReadme(outputDir: string): Promise<void> {\n const readmePath = path.join(outputDir, 'cms-schemas', 'README.md');\n \n const content = `# CMS Schemas\n\nAuto-generated Strapi content type schemas from your Webflow export.\n\n## What's in this folder?\n\nEach \\`.json\\` file is a Strapi content type schema:\n\n- **Pages** (single types) - Unique pages like \\`index.json\\`, \\`about.json\\`\n- **Collections** (collection types) - Repeating content like \\`portfolio_cards.json\\`\n\n## How to use with Strapi\n\n### Option 1: Manual Setup (Recommended for learning)\n\n1. Start your Strapi project\n2. In Strapi admin, go to **Content-Type Builder**\n3. Create each content type manually using these schemas as reference\n4. Match the field names and types\n\n### Option 2: Automated Setup (Advanced)\n\nCopy schemas to your Strapi project structure:\n\n\\`\\`\\`bash\n# For each schema file, create the Strapi directory structure\n# Example for index.json (single type):\nmkdir -p strapi/src/api/index/content-types/index\ncp cms-schemas/index.json strapi/src/api/index/content-types/index/schema.json\n\n# Example for portfolio_cards.json (collection type):\nmkdir -p strapi/src/api/portfolio-cards/content-types/portfolio-card\ncp cms-schemas/portfolio_cards.json strapi/src/api/portfolio-cards/content-types/portfolio-card/schema.json\n\\`\\`\\`\n\nThen restart Strapi - it will auto-create the content types.\n\n## Schema Structure\n\nEach schema defines:\n- \\`kind\\`: \"singleType\" (unique page) or \"collectionType\" (repeating)\n- \\`attributes\\`: Fields and their types (string, richtext, media, etc.)\n- \\`displayName\\`: How it appears in Strapi admin\n\n## Field Types\n\n- \\`string\\` - Plain text\n- \\`richtext\\` - Formatted text with HTML\n- \\`media\\` - Image uploads\n\n## Next Steps\n\n1. Set up a Strapi project: \\`npx create-strapi-app@latest my-strapi\\`\n2. Use these schemas to create content types\n3. Populate content in Strapi admin\n4. Connect your Nuxt app to Strapi API\n\n## API Usage in Nuxt\n\nOnce Strapi is running with these content types:\n\n\\`\\`\\`typescript\n// Fetch single type (e.g., home page)\nconst { data } = await $fetch('http://localhost:1337/api/index')\n\n// Fetch collection type (e.g., portfolio cards)\nconst { data } = await $fetch('http://localhost:1337/api/portfolio-cards')\n\\`\\`\\`\n`;\n \n await fs.writeFile(readmePath, content, 'utf-8');\n}\n"],"mappings":"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","names":["pc","pc","path","fs","path","fs","path","fs","path","fs","path","execSync","pc","fs","path","cheerio","fs","path","path","fs","fs","path","pc","fs","path","pc"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConversionOptions, CMSManifest, StrapiSchema } from '@see-ms/types';
|
|
1
|
+
import { ConversionOptions, FieldMapping, CollectionMapping, CMSManifest, StrapiSchema } from '@see-ms/types';
|
|
2
2
|
export { ConversionOptions } from '@see-ms/types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -8,17 +8,25 @@ export { ConversionOptions } from '@see-ms/types';
|
|
|
8
8
|
declare function convertWebflowExport(options: ConversionOptions): Promise<void>;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Auto-detection of editable fields
|
|
12
|
-
* TODO: Implement in Sprint 2
|
|
11
|
+
* Auto-detection of editable fields from Vue components
|
|
13
12
|
*/
|
|
14
|
-
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Detect editable fields from Vue template content
|
|
16
|
+
*/
|
|
17
|
+
declare function detectEditableFields(templateHtml: string): {
|
|
18
|
+
fields: Record<string, FieldMapping>;
|
|
19
|
+
collections: Record<string, CollectionMapping>;
|
|
20
|
+
};
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
23
|
* Manifest generation
|
|
18
|
-
* TODO: Implement in Sprint 2
|
|
19
24
|
*/
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Generate CMS manifest from analyzed pages
|
|
28
|
+
*/
|
|
29
|
+
declare function generateManifest(pagesDir: string): Promise<CMSManifest>;
|
|
22
30
|
|
|
23
31
|
/**
|
|
24
32
|
* CMS schema generation
|
|
@@ -28,11 +36,13 @@ declare function generateManifest(_data: any): CMSManifest;
|
|
|
28
36
|
declare function generateSchemas(_manifestPath: string, _cmsType: string): Promise<void>;
|
|
29
37
|
|
|
30
38
|
/**
|
|
31
|
-
* Transform manifest to
|
|
32
|
-
* TODO: Implement in Sprint 3
|
|
39
|
+
* Transform CMS manifest to Strapi schemas
|
|
33
40
|
*/
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Transform entire manifest to Strapi schemas
|
|
44
|
+
*/
|
|
45
|
+
declare function manifestToSchemas(manifest: CMSManifest): Record<string, StrapiSchema>;
|
|
36
46
|
|
|
37
47
|
/**
|
|
38
48
|
* Boilerplate cloning and setup utilities
|
|
@@ -42,4 +52,4 @@ declare function manifestToSchema(_manifest: CMSManifest, _cmsType: string): Str
|
|
|
42
52
|
*/
|
|
43
53
|
declare function setupBoilerplate(boilerplateSource: string | undefined, outputDir: string): Promise<void>;
|
|
44
54
|
|
|
45
|
-
export { convertWebflowExport, detectEditableFields, generateManifest, generateSchemas,
|
|
55
|
+
export { convertWebflowExport, detectEditableFields, generateManifest, generateSchemas, manifestToSchemas, setupBoilerplate };
|