export-business-plan.js
1 #!/usr/bin/env node 2 3 /** 4 * Export Business Plan to HTML 5 * 6 * Exports all business plan documents into a single professional HTML file 7 * with table of contents, styling, and print support. 8 */ 9 10 import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; 11 import { join, dirname } from 'path'; 12 import { fileURLToPath } from 'url'; 13 14 const __filename = fileURLToPath(import.meta.url); 15 const __dirname = dirname(__filename); 16 const rootDir = join(__dirname, '..'); 17 18 // Simple markdown to HTML converter (basic implementation) 19 function markdownToHtml(markdown) { 20 let html = markdown; 21 22 // Convert headers 23 html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>'); 24 html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>'); 25 html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>'); 26 27 // Convert bold 28 html = html.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>'); 29 30 // Convert italic 31 html = html.replace(/\*(.*?)\*/gim, '<em>$1</em>'); 32 33 // Convert inline code 34 html = html.replace(/`([^`]+)`/gim, '<code>$1</code>'); 35 36 // Convert code blocks 37 html = html.replace(/```(\w+)?\n([\s\S]*?)```/gim, '<pre><code>$2</code></pre>'); 38 39 // Convert links [text](url) 40 html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/gim, '<a href="$2">$1</a>'); 41 42 // Convert horizontal rules 43 html = html.replace(/^---$/gim, '<hr>'); 44 45 // Convert tables 46 html = html.replace(/\n\|(.+)\|\n\|[-:| ]+\|\n((?:\|.+\|\n?)*)/gim, (match, header, rows) => { 47 const headers = header 48 .split('|') 49 .map(h => h.trim()) 50 .filter(h => h); 51 const rowData = rows 52 .trim() 53 .split('\n') 54 .map(row => 55 row 56 .split('|') 57 .map(cell => cell.trim()) 58 .filter(cell => cell) 59 ); 60 61 let table = '<table class="data-table"><thead><tr>'; 62 headers.forEach(h => (table += `<th>${h}</th>`)); 63 table += '</tr></thead><tbody>'; 64 rowData.forEach(row => { 65 table += '<tr>'; 66 row.forEach(cell => (table += `<td>${cell}</td>`)); 67 table += '</tr>'; 68 }); 69 table += '</tbody></table>'; 70 return table; 71 }); 72 73 // Convert lists 74 html = html.replace(/^- (.+)$/gim, '<li>$1</li>'); 75 html = html.replace(/^(\d+)\. (.+)$/gim, '<li>$2</li>'); 76 html = html.replace(/(<li>.*<\/li>\n?)+/gim, '<ul>$&</ul>'); 77 78 // Convert paragraphs 79 html = html 80 .split('\n\n') 81 .map(para => { 82 if (!para.match(/^<[hupldt]/)) { 83 return `<p>${para}</p>`; 84 } 85 return para; 86 }) 87 .join('\n'); 88 89 // Clean up nested ul tags 90 html = html.replace(/<\/ul>\n<ul>/gim, ''); 91 92 return html; 93 } 94 95 // Business plan documents to include 96 const documents = [ 97 { 98 title: 'Executive Summary', 99 file: 'README.md', 100 sections: ['Quick Start', 'Architecture', 'Multi-Country Support'], 101 }, 102 { 103 title: 'Financial Projections', 104 file: 'docs/PROFIT-ESTIMATE.md', 105 }, 106 { 107 title: 'Total Addressable Market Analysis', 108 file: 'docs/TAM-EXPANSION.md', 109 }, 110 { 111 title: 'Pipeline Capacity & Throughput', 112 file: 'docs/PIPELINE-CAPACITY.md', 113 }, 114 { 115 title: 'Outreach Strategy Analysis', 116 file: 'docs/OUTREACH-STRATEGY-ANALYSIS.md', 117 }, 118 { 119 title: 'Multi-Country Pricing Strategy', 120 file: 'docs/PRICING-STRATEGY.md', 121 }, 122 { 123 title: 'Programmatic Scoring Analysis', 124 file: 'docs/PROGRAMMATIC-SCORING.md', 125 }, 126 { 127 title: 'HTML-Only Cost Analysis', 128 file: 'docs/HTML-ONLY-ANALYSIS.md', 129 }, 130 { 131 title: 'Template-Based Proposals', 132 file: 'docs/TEMPLATE-PROPOSALS.md', 133 }, 134 { 135 title: 'Functional Specification', 136 file: 'docs/FUNCTIONAL-SPEC.md', 137 }, 138 ]; 139 140 // Generate HTML 141 function generateBusinessPlanHTML() { 142 console.log('Generating business plan HTML...'); 143 144 // Read all documents 145 const documentContents = []; 146 147 for (const doc of documents) { 148 const filePath = join(rootDir, doc.file); 149 if (!existsSync(filePath)) { 150 console.warn(`⚠️ File not found: ${doc.file}, skipping...`); 151 continue; 152 } 153 154 const content = readFileSync(filePath, 'utf-8'); 155 documentContents.push({ 156 ...doc, 157 content: markdownToHtml(content), 158 }); 159 console.log(`✓ Loaded: ${doc.file}`); 160 } 161 162 // Generate table of contents 163 let toc = '<nav class="toc"><h2>Table of Contents</h2><ol>'; 164 documentContents.forEach((doc, index) => { 165 const id = doc.title.toLowerCase().replace(/[^a-z0-9]+/g, '-'); 166 toc += `<li><a href="#${id}">${doc.title}</a></li>`; 167 }); 168 toc += '</ol></nav>'; 169 170 // Generate document sections 171 let sections = ''; 172 documentContents.forEach((doc, index) => { 173 const id = doc.title.toLowerCase().replace(/[^a-z0-9]+/g, '-'); 174 sections += ` 175 <section class="document-section" id="${id}"> 176 <h1 class="section-title">${doc.title}</h1> 177 <div class="section-content"> 178 ${doc.content} 179 </div> 180 ${index < documentContents.length - 1 ? '<div class="page-break"></div>' : ''} 181 </section> 182 `; 183 }); 184 185 // HTML template 186 const html = `<!DOCTYPE html> 187 <html lang="en"> 188 <head> 189 <meta charset="UTF-8"> 190 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 191 <title>333 Method - Business Plan</title> 192 <style> 193 /* Reset and base styles */ 194 * { 195 margin: 0; 196 padding: 0; 197 box-sizing: border-box; 198 } 199 200 body { 201 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; 202 line-height: 1.6; 203 color: #333; 204 background: #fff; 205 font-size: 14px; 206 max-width: 1200px; 207 margin: 0 auto; 208 padding: 2rem; 209 } 210 211 /* Cover page */ 212 .cover { 213 text-align: center; 214 padding: 4rem 2rem; 215 margin-bottom: 3rem; 216 border-bottom: 3px solid #2563eb; 217 page-break-after: always; 218 } 219 220 .cover h1 { 221 font-size: 3rem; 222 color: #1e293b; 223 margin-bottom: 1rem; 224 } 225 226 .cover .subtitle { 227 font-size: 1.5rem; 228 color: #64748b; 229 margin-bottom: 2rem; 230 } 231 232 .cover .meta { 233 color: #94a3b8; 234 font-size: 1rem; 235 } 236 237 /* Table of contents */ 238 .toc { 239 background: #f8fafc; 240 padding: 2rem; 241 border-radius: 8px; 242 margin-bottom: 3rem; 243 page-break-after: always; 244 } 245 246 .toc h2 { 247 color: #1e293b; 248 margin-bottom: 1.5rem; 249 font-size: 1.8rem; 250 } 251 252 .toc ol { 253 list-style: none; 254 counter-reset: toc-counter; 255 } 256 257 .toc li { 258 counter-increment: toc-counter; 259 margin-bottom: 0.75rem; 260 } 261 262 .toc li::before { 263 content: counter(toc-counter) ". "; 264 font-weight: bold; 265 color: #2563eb; 266 margin-right: 0.5rem; 267 } 268 269 .toc a { 270 color: #1e293b; 271 text-decoration: none; 272 font-size: 1.1rem; 273 transition: color 0.2s; 274 } 275 276 .toc a:hover { 277 color: #2563eb; 278 } 279 280 /* Section styles */ 281 .document-section { 282 margin-bottom: 3rem; 283 } 284 285 .section-title { 286 color: #1e293b; 287 font-size: 2.5rem; 288 margin-bottom: 2rem; 289 padding-bottom: 0.5rem; 290 border-bottom: 2px solid #e2e8f0; 291 } 292 293 .section-content h1 { 294 color: #1e293b; 295 font-size: 2rem; 296 margin-top: 2rem; 297 margin-bottom: 1rem; 298 } 299 300 .section-content h2 { 301 color: #334155; 302 font-size: 1.6rem; 303 margin-top: 1.75rem; 304 margin-bottom: 0.75rem; 305 } 306 307 .section-content h3 { 308 color: #475569; 309 font-size: 1.3rem; 310 margin-top: 1.5rem; 311 margin-bottom: 0.5rem; 312 } 313 314 .section-content p { 315 margin-bottom: 1rem; 316 text-align: justify; 317 } 318 319 .section-content ul, 320 .section-content ol { 321 margin-left: 2rem; 322 margin-bottom: 1rem; 323 } 324 325 .section-content li { 326 margin-bottom: 0.5rem; 327 } 328 329 .section-content code { 330 background: #f1f5f9; 331 padding: 0.2rem 0.4rem; 332 border-radius: 3px; 333 font-family: 'Monaco', 'Courier New', monospace; 334 font-size: 0.9em; 335 color: #dc2626; 336 } 337 338 .section-content pre { 339 background: #1e293b; 340 color: #e2e8f0; 341 padding: 1rem; 342 border-radius: 6px; 343 overflow-x: auto; 344 margin-bottom: 1rem; 345 font-size: 0.85rem; 346 } 347 348 .section-content pre code { 349 background: none; 350 color: inherit; 351 padding: 0; 352 } 353 354 .section-content table.data-table { 355 width: 100%; 356 border-collapse: collapse; 357 margin: 1.5rem 0; 358 font-size: 0.9rem; 359 } 360 361 .section-content table.data-table th { 362 background: #2563eb; 363 color: white; 364 padding: 0.75rem; 365 text-align: left; 366 font-weight: 600; 367 } 368 369 .section-content table.data-table td { 370 padding: 0.75rem; 371 border-bottom: 1px solid #e2e8f0; 372 } 373 374 .section-content table.data-table tr:hover { 375 background: #f8fafc; 376 } 377 378 .section-content a { 379 color: #2563eb; 380 text-decoration: none; 381 } 382 383 .section-content a:hover { 384 text-decoration: underline; 385 } 386 387 .section-content hr { 388 border: none; 389 border-top: 1px solid #e2e8f0; 390 margin: 2rem 0; 391 } 392 393 .section-content strong { 394 color: #1e293b; 395 font-weight: 600; 396 } 397 398 .section-content em { 399 color: #64748b; 400 } 401 402 /* Page breaks for printing */ 403 .page-break { 404 page-break-after: always; 405 height: 0; 406 margin: 0; 407 padding: 0; 408 } 409 410 /* Print styles */ 411 @media print { 412 body { 413 font-size: 11pt; 414 max-width: 100%; 415 padding: 0; 416 } 417 418 .cover, 419 .toc, 420 .document-section { 421 page-break-inside: avoid; 422 } 423 424 .section-title { 425 page-break-after: avoid; 426 } 427 428 a { 429 color: inherit; 430 text-decoration: none; 431 } 432 433 .section-content table.data-table { 434 page-break-inside: avoid; 435 } 436 } 437 438 /* Screen-only navigation */ 439 @media screen { 440 .back-to-top { 441 position: fixed; 442 bottom: 2rem; 443 right: 2rem; 444 background: #2563eb; 445 color: white; 446 padding: 0.75rem 1.5rem; 447 border-radius: 50px; 448 text-decoration: none; 449 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 450 transition: all 0.3s; 451 } 452 453 .back-to-top:hover { 454 background: #1d4ed8; 455 transform: translateY(-2px); 456 box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); 457 } 458 } 459 </style> 460 </head> 461 <body> 462 <div class="cover"> 463 <h1>333 Method</h1> 464 <div class="subtitle">Business Plan & Strategic Analysis</div> 465 <div class="meta"> 466 <p><strong>Generated:</strong> ${new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}</p> 467 <p><strong>Status:</strong> Confidential</p> 468 </div> 469 </div> 470 471 ${toc} 472 473 ${sections} 474 475 <a href="#" class="back-to-top">↑ Back to Top</a> 476 477 <script> 478 // Smooth scrolling for anchor links 479 document.querySelectorAll('a[href^="#"]').forEach(anchor => { 480 anchor.addEventListener('click', function (e) { 481 e.preventDefault(); 482 const target = document.querySelector(this.getAttribute('href')); 483 if (target) { 484 target.scrollIntoView({ behavior: 'smooth', block: 'start' }); 485 } 486 }); 487 }); 488 </script> 489 </body> 490 </html>`; 491 492 // Ensure exports directory exists 493 const exportsDir = join(rootDir, 'exports'); 494 if (!existsSync(exportsDir)) { 495 mkdirSync(exportsDir, { recursive: true }); 496 } 497 498 // Write HTML file 499 const timestamp = new Date().toISOString().split('T')[0]; 500 const outputPath = join(exportsDir, `333Method-Business-Plan-${timestamp}.html`); 501 writeFileSync(outputPath, html, 'utf-8'); 502 503 console.log('\n✅ Business plan exported successfully!'); 504 console.log(`📄 File: ${outputPath}`); 505 console.log(`📊 Included ${documentContents.length} documents`); 506 console.log('\n💡 To view:'); 507 console.log(` Open in browser: file://${outputPath}`); 508 console.log(` Or use: xdg-open "${outputPath}"`); 509 510 return outputPath; 511 } 512 513 // Run 514 try { 515 generateBusinessPlanHTML(); 516 } catch (error) { 517 console.error('❌ Error generating business plan:', error); 518 process.exit(1); 519 }