@alliance-droid/svelte-docs-system 0.0.2 → 0.1.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 (185) hide show
  1. package/README.md +155 -23
  2. package/dist/components/APITable.svelte.d.ts +21 -0
  3. package/dist/components/Breadcrumbs.svelte.d.ts +14 -0
  4. package/dist/components/Callout.svelte.d.ts +15 -0
  5. package/dist/components/CodeBlock.svelte.d.ts +12 -0
  6. package/{src/lib → dist}/components/DocLayout.svelte +18 -6
  7. package/dist/components/DocLayout.svelte.d.ts +18 -0
  8. package/dist/components/DocsPage.svelte +39 -0
  9. package/dist/components/DocsPage.svelte.d.ts +8 -0
  10. package/dist/components/Documentation.svelte +639 -0
  11. package/dist/components/Footer.svelte.d.ts +10 -0
  12. package/dist/components/Image.svelte.d.ts +15 -0
  13. package/{src/lib → dist}/components/Navbar.svelte +4 -4
  14. package/dist/components/Navbar.svelte.d.ts +10 -0
  15. package/{src/lib → dist}/components/Search.svelte +2 -2
  16. package/dist/components/Search.svelte.d.ts +6 -0
  17. package/{template-starter/src/lib → dist}/components/Sidebar.svelte +2 -2
  18. package/dist/components/Sidebar.svelte.d.ts +9 -0
  19. package/dist/components/Tabs.svelte.d.ts +16 -0
  20. package/dist/config.d.ts +93 -0
  21. package/dist/config.js +89 -0
  22. package/dist/configLoader.d.ts +48 -0
  23. package/dist/configLoader.js +187 -0
  24. package/dist/configParser.d.ts +27 -0
  25. package/dist/configParser.js +208 -0
  26. package/{template-starter/src/lib/index.ts → dist/index.d.ts} +6 -7
  27. package/dist/index.js +18 -0
  28. package/dist/navigationBuilder.d.ts +64 -0
  29. package/dist/navigationBuilder.js +225 -0
  30. package/dist/plugin.d.ts +30 -0
  31. package/dist/plugin.js +172 -0
  32. package/dist/routing.d.ts +48 -0
  33. package/dist/routing.js +92 -0
  34. package/dist/stores/i18n.d.ts +20 -0
  35. package/dist/stores/i18n.js +119 -0
  36. package/dist/stores/nav.d.ts +20 -0
  37. package/dist/stores/nav.js +15 -0
  38. package/dist/stores/search.d.ts +49 -0
  39. package/dist/stores/search.js +127 -0
  40. package/dist/stores/theme.d.ts +7 -0
  41. package/dist/stores/theme.js +152 -0
  42. package/dist/stores/version.d.ts +18 -0
  43. package/dist/stores/version.js +93 -0
  44. package/dist/themeCustomization.d.ts +46 -0
  45. package/dist/themeCustomization.js +188 -0
  46. package/dist/utils/highlight.d.ts +13 -0
  47. package/dist/utils/highlight.js +83 -0
  48. package/dist/utils/index.d.ts +1 -0
  49. package/dist/utils/index.js +1 -0
  50. package/dist/utils/markdown.d.ts +40 -0
  51. package/dist/utils/markdown.js +165 -0
  52. package/package.json +44 -23
  53. package/COMPONENTS.md +0 -365
  54. package/COVERAGE_REPORT.md +0 -663
  55. package/SEARCH_VERIFICATION.md +0 -229
  56. package/TEST_SUMMARY.md +0 -344
  57. package/bin/init.js +0 -821
  58. package/docs/COMPONENT_LIBRARY_INTEGRATION_REPORT.md +0 -153
  59. package/docs/DARK_MODE_AUDIT_REPORT.md +0 -403
  60. package/docs/E2E_TESTS.md +0 -354
  61. package/docs/TESTING.md +0 -754
  62. package/docs/THEME_INHERITANCE.md +0 -192
  63. package/docs/de/index.md +0 -41
  64. package/docs/en/COMPONENTS.md +0 -443
  65. package/docs/en/api/examples.md +0 -100
  66. package/docs/en/api/overview.md +0 -69
  67. package/docs/en/components/index.md +0 -622
  68. package/docs/en/config/navigation.md +0 -505
  69. package/docs/en/config/theme-and-colors.md +0 -395
  70. package/docs/en/getting-started/integration.md +0 -406
  71. package/docs/en/guides/common-setups.md +0 -651
  72. package/docs/en/index.md +0 -243
  73. package/docs/en/markdown.md +0 -102
  74. package/docs/en/routing.md +0 -64
  75. package/docs/en/setup.md +0 -52
  76. package/docs/en/troubleshooting.md +0 -704
  77. package/docs/es/index.md +0 -41
  78. package/docs/fr/index.md +0 -41
  79. package/docs/ja/index.md +0 -41
  80. package/pagefind.toml +0 -8
  81. package/postcss.config.js +0 -5
  82. package/src/app.css +0 -119
  83. package/src/app.d.ts +0 -13
  84. package/src/app.html +0 -11
  85. package/src/lib/components/APITable.test.ts +0 -153
  86. package/src/lib/components/Breadcrumbs.test.ts +0 -148
  87. package/src/lib/components/Callout.test.ts +0 -100
  88. package/src/lib/components/CodeBlock.test.ts +0 -133
  89. package/src/lib/components/Image.test.ts +0 -163
  90. package/src/lib/components/Sidebar.svelte +0 -110
  91. package/src/lib/components/Tabs.test.ts +0 -102
  92. package/src/lib/config.test.ts +0 -140
  93. package/src/lib/config.ts +0 -179
  94. package/src/lib/configIntegration.test.ts +0 -272
  95. package/src/lib/configLoader.ts +0 -231
  96. package/src/lib/configParser.test.ts +0 -217
  97. package/src/lib/configParser.ts +0 -234
  98. package/src/lib/index.ts +0 -37
  99. package/src/lib/integration.test.ts +0 -426
  100. package/src/lib/navigationBuilder.test.ts +0 -338
  101. package/src/lib/navigationBuilder.ts +0 -268
  102. package/src/lib/performance.test.ts +0 -369
  103. package/src/lib/routing.test.ts +0 -202
  104. package/src/lib/routing.ts +0 -127
  105. package/src/lib/search-functionality.test.ts +0 -493
  106. package/src/lib/stores/i18n.test.ts +0 -180
  107. package/src/lib/stores/i18n.ts +0 -143
  108. package/src/lib/stores/nav.ts +0 -36
  109. package/src/lib/stores/search.test.ts +0 -140
  110. package/src/lib/stores/search.ts +0 -162
  111. package/src/lib/stores/theme.test.ts +0 -117
  112. package/src/lib/stores/theme.ts +0 -167
  113. package/src/lib/stores/version.test.ts +0 -139
  114. package/src/lib/stores/version.ts +0 -111
  115. package/src/lib/themeCustomization.test.ts +0 -223
  116. package/src/lib/themeCustomization.ts +0 -212
  117. package/src/lib/utils/highlight.test.ts +0 -136
  118. package/src/lib/utils/highlight.ts +0 -100
  119. package/src/lib/utils/index.ts +0 -7
  120. package/src/lib/utils/markdown.test.ts +0 -357
  121. package/src/lib/utils/markdown.ts +0 -77
  122. package/src/routes/+layout.server.ts +0 -1
  123. package/src/routes/+layout.svelte +0 -29
  124. package/src/routes/+page.svelte +0 -165
  125. package/src/routes/quote-demo/+page.svelte +0 -141
  126. package/static/robots.txt +0 -3
  127. package/svelte.config.js +0 -15
  128. package/tailwind.config.ts +0 -55
  129. package/template-starter/.github/workflows/build.yml +0 -40
  130. package/template-starter/.github/workflows/deploy-github-pages.yml +0 -47
  131. package/template-starter/.github/workflows/deploy-netlify.yml +0 -41
  132. package/template-starter/.github/workflows/deploy-vercel.yml +0 -64
  133. package/template-starter/NPM-PACKAGE-SETUP.md +0 -233
  134. package/template-starter/README.md +0 -320
  135. package/template-starter/docs/_config.json +0 -39
  136. package/template-starter/docs/api/components.md +0 -257
  137. package/template-starter/docs/api/overview.md +0 -169
  138. package/template-starter/docs/guides/configuration.md +0 -145
  139. package/template-starter/docs/guides/github-pages-deployment.md +0 -254
  140. package/template-starter/docs/guides/netlify-deployment.md +0 -159
  141. package/template-starter/docs/guides/vercel-deployment.md +0 -131
  142. package/template-starter/docs/index.md +0 -49
  143. package/template-starter/docs/setup.md +0 -149
  144. package/template-starter/package.json +0 -31
  145. package/template-starter/pagefind.toml +0 -3
  146. package/template-starter/postcss.config.js +0 -5
  147. package/template-starter/src/app.css +0 -34
  148. package/template-starter/src/app.d.ts +0 -13
  149. package/template-starter/src/app.html +0 -11
  150. package/template-starter/src/lib/components/APITable.svelte +0 -120
  151. package/template-starter/src/lib/components/APITable.test.ts +0 -96
  152. package/template-starter/src/lib/components/Breadcrumbs.svelte +0 -85
  153. package/template-starter/src/lib/components/Breadcrumbs.test.ts +0 -82
  154. package/template-starter/src/lib/components/Callout.svelte +0 -60
  155. package/template-starter/src/lib/components/Callout.test.ts +0 -91
  156. package/template-starter/src/lib/components/CodeBlock.svelte +0 -68
  157. package/template-starter/src/lib/components/CodeBlock.test.ts +0 -62
  158. package/template-starter/src/lib/components/DocLayout.svelte +0 -84
  159. package/template-starter/src/lib/components/Footer.svelte +0 -78
  160. package/template-starter/src/lib/components/Image.svelte +0 -100
  161. package/template-starter/src/lib/components/Image.test.ts +0 -81
  162. package/template-starter/src/lib/components/Navbar.svelte +0 -141
  163. package/template-starter/src/lib/components/Search.svelte +0 -248
  164. package/template-starter/src/lib/components/Tabs.svelte +0 -48
  165. package/template-starter/src/lib/components/Tabs.test.ts +0 -89
  166. package/template-starter/src/routes/+layout.svelte +0 -28
  167. package/template-starter/src/routes/+page.svelte +0 -92
  168. package/template-starter/svelte.config.js +0 -17
  169. package/template-starter/tailwind.config.ts +0 -17
  170. package/template-starter/tsconfig.json +0 -13
  171. package/template-starter/vite.config.ts +0 -6
  172. package/tests/e2e/example.spec.ts +0 -345
  173. package/tsconfig.json +0 -20
  174. package/vite.config.ts +0 -6
  175. package/vitest.config.ts +0 -33
  176. package/vitest.setup.ts +0 -21
  177. /package/{src/lib → dist}/assets/favicon.svg +0 -0
  178. /package/{src/lib → dist}/components/APITable.svelte +0 -0
  179. /package/{src/lib → dist}/components/Breadcrumbs.svelte +0 -0
  180. /package/{src/lib → dist}/components/Callout.svelte +0 -0
  181. /package/{src/lib → dist}/components/CodeBlock.svelte +0 -0
  182. /package/{src/lib → dist}/components/Footer.svelte +0 -0
  183. /package/{src/lib → dist}/components/Image.svelte +0 -0
  184. /package/{src/lib → dist}/components/Tabs.svelte +0 -0
  185. /package/{src/lib → dist}/svelte-component-library.d.ts +0 -0
