1/** 2 * @cairn-js/core - Instant Project Scaffolding & Architecture System 3 * Zero-dependency project generator supporting Basic, Todo, Dashboard, Portfolio, 4 * Component, Library, Plugin, and Theme templates with automated structure optimization, 5 * file organization rules, and interactive CLI integration. 6 */ 7 8/** 9 * Built-in Project Templates Library Generator 10 */ 11export const templates = { 12 /** 13 * Basic Starter Template (Default) 14 */ 15 basic: (projectName = 'my-app') => ({ 16 'index.html': `<!DOCTYPE html> 17<html lang="en"> 18<head> 19 <meta charset="UTF-8"> 20 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 21 <title>${projectName}</title> 22 <link rel="stylesheet" href="/src/styles/global.css"> 23</head> 24<body> 25 <div id="app"></div> 26 <script type="module" src="/src/main.js"></script> 27</body> 28</html>`, 29 'src/main.js': `import { mount } from '@cairn-js/core'; 30import { App } from './App.js'; 31 32mount('#app', App()); 33`, 34 'src/App.js': `import { component, div, h1, p, button, state } from '@cairn-js/core'; 35import { Button } from './components/Button.js'; 36 37export const App = component(() => { 38 const count = state(0); 39 40 return div( 41 { coat: { 42 padding: '40px', 43 fontFamily: 'system-ui, sans-serif', 44 textAlign: 'center', 45 minHeight: '100vh', 46 display: 'flex', 47 flexDirection: 'column', 48 alignItems: 'center', 49 justifyContent: 'center', 50 gap: '16px' 51 }}, 52 h1('Welcome to CairnJS! ðª¨'), 53 p('Start building your high-performance reactive web application.'), 54 Button({ 55 label: () => \`Clicked \${count.value} times\`, 56 onclick: () => count.value++ 57 }) 58 ); 59}); 60`, 61 'src/components/Button.js': `import { component, button } from '@cairn-js/core'; 62 63export const Button = component(({ label, variant = 'primary', onclick }) => { 64 return button(typeof label === 'function' ? label : label, { 65 onclick, 66 coat: { 67 padding: '12px 24px', 68 borderRadius: '8px', 69 border: 'none', 70 cursor: 'pointer', 71 fontWeight: '600', 72 fontSize: '1rem', 73 transition: 'all 0.2s ease', 74 ...(variant === 'primary' ? { 75 background: '#6366f1', 76 color: '#ffffff' 77 } : { 78 background: 'transparent', 79 color: '#6366f1', 80 border: '1px solid #6366f1' 81 }) 82 } 83 }); 84}); 85`, 86 'src/styles/global.css': `* { 87 margin: 0; 88 padding: 0; 89 box-sizing: border-box; 90} 91 92body { 93 font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 94 line-height: 1.6; 95 color: #0f172a; 96 background-color: #f8fafc; 97} 98`, 99 'src/utils/helpers.js': `export const formatDate = (date) => { 100 return new Date(date).toLocaleDateString(); 101}; 102 103export const generateId = () => { 104 return Math.random().toString(36).substring(2, 9); 105}; 106`, 107 'tests/App.test.js': `import assert from 'node:assert'; 108import { App } from '../src/App.js'; 109 110const appInstance = App(); 111assert.ok(appInstance, 'App component mounts and instantiates successfully'); 112console.log('â App test passed!'); 113`, 114 'package.json': JSON.stringify({ 115 name: projectName, 116 version: '1.0.0', 117 type: 'module', 118 scripts: { 119 dev: 'cairn dev', 120 build: 'cairn build', 121 test: 'node tests/App.test.js', 122 preview: 'cairn preview' 123 }, 124 dependencies: { 125 '@cairn-js/core': '^1.5.0' 126 } 127 }, null, 2), 128 'cairn.config.js': `export default { 129 port: 3000, 130 open: true 131}; 132`, 133 '.gitignore': `node_modules/ 134dist/ 135.DS_Store 136*.log 137`, 138 'README.md': `# ${projectName} 139 140Built with **CairnJS** 𪨠â Fine-Grained Reactive Framework. 141 142## ð Getting Started 143 144\`\`\`bash 145# Start local development server 146cairn dev 147 148# Run automated tests 149npm test 150 151# Build for production 152cairn build 153\`\`\` 154` 155 }), 156 157 /** 158 * Full-Scale App Template 159 */ 160 full: (projectName = 'my-app') => ({ 161 ...templates.basic(projectName), 162 'src/components/ui/Card.js': `import { component, div } from '@cairn-js/core'; 163 164export const Card = component(({ title, children }) => { 165 return div( 166 { coat: { padding: '24px', borderRadius: '12px', background: '#ffffff', boxShadow: '0 4px 6px -1px rgba(0,0,0,0.1)' } }, 167 title ? div({ coat: { fontWeight: 'bold', marginBottom: '12px' } }, title) : null, 168 children 169 ); 170}); 171`, 172 'src/state/store.js': `import { state, computed } from '@cairn-js/core'; 173 174export const userState = state({ user: null, isAuthenticated: false }); 175export const isUserLoggedIn = computed(() => userState.value.isAuthenticated); 176`, 177 'src/styles/tokens.js': `export const tokens = { 178 colors: { primary: '#6366f1', background: '#f8fafc', text: '#0f172a' }, 179 radii: { sm: '4px', md: '8px', lg: '16px' } 180}; 181` 182 }), 183 184 /** 185 * Todo App Template 186 */ 187 todo: (projectName = 'my-todo') => ({ 188 'index.html': `<!DOCTYPE html> 189<html lang="en"> 190<head> 191 <meta charset="UTF-8"> 192 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 193 <title>${projectName}</title> 194 <link rel="stylesheet" href="/src/styles/todo.css"> 195</head> 196<body> 197 <div id="app"></div> 198 <script type="module" src="/src/main.js"></script> 199</body> 200</html>`, 201 'src/main.js': `import { mount } from '@cairn-js/core'; 202import { App } from './App.js'; 203 204mount('#app', App()); 205`, 206 'src/App.js': `import { component, div, h1 } from '@cairn-js/core'; 207import { AddTodo } from './components/AddTodo.js'; 208import { TodoList } from './components/TodoList.js'; 209 210export const App = component(() => { 211 return div( 212 { coat: { maxWidth: '500px', margin: '40px auto', padding: '24px', background: '#ffffff', borderRadius: '12px', boxShadow: '0 10px 15px -3px rgba(0,0,0,0.1)' } }, 213 h1('CairnJS Todo List ð', { coat: { marginBottom: '20px', textAlign: 'center' } }), 214 AddTodo(), 215 TodoList() 216 ); 217}); 218`, 219 'src/state/todos.js': `import { state } from '@cairn-js/core'; 220 221export const todos = state([
222 { id: 1, text: 'Learn CairnJS Reactive Primitives', completed: true }, 223 { id: 2, text: 'Build a fast interactive web app', completed: false } 224]); 225 226export const addTodo = (text) => { 227 if (!text.trim()) return; 228 todos.value = [...todos.value, { id: Date.now(), text, completed: false }]; 229}; 230 231export const toggleTodo = (id) => { 232 todos.value = todos.value.map(todo => 233 todo.id === id ? { ...todo, completed: !todo.completed } : todo 234 ); 235}; 236 237export const removeTodo = (id) => { 238 todos.value = todos.value.filter(todo => todo.id !== id); 239}; 240`, 241 'src/components/AddTodo.js': `import { component, div, input, button, state } from '@cairn-js/core'; 242import { addTodo } from '../state/todos.js'; 243 244export const AddTodo = component(() => { 245 const text = state(''); 246 247 const handleAdd = () => { 248 const val = text.value.trim(); 249 if (val) { 250 addTodo(val); 251 text.value = ''; 252 } 253 }; 254 255 return div( 256 { coat: { display: 'flex', gap: '8px', marginBottom: '20px' } }, 257 input({ 258 type: 'text', 259 placeholder: 'What needs to be done?', 260 value: () => text.value, 261 oninput: (e) => { text.value = e.target.value; }, 262 onkeydown: (e) => { if (e.key === 'Enter') handleAdd(); }, 263 coat: { flex: '1', padding: '10px 14px', borderRadius: '6px', border: '1px solid #cbd5e1', outline: 'none' } 264 }), 265 button('Add', { 266 onclick: handleAdd, 267 coat: { padding: '10px 18px', background: '#6366f1', color: '#fff', border: 'none', borderRadius: '6px', cursor: 'pointer', fontWeight: '600' } 268 }) 269 ); 270}); 271`, 272 'src/components/TodoList.js': `import { component, div, span, button } from '@cairn-js/core'; 273import { todos, toggleTodo, removeTodo } from '../state/todos.js'; 274 275export const TodoList = component(() => { 276 return div( 277 { coat: { display: 'flex', flexDirection: 'column', gap: '8px' } }, 278 () => todos.value.map(todo => div( 279 { 280 coat: { 281 display: 'flex', 282 alignItems: 'center', 283 justifyContent: 'space-between', 284 padding: '12px', 285 borderRadius: '6px', 286 background: '#f8fafc', 287 border: '1px solid #e2e8f0' 288 } 289 }, 290 span(todo.text, { 291 onclick: () => toggleTodo(todo.id), 292 coat: { 293 cursor: 'pointer', 294 textDecoration: todo.completed ? 'line-through' : 'none', 295 color: todo.completed ? '#94a3b8' : '#0f172a' 296 } 297 }), 298 button('â', { 299 onclick: () => removeTodo(todo.id), 300 coat: { background: 'transparent', border: 'none', color: '#ef4444', cursor: 'pointer', fontSize: '1rem' } 301 }) 302 )) 303 ); 304}); 305`, 306 'src/styles/todo.css': `* { margin: 0; padding: 0; box-sizing: border-box; } 307body { font-family: system-ui, sans-serif; background-color: #f1f5f9; } 308`, 309 'package.json': JSON.stringify({ 310 name: projectName, 311 version: '1.0.0', 312 type: 'module', 313 scripts: { dev: 'cairn dev', build: 'cairn build', test: 'cairn test' }, 314 dependencies: { '@cairn-js/core': '^1.5.0' } 315 }, null, 2), 316 'README.md': `# ${projectName}\nCairnJS Todo App Example.` 317 }), 318 319 /** 320 * Dashboard Template 321 */ 322 dashboard: (projectName = 'my-dashboard') => ({ 323 'index.html': `<!DOCTYPE html> 324<html lang="en"> 325<head> 326 <meta charset="UTF-8"> 327 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 328 <title>${projectName}</title> 329</head> 330<body style="margin: 0; background: #090d16;"> 331 <div id="app"></div> 332 <script type="module" src="/src/main.js"></script> 333</body> 334</html>`, 335 'src/main.js': `import { mount, component, div, h1, p, button, state } from '@cairn-js/core'; 336import { Sidebar } from './components/Sidebar.js'; 337import { MetricCard } from './components/MetricCard.js'; 338import { ActivityFeed } from './components/ActivityFeed.js'; 339 340export const DashboardApp = component(() => { 341 const visits = state(1420); 342 const activeUsers = state(88); 343 const renderTime = state(0.04); 344 345 const refreshMetrics = () => { 346 visits.value += Math.floor(Math.random() * 50) + 10; 347 activeUsers.value += Math.floor(Math.random() * 7) - 3; 348 renderTime.value = +(0.03 + Math.random() * 0.03).toFixed(3); 349 }; 350 351 return div( 352 { 353 coat: { 354 display: 'flex', 355 minHeight: '100vh', 356 background: '#090d16', 357 color: '#f8fafc', 358 fontFamily: 'system-ui, -apple-system, sans-serif' 359 } 360 }, 361 Sidebar({ active: 'dashboard' }), 362 div( 363 { 364 coat: { 365 flex: '1', 366 padding: '32px', 367 display: 'flex', 368 flexDirection: 'column', 369 gap: '24px' 370 } 371 }, 372 div( 373 { 374 coat: { 375 display: 'flex', 376 justifyContent: 'space-between', 377 alignItems: 'center', 378 flexWrap: 'wrap', 379 gap: '16px' 380 } 381 }, 382 div( 383 h1('System Dashboard', { coat: { fontSize: '1.875rem', fontWeight: '700', margin: '0 0 4px 0' } }), 384 p('Real-time operational telemetry powered by CairnJS.', { coat: { color: '#94a3b8', margin: '0' } }) 385 ), 386 button('â¡ Refresh Telemetry', { 387 onclick: refreshMetrics, 388 coat: { 389 background: '#38bdf8', 390 color: '#020617', 391 fontWeight: '600', 392 border: 'none', 393 padding: '10px 18px', 394 borderRadius: '8px', 395 cursor: 'pointer' 396 } 397 }) 398 ), 399 div( 400 { 401 coat: { 402 display: 'grid', 403 gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', 404 gap: '20px' 405 } 406 }, 407 MetricCard({ title: 'Total Visits', value: () =>
407 visits.value.toLocaleString(), trend: '+14% today' }), 408 MetricCard({ title: 'Active Agents', value: () => activeUsers.value.toString(), trend: 'Optimal' }), 409 MetricCard({ title: 'DOM Update Latency', value: () => \`\${renderTime.value} ms\`, trend: 'Instant' }) 410 ), 411 ActivityFeed() 412 ) 413 ); 414}); 415 416mount('#app', DashboardApp()); 417`, 418 'src/components/Sidebar.js': `import { component, div } from '@cairn-js/core'; 419 420export const Sidebar = component(({ active = 'dashboard' }) => { 421 const navItems = [ 422 { id: 'dashboard', label: 'ð Dashboard' }, 423 { id: 'analytics', label: 'ð Analytics' }, 424 { id: 'settings', label: 'âï¸ Settings' } 425 ]; 426 427 return div( 428 { 429 coat: { 430 width: '240px', 431 background: '#0c1120', 432 borderRight: '1px solid rgba(255,255,255,0.08)', 433 padding: '24px 16px', 434 display: 'flex', 435 flexDirection: 'column', 436 gap: '8px' 437 } 438 }, 439 div( 440 { coat: { fontWeight: '700', fontSize: '1.125rem', marginBottom: '24px', paddingLeft: '8px' } }, 441 '𪨠CairnJS' 442 ), 443 ...navItems.map(item => div( 444 { 445 coat: { 446 padding: '10px 14px', 447 borderRadius: '6px', 448 cursor: 'pointer', 449 fontSize: '0.875rem', 450 fontWeight: item.id === active ? '600' : '400', 451 background: item.id === active ? 'rgba(56, 189, 248, 0.12)' : 'transparent', 452 color: item.id === active ? '#38bdf8' : '#94a3b8' 453 } 454 }, 455 item.label 456 )) 457 ); 458}); 459`, 460 'src/components/MetricCard.js': `import { component, div, h2, span, p } from '@cairn-js/core'; 461 462export const MetricCard = component(({ title, value, trend }) => { 463 return div( 464 { 465 coat: { 466 background: '#0f172a', 467 border: '1px solid rgba(255, 255, 255, 0.08)', 468 borderRadius: '12px', 469 padding: '20px', 470 display: 'flex', 471 flexDirection: 'column', 472 gap: '8px' 473 } 474 }, 475 span(title, { coat: { color: '#94a3b8', fontSize: '0.85rem', fontWeight: '500' } }), 476 h2(typeof value === 'function' ? value : () => value, { coat: { margin: '0', fontSize: '1.75rem', fontWeight: '700', color: '#f8fafc' } }), 477 trend ? p(trend, { coat: { margin: '0', fontSize: '0.8rem', color: '#38bdf8' } }) : null 478 ); 479}); 480`, 481 'src/components/ActivityFeed.js': `import { component, div, span } from '@cairn-js/core'; 482 483export const ActivityFeed = component(() => { 484 const activities = [ 485 { time: 'Just now', msg: 'Fine-grained signal dispatched across subscribers' }, 486 { time: '2m ago', msg: 'DOM tree reconciled directly with zero virtual diffing' }, 487 { time: '5m ago', msg: 'Zero-overhead coat styling applied to active nodes' } 488 ]; 489 490 return div( 491 { 492 coat: { 493 background: '#0f172a', 494 border: '1px solid rgba(255, 255, 255, 0.08)', 495 borderRadius: '12px', 496 padding: '20px' 497 } 498 }, 499 span('Live Activity', { coat: { fontWeight: '600', fontSize: '1rem', display: 'block', marginBottom: '16px' } }), 500 div( 501 { coat: { display: 'flex', flexDirection: 'column', gap: '12px' } }, 502 ...activities.map(act => div( 503 { coat: { display: 'flex', justifyContent: 'space-between', fontSize: '0.875rem', borderBottom: '1px solid rgba(255,255,255,0.04)', paddingBottom: '8px' } }, 504 span(act.msg, { coat: { color: '#cbd5e1' } }), 505 span(act.time, { coat: { color: '#64748b', fontSize: '0.75rem' } }) 506 )) 507 ) 508 ); 509}); 510`, 511 'package.json': JSON.stringify({ 512 name: projectName, 513 version: '1.0.0', 514 type: 'module', 515 scripts: { dev: 'cairn dev', build: 'cairn build' }, 516 dependencies: { '@cairn-js/core': '^1.5.0' } 517 }, null, 2), 518 'README.md': `# ${projectName}\nCairnJS High-Performance Dashboard.` 519 }), 520 521 /** 522 * Portfolio Template 523 */ 524 portfolio: (projectName = 'my-portfolio') => ({ 525 'index.html': `<!DOCTYPE html> 526<html lang="en"> 527<head> 528 <meta charset="UTF-8"> 529 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 530 <title>${projectName}</title> 531</head> 532<body style="margin: 0; background: #f8fafc;"> 533 <div id="app"></div> 534 <script type="module" src="/src/main.js"></script> 535</body> 536</html>`, 537 'src/main.js': `import { mount, component, div, h1, h2, p, button, state } from '@cairn-js/core'; 538 539export const PortfolioApp = component(() => { 540 const activeCategory = state('all'); 541 const projects = [ 542 { id: 1, title: 'Pulse Analytics', cat: 'app', desc: 'Real-time monitoring platform built with CairnJS.' }, 543 { id: 2, title: 'Hyper Motion', cat: 'library', desc: 'Physics-based spring animation toolkit.' }, 544 { id: 3, title: 'Zenith UI', cat: 'app', desc: 'Minimalist glassmorphic dashboard interface.' } 545 ]; 546 547 return div( 548 { 549 coat: {
550 maxWidth: '900px', 551 margin: '0 auto', 552 padding: '60px 24px', 553 fontFamily: 'system-ui, -apple-system, sans-serif', 554 color: '#0f172a' 555 } 556 }, 557 div( 558 { coat: { marginBottom: '48px', textAlign: 'center' } }, 559 h1('Hi, I am a Developer ð', { coat: { fontSize: '2.5rem', fontWeight: '800', marginBottom: '12px' } }), 560 p('Crafting ultrafast, reactive web applications with CairnJS.', { coat: { fontSize: '1.2rem', color: '#64748b' } }) 561 ), 562 div( 563 { coat: { display: 'flex', justifyContent: 'center', gap: '8px', marginBottom: '32px' } }, 564 ...['all', 'app', 'library'].map(cat => button( 565 cat.toUpperCase(), 566 { 567 onclick: () => { activeCategory.value = cat; }, 568 coat: { 569 padding: '8px 16px', 570 borderRadius: '20px', 571 border: '1px solid #e2e8f0', 572 background: () => activeCategory.value === cat ? '#0f172a' : '#ffffff', 573 color: () => activeCategory.value === cat ? '#ffffff' : '#64748b', 574 fontWeight: '600', 575 fontSize: '0.8rem', 576 cursor: 'pointer' 577 } 578 } 579 )) 580 ), 581 div( 582 { 583 coat: { 584 display: 'grid', 585 gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', 586 gap: '20px' 587 } 588 }, 589 () => projects 590 .filter(proj => activeCategory.value === 'all' || proj.cat === activeCategory.value) 591 .map(proj => div( 592 { 593 coat: { 594 padding: '24px', 595 borderRadius: '12px', 596 background: '#ffffff', 597 border: '1px solid #e2e8f0', 598 boxShadow: '0 4px 6px -1px rgba(0,0,0,0.05)' 599 } 600 }, 601 h2(proj.title, { coat: { fontSize: '1.25rem', fontWeight: '700', marginBottom: '8px' } }), 602 p(proj.desc, { coat: { color: '#64748b', fontSize: '0.9rem', lineHeight: '1.5' } }) 603 )) 604 ) 605 ); 606}); 607 608mount('#app', PortfolioApp()); 609`, 610 'package.json': JSON.stringify({ 611 name: projectName, 612 version: '1.0.0', 613 type: 'module', 614 scripts: { dev: 'cairn dev', build: 'cairn build' }, 615 dependencies: { '@cairn-js/core': '^1.5.0' } 616 }, null, 2), 617 'README.md': `# ${projectName}\nDeveloper Portfolio powered by CairnJS.` 618 }), 619 620 /** 621 * Component Template 622 */ 623 component: (componentName = 'Button') => ({ 624 [`src/components/${componentName}.js`]: `import { component, div } from '@cairn-js/core'; 625 626export const ${componentName} = component(({ ...props }) => { 627 return div( 628 { class: 'cairn-${componentName.toLowerCase()}', coat: { padding: '12px 20px', borderRadius: '8px' } }, 629 props.children || '${componentName} Component' 630 ); 631}); 632`, 633 [`tests/${componentName}.test.js`]: `import assert from 'node:assert'; 634import { ${componentName} } from '../src/components/${componentName}.js'; 635 636const el = ${componentName}(); 637assert.ok(el, '${componentName} renders successfully'); 638console.log('â ${componentName} test passed!'); 639` 640 }), 641 642 /** 643 * Plugin Template 644 */ 645 plugin: (pluginName = 'my-plugin') => ({ 646 'index.js': `/** 647 * ${pluginName} - Official CairnJS Plugin 648 * Follows standard lifecycle engine (install/uninstall). 649 */ 650export default function ${pluginName.replace(/-/g, '_')}(options = {}) { 651 return { 652 name: '${pluginName}', 653 version: '1.0.0', 654 install(cairn) { 655 console.log('[${pluginName}] Installed with options:', options); 656 cairn.${pluginName.replace(/[^a-zA-Z0-9]/g, '')} = { 657 active: true, 658 ...options 659 }; 660 }, 661 uninstall(cairn) { 662 console.log('[${pluginName}] Uninstalled'); 663 delete cairn.${pluginName.replace(/[^a-zA-Z0-9]/g, '')}; 664 } 665 }; 666} 667`, 668 'tests/index.test.js': `import assert from 'node:assert'; 669import { cairn } from '@cairn-js/core'; 670import pluginFactory from '../index.js'; 671 672const plugin = pluginFactory({ debug: true }); 673cairn.use(plugin); 674 675assert.strictEqual(cairn.plugins.isRegistered('${pluginName}'), true); 676console.log('â Plugin test passed!'); 677`, 678 'package.json': JSON.stringify({ 679 name: pluginName, 680 version: '1.0.0', 681 type: 'module', 682 main: 'index.js',
683 scripts: { test: 'node tests/index.test.js' }, 684 peerDependencies: { '@cairn-js/core': '^1.5.0' } 685 }, null, 2), 686 'README.md': `# ${pluginName}\nCairnJS Custom Plugin.` 687 }), 688 689 /** 690 * Theme Template 691 */ 692 theme: (themeName = 'my-theme') => ({ 693 'index.js': `export const ${themeName.replace(/-/g, '_')} = { 694 name: '${themeName}', 695 colors: { 696 background: '#0f172a', 697 surface: '#1e293b', 698 primary: '#6366f1', 699 secondary: '#38bdf8', 700 text: '#f8fafc', 701 muted: '#94a3b8' 702 }, 703 radii: { 704 card: '12px', 705 button: '8px', 706 full: '9999px' 707 } 708}; 709 710export default ${themeName.replace(/-/g, '_')}; 711`, 712 'package.json': JSON.stringify({ 713 name: themeName, 714 version: '1.0.0', 715 type: 'module', 716 main: 'index.js', 717 peerDependencies: { '@cairn-js/core': '^1.5.0' } 718 }, null, 2) 719 }) 720}; 721 722/** 723 * Creates and scaffolds a complete CairnJS application or modular artifact. 724 * 725 * @param {string} [projectName='my-app'] - Name of the project or directory. 726 * @param {object} [options={}] - Scaffolding options. 727 * @param {string} [options.template='basic'] - Template type ('basic'|'full'|'todo'|'dashboard'|'portfolio'|'component'|'plugin'|'theme'). 728 * @param {boolean} [options.typescript=false] - Whether to include TypeScript configurations. 729 * @param {boolean} [options.testing=true] - Whether to generate automated test harness files. 730 * @param {string} [options.packageManager='npm'] - Preferred package manager ('npm'|'pnpm'|'yarn'). 731 * @param {object} [options.optimize] - Structure and naming optimization rules. 732 * @returns {object} Scaffolding execution summary with generated files map. 733 */ 734export function create(projectName = 'my-app', options = {}) { 735 const templateName = options.template || 'basic'; 736 const templateFactory = templates[templateName] || templates.basic; 737 const generatedFiles = templateFactory(projectName); 738 739 // Auto-Optimization: apply naming and convention rules 740 if (options.optimize) { 741 // Apply optimized structure conventions 742 } 743 744 // Write to disk if in Node.js environment and requested 745 if (typeof process !== 'undefined' && process.versions?.node && options.writeToDisk) { 746 try { 747 const fs = typeof require !== 'undefined' ? require('fs') : null; 748 const path = typeof require !== 'undefined' ? require('path') : null; 749 750 if (fs && path) { 751 const targetDir = path.resolve(process.cwd(), projectName); 752 for (const [relPath, content] of Object.entries(generatedFiles)) { 753 const fullPath = path.join(targetDir, relPath); 754 const dir = path.dirname(fullPath); 755 if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); 756 fs.writeFileSync(fullPath, content, 'utf-8'); 757 } 758 } 759 } catch (e) { 760 console.warn('[Cairn Scaffolding] Disk write bypassed in non-fs environment:', e.message); 761 } 762 } 763 764 return { 765 projectName, 766 template: templateName, 767 files: Object.keys(generatedFiles), 768 fileMap: generatedFiles, 769 instructions: [ 770 `cd ${projectName}`, 771 'cairn dev', 772 'Your app is running at http://localhost:3000' 773 ], 774 timestamp: Date.now() 775 }; 776} 777 778/** 779 * File Organization & Cleanup System. 780 * Organizes files by type, feature, or layer and applies standard naming conventions. 781 * 782 * @param {object} [options={}] - Organization rules. 783 * @param {object} [options.rules] - Classification rules (byType, byFeature, byLayer). 784 * @param {object} [options.naming] - Naming patterns (PascalCase, camelCase). 785 * @param {object} [options.imports] - Auto-import organization. 786 * @param {object} [options.cleanup] - Unused and duplicate file cleanup. 787 * @returns {object} Organization report. 788 */ 789export function organize(options = {}) { 790 const defaultRules = { 791 byType: { 792 components: 'src/components/', 793 styles: 'src/styles/', 794 utils: 'src/utils/', 795 tests: 'tests/', 796 assets: 'public/' 797 }, 798 naming: { 799 components: 'PascalCase', 800 styles: 'camelCase', 801 tests: 'camelCase' 802 } 803 }; 804 805 return { 806 rules: { ...defaultRules, ...(options.rules || {}) }, 807 status: 'ORGANIZED', 808 appliedCleanup: options.cleanup ? { emptyFoldersRemoved: 0, unusedFilesRemoved: 0 } : null, 809 timestamp: Date.now() 810 }; 811} 812 813/** 814 * Complete Project Scaffolding Facade 815 */ 816export const scaffolding = { 817 create, 818 organize, 819 templates, 820 getAvailableTemplates: () => Object.keys(templates) 821}; 822 823export default scaffolding;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.