@knowcode/doc-builder 1.9.30 → 1.10.0

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.
Files changed (198) hide show
  1. package/lib/core-builder.js +164 -174
  2. package/lib/emoji-mapper.js +27 -12
  3. package/package.json +12 -2
  4. package/.claude/settings.local.json +0 -56
  5. package/CACHE-BUSTING-GUIDE.md +0 -82
  6. package/CLAUDE.md +0 -86
  7. package/CONTRIBUTING.md +0 -148
  8. package/GITHUB_SETUP.md +0 -203
  9. package/RELEASE-NOTES-1.7.5.md +0 -64
  10. package/Screenshot 2025-07-22 at 19.51.21.png +0 -0
  11. package/Screenshot 2025-07-26 at 17.06.49.png +0 -0
  12. package/add-user-clive.sql +0 -35
  13. package/add-user-lindsay-fixed.sql +0 -85
  14. package/add-user-lindsay.sql +0 -68
  15. package/add-user-pmorgan.sql +0 -35
  16. package/add-user-robbie.sql +0 -35
  17. package/add-wru-users.sql +0 -105
  18. package/debug-login.sql +0 -30
  19. package/doc-builder.config.js +0 -126
  20. package/doc-builder.config.js.backup.1753793768283 +0 -47
  21. package/doc-builder.config.js.backup.1753803964423 +0 -114
  22. package/doc-builder.config.js.backup.1753945707032 +0 -115
  23. package/doc-builder.config.js.backup.1754059241330 +0 -115
  24. package/doc-builder.config.js.backup.1754119567787 +0 -123
  25. package/doc-builder.config.js.backup.1754120048862 +0 -124
  26. package/doc-builder.config.js.backup.1754120529913 +0 -124
  27. package/doc-builder.config.js.backup.1754218469785 +0 -124
  28. package/doc-builder.config.js.backup.1754384764054 +0 -124
  29. package/doc-builder.config.js.backup.1754567425847 +0 -124
  30. package/doc-builder.config.js.backup.1754568137859 +0 -126
  31. package/doc-builder.config.js.backup.1754569388252 +0 -126
  32. package/doc-builder.config.js.backup.1754576694123 +0 -126
  33. package/doc-builder.config.js.backup.1755031374829 +0 -126
  34. package/doc-builder.config.js.backup.1755034500990 +0 -126
  35. package/doc-builder.config.js.backup.1755034809236 +0 -126
  36. package/grant-access.sql +0 -15
  37. package/html/11.png +0 -0
  38. package/html/404.html +0 -115
  39. package/html/README.html +0 -522
  40. package/html/Screenshot 2025-08-12 at 21.35.07.png +0 -0
  41. package/html/about-doc-builder.html +0 -491
  42. package/html/auth.js +0 -157
  43. package/html/claude-workflow-guide.html +0 -525
  44. package/html/css/notion-style.css +0 -2502
  45. package/html/documentation-index.html +0 -471
  46. package/html/guides/authentication-default-change.html +0 -370
  47. package/html/guides/authentication-guide.html +0 -509
  48. package/html/guides/cache-control-anti-pattern.html +0 -361
  49. package/html/guides/claude-workflow-guide.html +0 -1074
  50. package/html/guides/configuration-guide.html +0 -472
  51. package/html/guides/document-standards.html +0 -518
  52. package/html/guides/documentation-standards.html +0 -694
  53. package/html/guides/html-embedding-guide.html +0 -461
  54. package/html/guides/image-modal-guide.html +0 -515
  55. package/html/guides/next-steps-walkthrough.html +0 -638
  56. package/html/guides/phosphor-icons-guide.html +0 -584
  57. package/html/guides/private-directory-authentication-troubleshooting.html +0 -555
  58. package/html/guides/private-directory-authentication.html +0 -541
  59. package/html/guides/public-site-deployment.html +0 -431
  60. package/html/guides/search-engine-verification-guide.html +0 -542
  61. package/html/guides/seo-guide.html +0 -661
  62. package/html/guides/seo-optimization-guide.html +0 -887
  63. package/html/guides/supabase-auth-implementation-plan.html +0 -543
  64. package/html/guides/supabase-auth-integration-plan.html +0 -671
  65. package/html/guides/supabase-auth-setup-guide.html +0 -498
  66. package/html/guides/supabase-authentication-complete-guide.html +0 -866
  67. package/html/guides/troubleshooting-guide.html +0 -633
  68. package/html/guides/vercel-deployment-auth-setup.html +0 -337
  69. package/html/guides/windows-setup-guide.html +0 -859
  70. package/html/image-modal-test.html +0 -318
  71. package/html/index.html +0 -522
  72. package/html/js/auth.js +0 -157
  73. package/html/js/main.js +0 -1754
  74. package/html/launch/README.html +0 -297
  75. package/html/launch/bubble-plugin-specification.html +0 -933
  76. package/html/launch/go-to-market-strategy.html +0 -663
  77. package/html/launch/launch-announcements.html +0 -593
  78. package/html/login.html +0 -102
  79. package/html/logout.html +0 -18
  80. package/html/private/cache-control-anti-pattern.html +0 -429
  81. package/html/private/launch/README.html +0 -371
  82. package/html/private/launch/auth-cleanup-summary.html +0 -361
  83. package/html/private/launch/bubble-plugin-specification.html +0 -1007
  84. package/html/private/launch/go-to-market-strategy.html +0 -737
  85. package/html/private/launch/launch-announcements.html +0 -667
  86. package/html/private/launch/vercel-deployment-auth-setup.html +0 -417
  87. package/html/private/next-steps-walkthrough.html +0 -679
  88. package/html/private/supabase-auth-implementation-completed.html +0 -454
  89. package/html/private/supabase-auth-implementation-plan.html +0 -594
  90. package/html/private/supabase-auth-integration-plan.html +0 -704
  91. package/html/private/supabase-auth-setup-guide.html +0 -555
  92. package/html/private/test-private-doc.html +0 -302
  93. package/html/private/user-management-tooling.html +0 -601
  94. package/html/prompts/Screenshot 2025-08-02 at 08.49.55.png +0 -0
  95. package/html/prompts/beautiful-documentation-design.html +0 -784
  96. package/html/prompts/markdown-document-standards.html +0 -422
  97. package/html/prompts/project-rename-strategy-sasha-publish.html +0 -530
  98. package/html/robots.txt +0 -9
  99. package/html/sitemap.xml +0 -357
  100. package/html/test-questions/how-does-it-work%3F.html +0 -294
  101. package/html/test-questions/step-1%3A%20getting-started.html +0 -289
  102. package/html/test-questions/what-is-the-purpose.html +0 -293
  103. package/html/test-status.html +0 -281
  104. package/html/vercel-cli-setup-guide.html +0 -495
  105. package/html/vercel-first-time-setup-guide.html +0 -454
  106. package/html/vercel.json +0 -29
  107. package/html-static/11.png +0 -0
  108. package/html-static/404.html +0 -115
  109. package/html-static/README.html +0 -609
  110. package/html-static/Screenshot 2025-08-12 at 21.35.07.png +0 -0
  111. package/html-static/about-doc-builder.html +0 -578
  112. package/html-static/css/notion-style.css +0 -2502
  113. package/html-static/documentation-index.html +0 -558
  114. package/html-static/guides/authentication-default-change.html +0 -457
  115. package/html-static/guides/authentication-guide.html +0 -596
  116. package/html-static/guides/claude-workflow-guide.html +0 -1161
  117. package/html-static/guides/configuration-guide.html +0 -559
  118. package/html-static/guides/documentation-standards.html +0 -781
  119. package/html-static/guides/html-embedding-guide.html +0 -548
  120. package/html-static/guides/image-modal-guide.html +0 -602
  121. package/html-static/guides/phosphor-icons-guide.html +0 -671
  122. package/html-static/guides/private-directory-authentication-troubleshooting.html +0 -642
  123. package/html-static/guides/private-directory-authentication.html +0 -628
  124. package/html-static/guides/public-site-deployment.html +0 -518
  125. package/html-static/guides/search-engine-verification-guide.html +0 -629
  126. package/html-static/guides/seo-guide.html +0 -748
  127. package/html-static/guides/seo-optimization-guide.html +0 -974
  128. package/html-static/guides/supabase-authentication-complete-guide.html +0 -953
  129. package/html-static/guides/troubleshooting-guide.html +0 -720
  130. package/html-static/guides/windows-setup-guide.html +0 -946
  131. package/html-static/image-modal-test.html +0 -405
  132. package/html-static/index.html +0 -609
  133. package/html-static/js/main.js +0 -1754
  134. package/html-static/prompts/Screenshot 2025-08-02 at 08.49.55.png +0 -0
  135. package/html-static/prompts/beautiful-documentation-design.html +0 -871
  136. package/html-static/prompts/markdown-document-standards.html +0 -509
  137. package/html-static/prompts/project-rename-strategy-sasha-publish.html +0 -617
  138. package/html-static/robots.txt +0 -5
  139. package/html-static/sitemap.xml +0 -195
  140. package/html-static/test-questions/how-does-it-work%3F.html +0 -381
  141. package/html-static/test-questions/step-1%3A%20getting-started.html +0 -376
  142. package/html-static/test-questions/what-is-the-purpose.html +0 -380
  143. package/html-static/vercel-cli-setup-guide.html +0 -582
  144. package/html-static/vercel-first-time-setup-guide.html +0 -541
  145. package/manage-users.sql +0 -191
  146. package/migrate-to-domain-auth.sql +0 -47
  147. package/package/CACHE-BUSTING-GUIDE.md +0 -82
  148. package/package/CHANGELOG.md +0 -902
  149. package/package/README.md +0 -248
  150. package/package/assets/css/notion-style.css +0 -2211
  151. package/package/assets/js/auth.js +0 -67
  152. package/package/assets/js/main.js +0 -1565
  153. package/package/cli.js +0 -764
  154. package/package/index.js +0 -38
  155. package/package/knowcode-doc-builder-1.3.15.tgz +0 -0
  156. package/package/lib/builder.js +0 -32
  157. package/package/lib/config.js +0 -278
  158. package/package/lib/core-builder.js +0 -957
  159. package/package/lib/deploy.js +0 -497
  160. package/package/lib/dev-server.js +0 -96
  161. package/package/package.json +0 -34
  162. package/package/scripts/npx-runner.js +0 -27
  163. package/package/scripts/setup.js +0 -56
  164. package/package/test-cache-bust.sh +0 -43
  165. package/public-config.js +0 -22
  166. package/public-html/404.html +0 -115
  167. package/public-html/README.html +0 -149
  168. package/public-html/css/notion-style.css +0 -2036
  169. package/public-html/index.html +0 -149
  170. package/public-html/js/auth.js +0 -67
  171. package/public-html/js/main.js +0 -1485
  172. package/quick-test-commands.md +0 -40
  173. package/recordings/Screenshot 2025-07-24 at 18.22.01.png +0 -0
  174. package/recordings/mh-ls-22jul.txt +0 -2305
  175. package/screenshot.png +0 -0
  176. package/scripts/Screenshot 2025-07-23 at 15.39.41.png +0 -0
  177. package/setup-database-v2.sql +0 -53
  178. package/setup-database.sql +0 -41
  179. package/test-auth-config.js +0 -17
  180. package/test-cache-bust.sh +0 -43
  181. package/test-docs/README.md +0 -39
  182. package/test-html/404.html +0 -115
  183. package/test-html/README.html +0 -172
  184. package/test-html/auth.js +0 -97
  185. package/test-html/css/notion-style.css +0 -2036
  186. package/test-html/index.html +0 -172
  187. package/test-html/js/auth.js +0 -97
  188. package/test-html/js/main.js +0 -1485
  189. package/test-html/login.html +0 -102
  190. package/test-html/logout.html +0 -18
  191. package/update-domain.sql +0 -9
  192. package/user-access-view.sql +0 -49
  193. package/user-management/README.md +0 -301
  194. package/user-management/add-users.sh +0 -776
  195. package/user-management/create-user.js +0 -65
  196. package/user-management/users.txt +0 -15
  197. package/view-all-users.sql +0 -40
  198. package/wru-auth-config.js +0 -17