@@ -1,5 +1,6 @@
1
- // Re-export documentation components for use in your templates
2
-
1
+ export { default as Documentation } from './components/Documentation.svelte';
2
+ export { svelteDocsPlugin, default as docsPlugin } from './plugin.js';
3
+ export type { DocsPluginOptions, DocFile, DocFolder } from './plugin.js';
3
4
  export { default as Callout } from './components/Callout.svelte';
4
5
  export { default as Tabs } from './components/Tabs.svelte';
5
6
  export { default as CodeBlock } from './components/CodeBlock.svelte';
@@ -7,9 +8,7 @@ export { default as Image } from './components/Image.svelte';
7
8
  export { default as APITable } from './components/APITable.svelte';
8
9
  export { default as Breadcrumbs } from './components/Breadcrumbs.svelte';
9
10
  export { default as Search } from './components/Search.svelte';
10
-
11
- // Re-export theme components
12
- export { default as DocLayout } from './components/DocLayout.svelte';
13
- export { default as Navbar } from './components/Navbar.svelte';
14
11
  export { default as Sidebar } from './components/Sidebar.svelte';
15
- export { default as Footer } from './components/Footer.svelte';
12
+ export { renderMarkdown, renderMarkdownSync, extractMetadata, getExcerpt, type MarkdownMetadata, type MarkdownResult, } from './utils/index.js';
13
+ export { theme } from './stores/theme';
14
+ export { sidebarOpen } from './stores/nav';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // Main component - drop this into your +page.svelte
2
+ export { default as Documentation } from './components/Documentation.svelte';
3
+ // Vite plugin - add to vite.config.ts
4
+ export { svelteDocsPlugin, default as docsPlugin } from './plugin.js';
5
+ // Content components for custom layouts
6
+ export { default as Callout } from './components/Callout.svelte';
7
+ export { default as Tabs } from './components/Tabs.svelte';
8
+ export { default as CodeBlock } from './components/CodeBlock.svelte';
9
+ export { default as Image } from './components/Image.svelte';
10
+ export { default as APITable } from './components/APITable.svelte';
11
+ export { default as Breadcrumbs } from './components/Breadcrumbs.svelte';
12
+ export { default as Search } from './components/Search.svelte';
13
+ export { default as Sidebar } from './components/Sidebar.svelte';
14
+ // Utilities
15
+ export { renderMarkdown, renderMarkdownSync, extractMetadata, getExcerpt, } from './utils/index.js';
16
+ // Stores (for advanced usage)
17
+ export { theme } from './stores/theme';
18
+ export { sidebarOpen } from './stores/nav';
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Navigation builder for generating navigation from folder structure or config
3
+ */
4
+ import type { NavItem, NavSection, NavigationConfig } from './config';
5
+ export interface FileInfo {
6
+ /** Full file path (e.g., docs/api/overview.md) */
7
+ path: string;
8
+ /** File name without extension (e.g., overview) */
9
+ name: string;
10
+ /** File title (from frontmatter or derived from name) */
11
+ title?: string;
12
+ /** File order (from frontmatter) */
13
+ order?: number;
14
+ /** Is this the index file? */
15
+ isIndex: boolean;
16
+ }
17
+ /**
18
+ * Convert a file name to a display title
19
+ * Example: "api-reference" -> "API Reference"
20
+ */
21
+ export declare function formatFileName(name: string): string;
22
+ /**
23
+ * Parse file information from path
24
+ * Example: "docs/api/reference.md" -> { path: "docs/api/reference.md", name: "reference", isIndex: false }
25
+ */
26
+ export declare function parseFileInfo(filePath: string, fileMetadata?: {
27
+ title?: string;
28
+ order?: number;
29
+ }): FileInfo;
30
+ /**
31
+ * Generate navigation from a list of files
32
+ * Useful for auto-generating sidebar from folder structure
33
+ */
34
+ export declare function generateNavigationFromFiles(files: FileInfo[], baseRoute?: string): NavSection[];
35
+ /**
36
+ * Flatten navigation sections to a single array of NavItems
37
+ */
38
+ export declare function flattenNavigation(sections: NavSection[]): NavItem[];
39
+ /**
40
+ * Validate navigation configuration
41
+ */
42
+ export declare function validateNavigation(nav: NavigationConfig): {
43
+ valid: boolean;
44
+ errors: string[];
45
+ };
46
+ /**
47
+ * Filter files based on exclude patterns
48
+ */
49
+ export declare function filterFiles(files: FileInfo[], excludePatterns?: string[]): FileInfo[];
50
+ /**
51
+ * Build navigation from a config object
52
+ */
53
+ export declare function buildNavigationFromConfig(config: NavigationConfig, files?: FileInfo[], baseRoute?: string): NavSection[];
54
+ /**
55
+ * Find a navigation item by href
56
+ */
57
+ export declare function findNavItem(sections: NavSection[], href: string): NavItem | null;
58
+ /**
59
+ * Get previous and next navigation items in order
60
+ */
61
+ export declare function getPrevNext(sections: NavSection[], currentHref: string): {
62
+ prev: NavItem | null;
63
+ next: NavItem | null;
64
+ };
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Navigation builder for generating navigation from folder structure or config
3
+ */
4
+ /**
5
+ * Convert a file name to a display title
6
+ * Example: "api-reference" -> "API Reference"
7
+ */
8
+ export function formatFileName(name) {
9
+ return name
10
+ .replace(/[-_]/g, ' ') // Replace hyphens and underscores with spaces
11
+ .replace(/\b\w/g, (char) => char.toUpperCase()); // Capitalize first letter of each word
12
+ }
13
+ /**
14
+ * Parse file information from path
15
+ * Example: "docs/api/reference.md" -> { path: "docs/api/reference.md", name: "reference", isIndex: false }
16
+ */
17
+ export function parseFileInfo(filePath, fileMetadata) {
18
+ const cleanPath = filePath.replace(/^\.\//, ''); // Remove leading ./
19
+ const lastSlash = cleanPath.lastIndexOf('/');
20
+ const fileName = cleanPath.substring(lastSlash + 1);
21
+ const name = fileName.replace(/\.md$/, '');
22
+ return {
23
+ path: cleanPath,
24
+ name,
25
+ title: fileMetadata?.title || formatFileName(name),
26
+ order: fileMetadata?.order,
27
+ isIndex: name === 'index',
28
+ };
29
+ }
30
+ /**
31
+ * Group files by directory
32
+ */
33
+ function groupFilesByDirectory(files) {
34
+ const groups = new Map();
35
+ files.forEach((file) => {
36
+ const match = file.path.match(/^docs\/(.+)\/[^/]+\.md$/);
37
+ const dir = match ? match[1] : 'root';
38
+ if (!groups.has(dir)) {
39
+ groups.set(dir, []);
40
+ }
41
+ groups.get(dir).push(file);
42
+ });
43
+ return groups;
44
+ }
45
+ /**
46
+ * Sort files by order, then alphabetically
47
+ */
48
+ function sortFiles(files) {
49
+ return [...files].sort((a, b) => {
50
+ // Priority to index files at the top
51
+ if (a.isIndex && !b.isIndex)
52
+ return -1;
53
+ if (!a.isIndex && b.isIndex)
54
+ return 1;
55
+ // Then sort by order if specified
56
+ if (a.order !== undefined && b.order !== undefined) {
57
+ return a.order - b.order;
58
+ }
59
+ if (a.order !== undefined)
60
+ return -1;
61
+ if (b.order !== undefined)
62
+ return 1;
63
+ // Finally alphabetically
64
+ return a.name.localeCompare(b.name);
65
+ });
66
+ }
67
+ /**
68
+ * Generate navigation from a list of files
69
+ * Useful for auto-generating sidebar from folder structure
70
+ */
71
+ export function generateNavigationFromFiles(files, baseRoute = '/docs') {
72
+ const groups = groupFilesByDirectory(files);
73
+ const sections = [];
74
+ // Process files in natural order
75
+ const sortedDirs = Array.from(groups.keys()).sort((a, b) => {
76
+ if (a === 'root')
77
+ return -1;
78
+ if (b === 'root')
79
+ return 1;
80
+ return a.localeCompare(b);
81
+ });
82
+ sortedDirs.forEach((dir) => {
83
+ const dirFiles = sortFiles(groups.get(dir));
84
+ if (dir === 'root') {
85
+ // Root files go to main section
86
+ dirFiles.forEach((file) => {
87
+ if (!file.isIndex) {
88
+ if (!sections[0]) {
89
+ sections.push({ title: 'Documentation', items: [] });
90
+ }
91
+ sections[0].items.push({
92
+ label: file.title || file.name,
93
+ href: `${baseRoute}/${file.name}`,
94
+ });
95
+ }
96
+ });
97
+ }
98
+ else {
99
+ // Directory files go to their own section
100
+ const sectionTitle = formatFileName(dir);
101
+ const items = dirFiles.map((file) => ({
102
+ label: file.title || file.name,
103
+ href: `${baseRoute}/${dir}/${file.name}`,
104
+ }));
105
+ sections.push({ title: sectionTitle, items });
106
+ }
107
+ });
108
+ return sections;
109
+ }
110
+ /**
111
+ * Flatten navigation sections to a single array of NavItems
112
+ */
113
+ export function flattenNavigation(sections) {
114
+ const items = [];
115
+ sections.forEach((section) => {
116
+ items.push({
117
+ label: section.title,
118
+ children: section.items,
119
+ });
120
+ });
121
+ return items;
122
+ }
123
+ /**
124
+ * Validate navigation configuration
125
+ */
126
+ export function validateNavigation(nav) {
127
+ const errors = [];
128
+ if (!nav || typeof nav !== 'object') {
129
+ return { valid: false, errors: ['Navigation must be an object'] };
130
+ }
131
+ if (nav.sections !== undefined) {
132
+ if (!Array.isArray(nav.sections)) {
133
+ errors.push('sections must be an array');
134
+ }
135
+ else {
136
+ nav.sections.forEach((section, idx) => {
137
+ if (!section.title) {
138
+ errors.push(`Section ${idx}: missing title`);
139
+ }
140
+ if (!Array.isArray(section.items)) {
141
+ errors.push(`Section ${idx}: items must be an array`);
142
+ }
143
+ else {
144
+ section.items.forEach((item, itemIdx) => {
145
+ if (!item.label) {
146
+ errors.push(`Section ${idx}, item ${itemIdx}: missing label`);
147
+ }
148
+ });
149
+ }
150
+ });
151
+ }
152
+ }
153
+ if (nav.excludePaths !== undefined && !Array.isArray(nav.excludePaths)) {
154
+ errors.push('excludePaths must be an array');
155
+ }
156
+ return { valid: errors.length === 0, errors };
157
+ }
158
+ /**
159
+ * Filter files based on exclude patterns
160
+ */
161
+ export function filterFiles(files, excludePatterns = []) {
162
+ return files.filter((file) => {
163
+ return !excludePatterns.some((pattern) => {
164
+ // Simple pattern matching (could be extended to regex)
165
+ return file.path.includes(pattern);
166
+ });
167
+ });
168
+ }
169
+ /**
170
+ * Build navigation from a config object
171
+ */
172
+ export function buildNavigationFromConfig(config, files, baseRoute = '/docs') {
173
+ // If explicit sections are provided, use them
174
+ if (config.sections && config.sections.length > 0) {
175
+ return config.sections;
176
+ }
177
+ // Otherwise auto-generate from files
178
+ if (files && files.length > 0) {
179
+ const filtered = filterFiles(files, config.excludePaths);
180
+ return generateNavigationFromFiles(filtered, baseRoute);
181
+ }
182
+ // Return empty navigation
183
+ return [];
184
+ }
185
+ /**
186
+ * Find a navigation item by href
187
+ */
188
+ export function findNavItem(sections, href) {
189
+ for (const section of sections) {
190
+ for (const item of section.items) {
191
+ if (item.href === href) {
192
+ return item;
193
+ }
194
+ if (item.children) {
195
+ const found = item.children.find((child) => child.href === href);
196
+ if (found)
197
+ return found;
198
+ }
199
+ }
200
+ }
201
+ return null;
202
+ }
203
+ /**
204
+ * Get previous and next navigation items in order
205
+ */
206
+ export function getPrevNext(sections, currentHref) {
207
+ const allItems = [];
208
+ sections.forEach((section) => {
209
+ section.items.forEach((item) => {
210
+ if (item.href)
211
+ allItems.push(item);
212
+ if (item.children) {
213
+ item.children.forEach((child) => {
214
+ if (child.href)
215
+ allItems.push(child);
216
+ });
217
+ }
218
+ });
219
+ });
220
+ const currentIndex = allItems.findIndex((item) => item.href === currentHref);
221
+ return {
222
+ prev: currentIndex > 0 ? allItems[currentIndex - 1] : null,
223
+ next: currentIndex < allItems.length - 1 ? allItems[currentIndex + 1] : null,
224
+ };
225
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Vite plugin for svelte-docs-system
3
+ * Auto-scans /docs folder and generates navigation structure
4
+ */
5
+ import type { Plugin } from 'vite';
6
+ export interface DocFile {
7
+ slug: string;
8
+ path: string;
9
+ title: string;
10
+ description?: string;
11
+ order?: number;
12
+ }
13
+ export interface DocFolder {
14
+ name: string;
15
+ slug: string;
16
+ files: DocFile[];
17
+ folders: DocFolder[];
18
+ order?: number;
19
+ }
20
+ export interface DocsPluginOptions {
21
+ /** Path to docs folder relative to project root. Default: './docs' */
22
+ docsPath?: string;
23
+ /** Route where docs will be served. Default: '/documentation' */
24
+ route?: string;
25
+ }
26
+ /**
27
+ * Vite plugin for svelte-docs-system
28
+ */
29
+ export declare function svelteDocsPlugin(options?: DocsPluginOptions): Plugin;
30
+ export default svelteDocsPlugin;
package/dist/plugin.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Vite plugin for svelte-docs-system
3
+ * Auto-scans /docs folder and generates navigation structure
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import matter from 'gray-matter';
8
+ const VIRTUAL_MODULE_ID = 'virtual:svelte-docs';
9
+ const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
10
+ /**
11
+ * Extract frontmatter and title from markdown file
12
+ */
13
+ function parseMarkdownFile(filePath) {
14
+ try {
15
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
16
+ const { data, content } = matter(fileContent);
17
+ // Get title from frontmatter or first H1
18
+ let title = data.title;
19
+ if (!title) {
20
+ const h1Match = content.match(/^#\s+(.+)$/m);
21
+ title = h1Match ? h1Match[1] : path.basename(filePath, '.md');
22
+ }
23
+ return {
24
+ title,
25
+ description: data.description,
26
+ order: data.order ?? data.sidebar_position,
27
+ content
28
+ };
29
+ }
30
+ catch {
31
+ return {
32
+ title: path.basename(filePath, '.md'),
33
+ content: ''
34
+ };
35
+ }
36
+ }
37
+ /**
38
+ * Convert filename to readable title
39
+ */
40
+ function slugToTitle(slug) {
41
+ return slug
42
+ .replace(/-/g, ' ')
43
+ .replace(/_/g, ' ')
44
+ .replace(/\b\w/g, c => c.toUpperCase());
45
+ }
46
+ /**
47
+ * Recursively scan docs folder
48
+ */
49
+ function scanDocsFolder(dirPath, basePath = '') {
50
+ const name = path.basename(dirPath);
51
+ const slug = basePath || '/';
52
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
53
+ const files = [];
54
+ const folders = [];
55
+ // Check for folder config (index.md or _category_.json)
56
+ let folderOrder;
57
+ const indexPath = path.join(dirPath, 'index.md');
58
+ if (fs.existsSync(indexPath)) {
59
+ const { order } = parseMarkdownFile(indexPath);
60
+ folderOrder = order;
61
+ }
62
+ for (const entry of entries) {
63
+ const entryPath = path.join(dirPath, entry.name);
64
+ if (entry.isDirectory() && !entry.name.startsWith('_') && !entry.name.startsWith('.')) {
65
+ // Recurse into subdirectory
66
+ const subSlug = basePath ? `${basePath}/${entry.name}` : entry.name;
67
+ folders.push(scanDocsFolder(entryPath, subSlug));
68
+ }
69
+ else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'index.md') {
70
+ // Parse markdown file
71
+ const fileSlug = entry.name.replace(/\.md$/, '');
72
+ const fullSlug = basePath ? `${basePath}/${fileSlug}` : fileSlug;
73
+ const { title, description, order } = parseMarkdownFile(entryPath);
74
+ files.push({
75
+ slug: fullSlug,
76
+ path: entryPath,
77
+ title,
78
+ description,
79
+ order
80
+ });
81
+ }
82
+ }
83
+ // Sort by order, then alphabetically
84
+ files.sort((a, b) => {
85
+ if (a.order !== undefined && b.order !== undefined)
86
+ return a.order - b.order;
87
+ if (a.order !== undefined)
88
+ return -1;
89
+ if (b.order !== undefined)
90
+ return 1;
91
+ return a.title.localeCompare(b.title);
92
+ });
93
+ folders.sort((a, b) => {
94
+ if (a.order !== undefined && b.order !== undefined)
95
+ return a.order - b.order;
96
+ if (a.order !== undefined)
97
+ return -1;
98
+ if (b.order !== undefined)
99
+ return 1;
100
+ return a.name.localeCompare(b.name);
101
+ });
102
+ return {
103
+ name: slugToTitle(name),
104
+ slug,
105
+ files,
106
+ folders,
107
+ order: folderOrder
108
+ };
109
+ }
110
+ /**
111
+ * Generate the docs structure as a module
112
+ */
113
+ function generateDocsModule(docsPath, route) {
114
+ if (!fs.existsSync(docsPath)) {
115
+ // Return empty structure if docs folder doesn't exist
116
+ return `
117
+ export const docsStructure = { name: 'Documentation', slug: '/', files: [], folders: [] };
118
+ export const docsRoute = '${route}';
119
+ export const allDocs = [];
120
+ `;
121
+ }
122
+ const structure = scanDocsFolder(docsPath);
123
+ // Flatten all docs for search/lookup
124
+ const allDocs = [];
125
+ function collectDocs(folder) {
126
+ allDocs.push(...folder.files);
127
+ folder.folders.forEach(collectDocs);
128
+ }
129
+ collectDocs(structure);
130
+ return `
131
+ export const docsStructure = ${JSON.stringify(structure, null, 2)};
132
+ export const docsRoute = '${route}';
133
+ export const allDocs = ${JSON.stringify(allDocs, null, 2)};
134
+ `;
135
+ }
136
+ /**
137
+ * Vite plugin for svelte-docs-system
138
+ */
139
+ export function svelteDocsPlugin(options = {}) {
140
+ const docsPath = options.docsPath || './docs';
141
+ const route = options.route || '/documentation';
142
+ let root;
143
+ return {
144
+ name: 'svelte-docs-system',
145
+ configResolved(config) {
146
+ root = config.root;
147
+ },
148
+ resolveId(id) {
149
+ if (id === VIRTUAL_MODULE_ID) {
150
+ return RESOLVED_VIRTUAL_MODULE_ID;
151
+ }
152
+ },
153
+ load(id) {
154
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
155
+ const fullDocsPath = path.resolve(root, docsPath);
156
+ return generateDocsModule(fullDocsPath, route);
157
+ }
158
+ },
159
+ handleHotUpdate({ file, server }) {
160
+ // Reload when docs files change
161
+ const fullDocsPath = path.resolve(root, docsPath);
162
+ if (file.startsWith(fullDocsPath) && file.endsWith('.md')) {
163
+ const module = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID);
164
+ if (module) {
165
+ server.moduleGraph.invalidateModule(module);
166
+ return [module];
167
+ }
168
+ }
169
+ }
170
+ };
171
+ }
172
+ export default svelteDocsPlugin;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Routing utilities for customizable documentation mount points
3
+ */
4
+ import type { ConfigOptions } from './config';
5
+ export interface RouteConfig {
6
+ /** Mount point for documentation (e.g., /docs, /help, /guides) */
7
+ docsRoute: string;
8
+ /** Path to docs folder relative to project root */
9
+ docsFolderPath: string;
10
+ /** Base path for links */
11
+ basePath: string;
12
+ }
13
+ /**
14
+ * Converts a route slug to a markdown file path
15
+ * Example: slug="api/overview", docsFolderPath="./docs" -> "./docs/api/overview.md"
16
+ */
17
+ export declare function slugToFilePath(slug: string | string[], docsFolderPath: string): string;
18
+ /**
19
+ * Converts a file path to a route URL
20
+ * Example: filePath="./docs/api/overview.md", docsRoute="/docs" -> "/docs/api/overview"
21
+ */
22
+ export declare function filePathToRoute(filePath: string, docsRoute: string): string;
23
+ /**
24
+ * Generates a list of all doc routes from a folder structure
25
+ * This would typically be called at build time to pre-generate routes
26
+ */
27
+ export declare function generateDocRoutes(files: string[], docsRoute?: string, docsFolderPath?: string): string[];
28
+ /**
29
+ * Validates a docs route
30
+ */
31
+ export declare function validateRoute(route: string): boolean;
32
+ /**
33
+ * Create route configuration from ConfigOptions
34
+ */
35
+ export declare function createRouteConfig(config: ConfigOptions): RouteConfig;
36
+ /**
37
+ * Build a navigation link using the docs route
38
+ */
39
+ export declare function buildNavLink(slug: string, docsRoute?: string, absolute?: boolean): string;
40
+ /**
41
+ * Extract slug from a docs route
42
+ * Example: "/docs/api/overview" with docsRoute="/docs" -> "api/overview"
43
+ */
44
+ export declare function extractSlugFromRoute(fullRoute: string, docsRoute: string): string;
45
+ /**
46
+ * Check if a route is a documentation route
47
+ */
48
+ export declare function isDocsRoute(route: string, docsRoute: string): boolean;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Routing utilities for customizable documentation mount points
3
+ */
4
+ /**
5
+ * Converts a route slug to a markdown file path
6
+ * Example: slug="api/overview", docsFolderPath="./docs" -> "./docs/api/overview.md"
7
+ */
8
+ export function slugToFilePath(slug, docsFolderPath) {
9
+ const pathParts = Array.isArray(slug) ? slug : slug.split('/').filter(Boolean);
10
+ const fileName = pathParts.join('/') || 'index';
11
+ return `${docsFolderPath}/${fileName}.md`;
12
+ }
13
+ /**
14
+ * Converts a file path to a route URL
15
+ * Example: filePath="./docs/api/overview.md", docsRoute="/docs" -> "/docs/api/overview"
16
+ */
17
+ export function filePathToRoute(filePath, docsRoute) {
18
+ // Remove docs folder prefix and .md extension
19
+ let relativePath = filePath.replace(/^\.\//, ''); // Remove leading ./
20
+ relativePath = relativePath.replace(/^docs\//, ''); // Remove docs/ prefix
21
+ relativePath = relativePath.replace(/\.md$/, ''); // Remove .md extension
22
+ relativePath = relativePath.replace(/\/index$/, ''); // Remove /index suffix
23
+ relativePath = relativePath.replace(/^index$/, ''); // Remove index if it's the only part
24
+ if (relativePath === '' || relativePath === 'index') {
25
+ return docsRoute || '/docs';
26
+ }
27
+ return `${docsRoute || '/docs'}/${relativePath}`;
28
+ }
29
+ /**
30
+ * Generates a list of all doc routes from a folder structure
31
+ * This would typically be called at build time to pre-generate routes
32
+ */
33
+ export function generateDocRoutes(files, docsRoute = '/docs', docsFolderPath = './docs') {
34
+ return files.map((file) => filePathToRoute(file, docsRoute)).filter((route) => route !== docsRoute || !route.endsWith('/'));
35
+ }
36
+ /**
37
+ * Validates a docs route
38
+ */
39
+ export function validateRoute(route) {
40
+ // Must start with /
41
+ if (!route.startsWith('/')) {
42
+ return false;
43
+ }
44
+ // Should not have trailing slash (except root)
45
+ if (route !== '/' && route.endsWith('/')) {
46
+ return false;
47
+ }
48
+ // No double slashes
49
+ if (route.includes('//')) {
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ /**
55
+ * Create route configuration from ConfigOptions
56
+ */
57
+ export function createRouteConfig(config) {
58
+ return {
59
+ docsRoute: config.docsRoute || '/docs',
60
+ docsFolderPath: config.docsFolderPath || './docs',
61
+ basePath: config.basePath || '/docs',
62
+ };
63
+ }
64
+ /**
65
+ * Build a navigation link using the docs route
66
+ */
67
+ export function buildNavLink(slug, docsRoute = '/docs', absolute = false) {
68
+ if (slug === '' || slug === 'index') {
69
+ return docsRoute;
70
+ }
71
+ const cleanSlug = slug.replace(/\.md$/, '').replace(/\/index$/, '');
72
+ const link = `${docsRoute}/${cleanSlug}`.replace(/\/+/g, '/'); // Remove double slashes
73
+ return link;
74
+ }
75
+ /**
76
+ * Extract slug from a docs route
77
+ * Example: "/docs/api/overview" with docsRoute="/docs" -> "api/overview"
78
+ */
79
+ export function extractSlugFromRoute(fullRoute, docsRoute) {
80
+ if (fullRoute === docsRoute) {
81
+ return '';
82
+ }
83
+ const pattern = `^${docsRoute.replace(/\//g, '\\/')}\\/`;
84
+ const regex = new RegExp(pattern);
85
+ return fullRoute.replace(regex, '');
86
+ }
87
+ /**
88
+ * Check if a route is a documentation route
89
+ */
90
+ export function isDocsRoute(route, docsRoute) {
91
+ return route === docsRoute || route.startsWith(`${docsRoute}/`);
92
+ }