@@ -1,957 +0,0 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const marked = require('marked');
4
- const chalk = require('chalk');
5
-
6
- // Configure marked options
7
- marked.setOptions({
8
- highlight: function(code, lang) {
9
- return `<code class="language-${lang}">${escapeHtml(code)}</code>`;
10
- },
11
- breaks: true,
12
- gfm: true
13
- });
14
-
15
- // Helper function to escape HTML
16
- function escapeHtml(text) {
17
- const map = {
18
- '&': '&amp;',
19
- '<': '&lt;',
20
- '>': '&gt;',
21
- '"': '&quot;',
22
- "'": '&#039;'
23
- };
24
- return text.replace(/[&<>"']/g, m => map[m]);
25
- }
26
-
27
- // Process markdown content
28
- function processMarkdownContent(content) {
29
- // Convert mermaid code blocks to mermaid divs with titles
30
- content = content.replace(/```mermaid\n([\s\S]*?)```/g, (match, mermaidContent) => {
31
- // Try to extract title from mermaid content
32
- let title = 'Diagram';
33
-
34
- // Look for title in various mermaid formats
35
- const titlePatterns = [
36
- /title\s+([^\n]+)/i, // gantt charts: title My Title
37
- /graph\s+\w+\[["']([^"']+)["']\]/, // graph TD["My Title"]
38
- /flowchart\s+\w+\[["']([^"']+)["']\]/, // flowchart TD["My Title"]
39
- /---\s*title:\s*([^\n]+)\s*---/, // frontmatter style
40
- ];
41
-
42
- for (const pattern of titlePatterns) {
43
- const match = mermaidContent.match(pattern);
44
- if (match) {
45
- title = match[1].trim();
46
- break;
47
- }
48
- }
49
-
50
- return `<div class="mermaid-wrapper">
51
- <div class="mermaid-title">${escapeHtml(title)}</div>
52
- <div class="mermaid">${escapeHtml(mermaidContent)}</div>
53
- </div>`;
54
- });
55
-
56
- return marked.parse(content);
57
- }
58
-
59
- // Generate HTML from template
60
- function generateHTML(title, content, navigation, currentPath = '', config = {}) {
61
- const depth = currentPath.split('/').filter(p => p).length;
62
- const relativePath = depth > 0 ? '../'.repeat(depth) : '';
63
-
64
- const siteName = config.siteName || 'Documentation';
65
- const siteDescription = config.siteDescription || 'Documentation site';
66
-
67
- return `<!DOCTYPE html>
68
- <html lang="en">
69
- <head>
70
- <meta charset="UTF-8">
71
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
72
- <meta name="description" content="${siteDescription}">
73
- <title>${title} - ${siteName}</title>
74
-
75
- <!-- Fonts -->
76
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
77
-
78
- <!-- Icons -->
79
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
80
-
81
- <!-- Mermaid -->
82
- <script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
83
-
84
- <!-- Styles -->
85
- <link rel="stylesheet" href="/css/notion-style.css">
86
- <link rel="stylesheet" href="/css/style.css">
87
-
88
- <!-- Favicon -->
89
- <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📚</text></svg>">
90
- </head>
91
- <body>
92
- <!-- Header -->
93
- <header class="header">
94
- <div class="header-content">
95
- <a href="/index.html" class="logo">${siteName}</a>
96
-
97
- <div class="header-actions">
98
- <div class="deployment-info">
99
- <span class="deployment-date">Last updated: ${new Date().toLocaleDateString('en-US', {
100
- year: 'numeric',
101
- month: 'short',
102
- day: 'numeric',
103
- hour: '2-digit',
104
- minute: '2-digit',
105
- timeZone: 'UTC'
106
- })} UTC</span>
107
- </div>
108
-
109
- ${config.features?.authentication ? `
110
- <a href="${relativePath}logout.html" class="logout-btn" title="Logout">
111
- <i class="fas fa-sign-out-alt"></i>
112
- </a>
113
- ` : ''}
114
-
115
- <button id="theme-toggle" class="theme-toggle" aria-label="Toggle theme">
116
- <i class="fas fa-moon"></i>
117
- </button>
118
-
119
- <button id="menu-toggle" class="menu-toggle" aria-label="Toggle menu">
120
- <i class="fas fa-bars"></i>
121
- </button>
122
- </div>
123
- </div>
124
- </header>
125
-
126
- <!-- Preview Banner -->
127
- <div id="preview-banner" class="preview-banner">
128
- <div class="banner-content">
129
- <i class="fas fa-exclamation-triangle banner-icon"></i>
130
- <span class="banner-text">This documentation is a preview version - some content may be incomplete</span>
131
- <button id="dismiss-banner" class="banner-dismiss" aria-label="Dismiss banner">
132
- <i class="fas fa-times"></i>
133
- </button>
134
- </div>
135
- </div>
136
-
137
- <!-- Breadcrumbs -->
138
- <nav class="breadcrumbs" id="breadcrumbs">
139
- <!-- Breadcrumbs will be generated by JavaScript -->
140
- </nav>
141
-
142
- <!-- Main Content -->
143
- <div class="main-wrapper">
144
- <!-- Sidebar -->
145
- <aside class="sidebar">
146
- <div class="sidebar-header">
147
- <div class="sidebar-breadcrumbs">
148
- <a href="/index.html" class="sidebar-home-link">
149
- <i class="fas fa-home"></i>
150
- <span>Home</span>
151
- </a>
152
- </div>
153
- <div class="filter-box">
154
- <input type="text" placeholder="Filter items..." class="filter-input" id="nav-filter">
155
- <i class="fas fa-search filter-icon"></i>
156
- </div>
157
- </div>
158
- <nav class="navigation">
159
- ${navigation}
160
- </nav>
161
- <div class="resize-handle"></div>
162
- </aside>
163
-
164
- <!-- Content Area -->
165
- <main class="content">
166
- <div class="content-inner">
167
- ${content}
168
- </div>
169
- </main>
170
- </div>
171
-
172
- <!-- Scripts -->
173
- <script src="/js/main.js"></script>
174
- ${config.features?.authentication ? `<script src="/js/auth.js"></script>` : ''}
175
- </body>
176
- </html>`;
177
- }
178
-
179
- // Define folder descriptions for tooltips
180
- const folderDescriptions = {
181
- 'product-roadmap': 'Strategic vision, timeline, and feature planning',
182
- 'product-requirements': 'Detailed product specifications, requirements documents, and feature definitions',
183
- 'architecture': 'System design, data flows, and technical infrastructure documentation',
184
- 'system-analysis': 'Comprehensive system analysis, functional requirements, and cross-component documentation',
185
- 'bubble': 'Core application platform - business logic, UI/UX, and user workflows',
186
- 'quickbase': 'Database schema, data management, and backend operations',
187
- 'activecampaign': 'Marketing automation integration and lead management system',
188
- 'doc-signer': 'Document signing service for digital signatures and PDF generation',
189
- 'api-deprecated': 'Legacy API documentation (deprecated, for reference only)',
190
- 'postman': 'API testing tools, collections, and test automation',
191
- 'mcp': 'Model Context Protocol integration and configuration',
192
- 'team': 'Team structure, roles, and responsibilities',
193
- 'thought-leadership': 'Strategic insights and industry perspectives',
194
- 'middleware': 'Integration layers and data transformation services',
195
- 'paths': 'User journey flows and process workflows',
196
- 'testing': 'Test strategies, scenarios, and quality assurance processes',
197
- 'api': 'API documentation and integration guides'
198
- };
199
-
200
- // Build navigation structure with rich functionality
201
- function buildNavigationStructure(files, currentFile) {
202
- const tree = { files: [], folders: {} };
203
-
204
- files.forEach(file => {
205
- const parts = file.urlPath.split('/');
206
- let current = tree;
207
-
208
- // Navigate/create folder structure
209
- for (let i = 0; i < parts.length - 1; i++) {
210
- const folder = parts[i];
211
- if (!current.folders[folder]) {
212
- current.folders[folder] = { files: [], folders: {} };
213
- }
214
- current = current.folders[folder];
215
- }
216
-
217
- // Add file to current folder
218
- current.files.push(file);
219
- });
220
-
221
- // Helper function to check if a node has active child
222
- const checkActiveChild = (node, currentFile) => {
223
- // Check files
224
- if (node.files.some(f => f.urlPath === currentFile)) return true;
225
-
226
- // Check folders recursively
227
- return Object.values(node.folders).some(folder => checkActiveChild(folder, currentFile));
228
- };
229
-
230
- // Helper function to generate file title
231
- const generateFileTitle = (file, parentDisplayName, level) => {
232
- let title = file.displayName;
233
-
234
- if (file.displayName === 'README') {
235
- return level === 0 ? 'Overview' : `${parentDisplayName} Overview`;
236
- }
237
-
238
- // Clean up title by removing common prefixes and improving formatting
239
- title = title
240
- .replace(/^(bubble|system|quickbase|middleware|product-roadmap)-?/, '')
241
- .replace(/-/g, ' ')
242
- .replace(/\b\w/g, l => l.toUpperCase());
243
-
244
- return title;
245
- };
246
-
247
- // Helper function to render a section
248
- const renderSection = (folderName, folderData, level = 0, parentPath = '') => {
249
- const icons = {
250
- 'root': 'fas fa-home',
251
- 'product-roadmap': 'fas fa-road',
252
- 'product-requirements': 'fas fa-clipboard-list',
253
- 'architecture': 'fas fa-sitemap',
254
- 'system-analysis': 'fas fa-chart-line',
255
- 'system': 'fas fa-cogs',
256
- 'bubble': 'fas fa-circle',
257
- 'quickbase': 'fas fa-database',
258
- 'activecampaign': 'fas fa-envelope',
259
- 'doc-signer': 'fas fa-signature',
260
- 'api-deprecated': 'fas fa-archive',
261
- 'postman': 'fas fa-flask',
262
- 'mcp': 'fas fa-puzzle-piece',
263
- 'team': 'fas fa-users',
264
- 'thought-leadership': 'fas fa-lightbulb',
265
- 'middleware': 'fas fa-layer-group',
266
- 'paths': 'fas fa-route',
267
- 'testing': 'fas fa-vial',
268
- 'api': 'fas fa-plug',
269
- 'documentation-tool': 'fas fa-tools'
270
- };
271
-
272
- const displayName = folderName === 'root' ? 'Documentation' :
273
- folderName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
274
- const icon = icons[folderName] || 'fas fa-folder';
275
-
276
- if (!folderData.files.length && !Object.keys(folderData.folders).length) {
277
- return '';
278
- }
279
-
280
- // Include parent path in section ID to make it unique
281
- const pathParts = parentPath ? [parentPath, folderName].join('-') : folderName;
282
- const sectionId = `nav-${pathParts}-${level}`;
283
- const isCollapsible = level > 0 || folderName !== 'root';
284
- const collapseIcon = isCollapsible ? '<i class="fas fa-chevron-right collapse-icon"></i>' : '';
285
-
286
- // Check if this folder has a README.md file to link to
287
- const readmeFile = folderData.files.find(f => f.displayName === 'README');
288
- const folderLink = readmeFile ? `href="/${readmeFile.urlPath}"` : 'href="#"';
289
-
290
- // Get folder description for tooltip
291
- const folderDescription = folderDescriptions[folderName] || '';
292
- const tooltipAttr = folderDescription ? `data-tooltip="${escapeHtml(folderDescription)}"` : '';
293
-
294
- // Start all sections collapsed by default (JavaScript will expand sections containing active items)
295
- const hasActiveChild = checkActiveChild(folderData, currentFile);
296
-
297
- let html = `
298
- <div class="nav-section" data-level="${level}">
299
- <a class="nav-title${isCollapsible ? ' collapsible' : ''}${hasActiveChild ? ' expanded' : ''}" ${folderLink} ${isCollapsible ? `data-target="${sectionId}"` : ''} ${tooltipAttr}>
300
- ${collapseIcon}<i class="${icon}"></i> ${displayName}
301
- </a>
302
- <div class="nav-content${isCollapsible ? (hasActiveChild ? '' : ' collapsed') : ''}" ${isCollapsible ? `id="${sectionId}"` : ''}>`;
303
-
304
- // Sort and render files
305
- const sortedFiles = [...folderData.files].sort((a, b) => {
306
- if (a.displayName === 'README') return -1;
307
- if (b.displayName === 'README') return 1;
308
- return a.displayName.localeCompare(b.displayName);
309
- });
310
-
311
- sortedFiles.forEach(file => {
312
- const title = generateFileTitle(file, displayName, level);
313
-
314
- // Check if this file is active
315
- let isActive = '';
316
- if (currentFile === file.urlPath) {
317
- isActive = ' active';
318
- } else if (currentFile === 'index.html' && file.displayName === 'README' && folderName === 'root') {
319
- // Mark root README as active when viewing index.html
320
- isActive = ' active';
321
- }
322
-
323
- const linkPath = '/' + file.urlPath;
324
-
325
- html += `
326
- <a href="${linkPath}" class="nav-item${isActive}"><i class="fas fa-file-alt"></i> ${title}</a>`;
327
- });
328
-
329
- html += `</div></div>`;
330
-
331
- // Render subfolders AFTER closing the parent section
332
- Object.keys(folderData.folders)
333
- .sort()
334
- .forEach(subFolder => {
335
- // Build the path for the subfolder including current folder
336
- const currentPath = parentPath ? `${parentPath}-${folderName}` : folderName;
337
- html += renderSection(subFolder, folderData.folders[subFolder], level + 1, currentPath);
338
- });
339
-
340
- return html;
341
- };
342
-
343
- // Check if this is a flat structure
344
- const hasFolders = Object.keys(tree.folders).length > 0;
345
-
346
- if (!hasFolders) {
347
- // Generate simple flat navigation for all files in root
348
- return renderSection('root', { files: tree.files, folders: {} }, 0);
349
- } else {
350
- // Generate hierarchical navigation
351
- let nav = '';
352
-
353
- // Render root files first
354
- if (tree.files.length > 0) {
355
- nav += renderSection('root', { files: tree.files, folders: {} }, 0);
356
- }
357
-
358
- // Add other top-level folders in logical order
359
- const folderOrder = [
360
- 'product-roadmap',
361
- 'product-requirements',
362
- 'architecture',
363
- 'system-analysis',
364
- 'bubble',
365
- 'quickbase',
366
- 'activecampaign',
367
- 'doc-signer',
368
- 'api-deprecated',
369
- 'postman',
370
- 'mcp',
371
- 'team',
372
- 'thought-leadership',
373
- 'documentation-tool'
374
- ];
375
-
376
- folderOrder.forEach(folderName => {
377
- if (tree.folders[folderName]) {
378
- nav += renderSection(folderName, tree.folders[folderName], 1);
379
- delete tree.folders[folderName]; // Remove so we don't render it again
380
- }
381
- });
382
-
383
- // Render any remaining folders not in the predefined order
384
- Object.keys(tree.folders)
385
- .sort()
386
- .forEach(folderName => {
387
- nav += renderSection(folderName, tree.folders[folderName], 1);
388
- });
389
-
390
- return nav;
391
- }
392
- }
393
-
394
- // Process single markdown file
395
- async function processMarkdownFile(filePath, outputPath, allFiles, config) {
396
- const content = await fs.readFile(filePath, 'utf-8');
397
- const fileName = path.basename(filePath, '.md');
398
- const relativePath = path.relative(config.docsDir, filePath);
399
- const urlPath = relativePath.replace(/\.md$/, '.html').replace(/\\/g, '/');
400
-
401
- // Extract title from content
402
- const titleMatch = content.match(/^#\s+(.+)$/m);
403
- const title = titleMatch ? titleMatch[1] : fileName;
404
-
405
- // Process content
406
- const htmlContent = processMarkdownContent(content);
407
-
408
- // Build navigation
409
- const navigation = buildNavigationStructure(allFiles, urlPath);
410
-
411
- // Generate full HTML
412
- const html = generateHTML(title, htmlContent, navigation, urlPath, config);
413
-
414
- // Write file
415
- await fs.ensureDir(path.dirname(outputPath));
416
- await fs.writeFile(outputPath, html);
417
-
418
- return { title, urlPath };
419
- }
420
-
421
- // Get all markdown files
422
- async function getAllMarkdownFiles(dir, baseDir = dir) {
423
- const files = [];
424
- const items = await fs.readdir(dir);
425
-
426
- for (const item of items) {
427
- const fullPath = path.join(dir, item);
428
- const stat = await fs.stat(fullPath);
429
-
430
- if (stat.isDirectory() && !item.startsWith('.')) {
431
- const subFiles = await getAllMarkdownFiles(fullPath, baseDir);
432
- files.push(...subFiles);
433
- } else if (item.endsWith('.md')) {
434
- const relativePath = path.relative(baseDir, fullPath);
435
- const urlPath = relativePath.replace(/\.md$/, '.html').replace(/\\/g, '/');
436
- const displayName = path.basename(item, '.md')
437
- .replace(/[-_]/g, ' ')
438
- .replace(/\b\w/g, l => l.toUpperCase());
439
-
440
- files.push({
441
- path: fullPath,
442
- relativePath,
443
- urlPath,
444
- displayName
445
- });
446
- }
447
- }
448
-
449
- return files;
450
- }
451
-
452
- // Main build function
453
- async function buildDocumentation(config) {
454
- const docsDir = path.join(process.cwd(), config.docsDir);
455
- const outputDir = path.join(process.cwd(), config.outputDir);
456
-
457
- // Log version for debugging
458
- const packageJson = require('../package.json');
459
- console.log(chalk.blue(`📦 Using @knowcode/doc-builder v${packageJson.version}`));
460
-
461
- // Check and create placeholder README.md if missing
462
- console.log(chalk.blue('📋 Checking documentation structure...'));
463
- const readmeGenerated = await createPlaceholderReadme(docsDir, config);
464
-
465
- console.log(chalk.blue('📄 Scanning for markdown files...'));
466
- const files = await getAllMarkdownFiles(docsDir);
467
- console.log(chalk.green(`✅ Found ${files.length} markdown files${readmeGenerated ? ' (including auto-generated README)' : ''}`));
468
-
469
- // Log the files found
470
- if (files.length > 0) {
471
- console.log(chalk.gray(' Found files:'));
472
- files.forEach(file => {
473
- console.log(chalk.gray(` - ${file.relativePath} → ${file.urlPath}`));
474
- });
475
- }
476
-
477
- console.log(chalk.blue('📝 Processing files...'));
478
- for (const file of files) {
479
- const outputPath = path.join(outputDir, file.urlPath);
480
- await processMarkdownFile(file.path, outputPath, files, config);
481
- console.log(chalk.green(`✅ Generated: ${outputPath}`));
482
- }
483
-
484
- // Copy assets
485
- const assetsDir = path.join(__dirname, '../assets');
486
- const cssSource = path.join(assetsDir, 'css');
487
- const jsSource = path.join(assetsDir, 'js');
488
-
489
- if (fs.existsSync(cssSource)) {
490
- await fs.copy(cssSource, path.join(outputDir, 'css'), { overwrite: true });
491
- }
492
-
493
- if (fs.existsSync(jsSource)) {
494
- await fs.copy(jsSource, path.join(outputDir, 'js'), { overwrite: true });
495
-
496
- // Copy auth.js to root if authentication is enabled
497
- if (config.features?.authentication) {
498
- const authSource = path.join(jsSource, 'auth.js');
499
- const authDest = path.join(outputDir, 'auth.js');
500
- if (fs.existsSync(authSource)) {
501
- await fs.copy(authSource, authDest, { overwrite: true });
502
- }
503
- }
504
- }
505
-
506
- // Create auth pages if needed
507
- if (config.features?.authentication) {
508
- await createAuthPages(outputDir, config);
509
- }
510
-
511
- // Create index.html from index.html, README.html, or generate default
512
- const indexPath = path.join(outputDir, 'index.html');
513
- const indexSourcePath = path.join(outputDir, 'index.html'); // from index.md
514
- const readmePath = path.join(outputDir, 'README.html');
515
-
516
- console.log(chalk.blue('\n📄 Checking for index.html creation...'));
517
- console.log(chalk.gray(` - Output directory: ${outputDir}`));
518
- console.log(chalk.gray(` - Index path: ${indexPath}`));
519
- console.log(chalk.gray(` - README path: ${readmePath}`));
520
- console.log(chalk.gray(` - index.html exists: ${fs.existsSync(indexPath)}`));
521
- console.log(chalk.gray(` - README.html exists: ${fs.existsSync(readmePath)}`));
522
-
523
- // List all HTML files in output directory
524
- if (fs.existsSync(outputDir)) {
525
- const htmlFiles = fs.readdirSync(outputDir).filter(f => f.endsWith('.html'));
526
- console.log(chalk.gray(` - HTML files in output: [${htmlFiles.join(', ')}]`));
527
- } else {
528
- console.log(chalk.red(` - ERROR: Output directory does not exist!`));
529
- }
530
-
531
- // Check if we need to create/replace index.html
532
- let shouldCreateIndex = false;
533
-
534
- if (!fs.existsSync(indexPath)) {
535
- console.log(chalk.yellow('⚠️ index.html does not exist, need to create it'));
536
- shouldCreateIndex = true;
537
- } else {
538
- // Check if existing index.html is likely a directory listing or outdated
539
- const indexStats = fs.statSync(indexPath);
540
- const indexContent = fs.readFileSync(indexPath, 'utf8');
541
-
542
- // Check if it's a small file (likely directory listing) or contains directory listing markers
543
- if (indexStats.size < 3000 || indexContent.includes('<title>Documentation</title>') && indexContent.includes('<ul>') && !indexContent.includes('class="navigation"')) {
544
- console.log(chalk.yellow('⚠️ Existing index.html appears to be a directory listing (size: ' + indexStats.size + ' bytes), will replace it'));
545
- shouldCreateIndex = true;
546
- } else if (!indexContent.includes('@knowcode/doc-builder')) {
547
- console.log(chalk.yellow('⚠️ Existing index.html was not created by doc-builder, will replace it'));
548
- shouldCreateIndex = true;
549
- }
550
- }
551
-
552
- if (shouldCreateIndex) {
553
- if (fs.existsSync(readmePath)) {
554
- console.log(chalk.blue(' → Found README.html, copying to index.html'));
555
- try {
556
- await fs.copy(readmePath, indexPath);
557
- console.log(chalk.green('✅ Successfully created index.html from README.html'));
558
-
559
- // Verify the copy worked
560
- if (fs.existsSync(indexPath)) {
561
- const stats = fs.statSync(indexPath);
562
- console.log(chalk.gray(` - index.html size: ${stats.size} bytes`));
563
- } else {
564
- console.log(chalk.red(' - ERROR: index.html was not created!'));
565
- }
566
- } catch (error) {
567
- console.log(chalk.red(` - ERROR copying README.html: ${error.message}`));
568
- }
569
- } else {
570
- // No README.html, create informative default page
571
- console.log(chalk.yellow('⚠️ No README.html found, creating default index.html'));
572
- try {
573
- const defaultIndex = await createDefaultIndexPage(outputDir, config, packageJson.version);
574
- await fs.writeFile(indexPath, defaultIndex);
575
- console.log(chalk.green('✅ Created default index.html with instructions'));
576
-
577
- // Verify the write worked
578
- if (fs.existsSync(indexPath)) {
579
- const stats = fs.statSync(indexPath);
580
- console.log(chalk.gray(` - index.html size: ${stats.size} bytes`));
581
- } else {
582
- console.log(chalk.red(' - ERROR: default index.html was not created!'));
583
- }
584
- } catch (error) {
585
- console.log(chalk.red(` - ERROR creating default index.html: ${error.message}`));
586
- }
587
- }
588
- } else {
589
- console.log(chalk.gray('ℹ️ index.html already exists and appears valid'));
590
- const stats = fs.statSync(indexPath);
591
- console.log(chalk.gray(` - Existing index.html size: ${stats.size} bytes`));
592
- console.log(chalk.gray(` - Keeping existing index.html (likely from index.md or custom page)`));
593
- }
594
-
595
- // Final verification
596
- console.log(chalk.blue('\n📋 Final index.html check:'));
597
- if (fs.existsSync(indexPath)) {
598
- console.log(chalk.green(` ✅ index.html exists at: ${indexPath}`));
599
- } else {
600
- console.log(chalk.red(` ❌ index.html is MISSING at: ${indexPath}`));
601
- }
602
-
603
- console.log(chalk.green('✅ Documentation build complete!'));
604
- }
605
-
606
- // Create placeholder README.md if missing
607
- async function createPlaceholderReadme(docsDir, config) {
608
- const readmePath = path.join(docsDir, 'README.md');
609
- const indexPath = path.join(docsDir, 'index.md');
610
-
611
- // Check if README.md or index.md already exists
612
- if (fs.existsSync(readmePath)) {
613
- console.log(chalk.gray(' ✓ README.md found'));
614
- return false; // README already exists, no need to create
615
- }
616
-
617
- if (fs.existsSync(indexPath)) {
618
- console.log(chalk.gray(' ✓ index.md found'));
619
- return false; // index.md exists, no need for README
620
- }
621
-
622
- const siteName = config.siteName || 'Documentation';
623
- const currentDate = new Date().toISOString().split('T')[0];
624
-
625
- const placeholderContent = `# Welcome to ${siteName}
626
-
627
- **Generated**: ${currentDate} UTC
628
- **Status**: Placeholder - Ready for customization
629
- **Verified**: ❓ (Auto-generated content)
630
-
631
- ## Overview
632
-
633
- This documentation site was built with @knowcode/doc-builder. This is an auto-generated placeholder to help you get started.
634
-
635
- ## Getting Started
636
-
637
- 1. **Replace this file**: Edit \`docs/README.md\` with your project's actual documentation
638
- 2. **Add content**: Create additional markdown files in the \`docs/\` directory
639
- 3. **Organize with folders**: Use subfolders to structure your documentation
640
- 4. **Rebuild**: Run \`npx @knowcode/doc-builder build\` to regenerate the site
641
-
642
- ## Documentation Structure
643
-
644
- Your documentation can include:
645
-
646
- - **Overview**: Main project description (this file)
647
- - **Guides**: Step-by-step tutorials
648
- - **API Reference**: Technical documentation
649
- - **Examples**: Code samples and usage
650
- - **Architecture**: System design and technical details
651
-
652
- ## Next Steps
653
-
654
- 1. Edit this README.md file with your project information
655
- 2. Create additional markdown files for your content
656
- 3. Organize files into logical folders
657
- 4. Use Mermaid diagrams for visual explanations
658
- 5. Deploy with \`npx @knowcode/doc-builder deploy\`
659
-
660
- ## Documentation Standards
661
-
662
- This project follows structured documentation conventions:
663
-
664
- ### File Organization
665
- - Use descriptive filenames with hyphens (e.g., \`user-guide.md\`)
666
- - Organize related content in folders
667
- - Include a README.md in each major folder
668
-
669
- ### Content Format
670
- - Start each document with metadata (Generated date, Status, Verified status)
671
- - Use clear headings and consistent structure
672
- - Include diagrams where helpful to explain concepts
673
- - Mark information as verified (✅) or speculated (❓)
674
-
675
- ### Mermaid Diagrams
676
- Include visual diagrams to explain complex concepts:
677
-
678
- \`\`\`mermaid
679
- graph TD
680
- A[Start Documentation] --> B{Have Content?}
681
- B -->|Yes| C[Edit README.md]
682
- B -->|No| D[Create Content Files]
683
- C --> E[Build & Deploy]
684
- D --> E
685
- E --> F[Share Documentation]
686
- \`\`\`
687
-
688
- ## Support
689
-
690
- For help with @knowcode/doc-builder:
691
- - Check the documentation at your package source
692
- - Use \`npx @knowcode/doc-builder --help\` for CLI options
693
- - Review the generated configuration guide if available
694
- `;
695
-
696
- try {
697
- await fs.writeFile(readmePath, placeholderContent);
698
- console.log(chalk.yellow('📄 Auto-generated placeholder README.md - please customize it!'));
699
- return true; // Successfully created placeholder
700
- } catch (error) {
701
- console.warn(chalk.yellow(`Warning: Could not create placeholder README.md: ${error.message}`));
702
- return false;
703
- }
704
- }
705
-
706
- // Create login/logout pages
707
- async function createAuthPages(outputDir, config) {
708
- // Login page
709
- const loginHTML = `<!DOCTYPE html>
710
- <html lang="en">
711
- <head>
712
- <meta charset="UTF-8">
713
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
714
- <title>Login - ${config.siteName}</title>
715
- <link rel="stylesheet" href="css/notion-style.css">
716
- </head>
717
- <body>
718
- <div class="auth-container">
719
- <div class="auth-box">
720
- <h1>Login to ${config.siteName}</h1>
721
- <form id="login-form">
722
- <div class="form-group">
723
- <label for="username">Username</label>
724
- <input type="text" id="username" name="username" required>
725
- </div>
726
- <div class="form-group">
727
- <label for="password">Password</label>
728
- <input type="password" id="password" name="password" required>
729
- </div>
730
- <button type="submit" class="auth-button">Login</button>
731
- </form>
732
- <div id="error-message" class="error-message"></div>
733
- </div>
734
- </div>
735
- <script>
736
- document.getElementById('login-form').addEventListener('submit', function(e) {
737
- e.preventDefault();
738
- const username = document.getElementById('username').value;
739
- const password = document.getElementById('password').value;
740
-
741
- // Validate credentials
742
- if (username === '${config.auth.username}' && password === '${config.auth.password}') {
743
- // Set auth cookie
744
- const token = btoa(username + ':' + password);
745
- document.cookie = 'doc-auth=' + token + '; path=/';
746
-
747
- // Redirect
748
- const params = new URLSearchParams(window.location.search);
749
- const redirect = params.get('redirect') || '/';
750
- window.location.href = redirect;
751
- } else {
752
- document.getElementById('error-message').textContent = 'Invalid username or password';
753
- }
754
- });
755
- </script>
756
- </body>
757
- </html>`;
758
-
759
- await fs.writeFile(path.join(outputDir, 'login.html'), loginHTML);
760
-
761
- // Logout page
762
- const logoutHTML = `<!DOCTYPE html>
763
- <html lang="en">
764
- <head>
765
- <meta charset="UTF-8">
766
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
767
- <title>Logged Out - ${config.siteName}</title>
768
- <link rel="stylesheet" href="css/notion-style.css">
769
- </head>
770
- <body>
771
- <div class="auth-container">
772
- <div class="auth-box">
773
- <h1>You have been logged out</h1>
774
- <p>Thank you for using ${config.siteName}.</p>
775
- <a href="login.html" class="auth-button">Login Again</a>
776
- </div>
777
- </div>
778
- </body>
779
- </html>`;
780
-
781
- await fs.writeFile(path.join(outputDir, 'logout.html'), logoutHTML);
782
- }
783
-
784
- // Create default index page when no documentation exists
785
- async function createDefaultIndexPage(outputDir, config, version) {
786
- const siteName = config.siteName || 'Documentation';
787
- const currentDate = new Date().toISOString();
788
-
789
- // List all HTML files in the output directory
790
- const htmlFiles = [];
791
- async function findHtmlFiles(dir, baseDir = dir) {
792
- const items = await fs.readdir(dir);
793
- for (const item of items) {
794
- const fullPath = path.join(dir, item);
795
- const stat = await fs.stat(fullPath);
796
- if (stat.isDirectory() && !item.startsWith('.')) {
797
- await findHtmlFiles(fullPath, baseDir);
798
- } else if (item.endsWith('.html') && item !== 'index.html' && item !== 'login.html' && item !== 'logout.html') {
799
- const relativePath = path.relative(baseDir, fullPath);
800
- htmlFiles.push(relativePath);
801
- }
802
- }
803
- }
804
-
805
- await findHtmlFiles(outputDir);
806
-
807
- let fileListHtml = '';
808
- if (htmlFiles.length > 0) {
809
- fileListHtml = `
810
- <div class="existing-files">
811
- <h2>📁 Available Documentation</h2>
812
- <p>The following documentation files were found:</p>
813
- <ul>
814
- ${htmlFiles.map(file => `<li><a href="${file}">${file}</a></li>`).join('\n ')}
815
- </ul>
816
- </div>`;
817
- }
818
-
819
- return `<!DOCTYPE html>
820
- <html lang="en">
821
- <head>
822
- <meta charset="UTF-8">
823
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
824
- <title>Welcome to ${siteName}</title>
825
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
826
- <link rel="stylesheet" href="/css/notion-style.css">
827
- <link rel="stylesheet" href="/css/style.css">
828
- <style>
829
- .welcome-container {
830
- max-width: 800px;
831
- margin: 50px auto;
832
- padding: 40px;
833
- background: var(--bg-secondary);
834
- border-radius: 12px;
835
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
836
- }
837
- .welcome-container h1 {
838
- color: var(--text-primary);
839
- margin-bottom: 20px;
840
- }
841
- .welcome-container h2 {
842
- color: var(--text-primary);
843
- margin-top: 30px;
844
- margin-bottom: 15px;
845
- }
846
- .welcome-container p {
847
- color: var(--text-secondary);
848
- line-height: 1.6;
849
- margin-bottom: 15px;
850
- }
851
- .welcome-container pre {
852
- background: var(--bg-tertiary);
853
- padding: 20px;
854
- border-radius: 8px;
855
- overflow-x: auto;
856
- margin: 20px 0;
857
- }
858
- .welcome-container code {
859
- font-family: 'JetBrains Mono', monospace;
860
- font-size: 14px;
861
- }
862
- .welcome-container ul {
863
- margin: 20px 0;
864
- padding-left: 30px;
865
- }
866
- .welcome-container li {
867
- margin: 8px 0;
868
- }
869
- .version-info {
870
- margin-top: 40px;
871
- padding-top: 20px;
872
- border-top: 1px solid var(--border-color);
873
- font-size: 12px;
874
- color: var(--text-tertiary);
875
- }
876
- .existing-files {
877
- background: var(--bg-primary);
878
- padding: 20px;
879
- border-radius: 8px;
880
- margin: 30px 0;
881
- }
882
- .existing-files a {
883
- color: var(--link-color);
884
- text-decoration: none;
885
- }
886
- .existing-files a:hover {
887
- text-decoration: underline;
888
- }
889
- </style>
890
- </head>
891
- <body>
892
- <div class="welcome-container">
893
- <h1>📚 Welcome to ${siteName}</h1>
894
-
895
- <p>This documentation site was generated by <strong>@knowcode/doc-builder</strong>. To add your own content, follow the instructions below.</p>
896
-
897
- <h2>🚀 Getting Started</h2>
898
-
899
- <p>To create your documentation homepage, create either of these files in your <code>docs/</code> directory:</p>
900
-
901
- <ul>
902
- <li><code>index.md</code> - Primary homepage (highest priority)</li>
903
- <li><code>README.md</code> - Alternative homepage</li>
904
- </ul>
905
-
906
- <h2>📝 Example Content</h2>
907
-
908
- <p>Create <code>docs/index.md</code> with content like:</p>
909
-
910
- <pre><code># Welcome to My Project
911
-
912
- This is the homepage for my documentation.
913
-
914
- ## Features
915
-
916
- - Feature 1
917
- - Feature 2
918
- - Feature 3
919
-
920
- ## Getting Started
921
-
922
- 1. Install the package
923
- 2. Configure your settings
924
- 3. Start building!</code></pre>
925
-
926
- <h2>🔧 Next Steps</h2>
927
-
928
- <ol>
929
- <li>Create <code>docs/index.md</code> or <code>docs/README.md</code></li>
930
- <li>Add more markdown files for additional pages</li>
931
- <li>Rebuild: <code>npx @knowcode/doc-builder build</code></li>
932
- <li>Deploy: <code>npx @knowcode/doc-builder deploy</code></li>
933
- </ol>
934
-
935
- ${fileListHtml}
936
-
937
- <div class="version-info">
938
- <p><strong>Debug Information:</strong></p>
939
- <ul>
940
- <li>doc-builder version: ${version}</li>
941
- <li>Generated: ${currentDate}</li>
942
- <li>Site name: ${siteName}</li>
943
- <li>No index.md or README.md found in docs directory</li>
944
- </ul>
945
- </div>
946
- </div>
947
- </body>
948
- </html>`;
949
- }
950
-
951
- module.exports = {
952
- buildDocumentation,
953
- processMarkdownContent,
954
- generateHTML,
955
- createPlaceholderReadme,
956
- createDefaultIndexPage
957
- };