@alliance-droid/svelte-docs-system 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +365 -0
- package/COVERAGE_REPORT.md +663 -0
- package/README.md +42 -0
- package/SEARCH_VERIFICATION.md +229 -0
- package/TEST_SUMMARY.md +344 -0
- package/bin/init.js +821 -0
- package/docs/E2E_TESTS.md +354 -0
- package/docs/TESTING.md +754 -0
- package/docs/de/index.md +41 -0
- package/docs/en/COMPONENTS.md +443 -0
- package/docs/en/api/examples.md +100 -0
- package/docs/en/api/overview.md +69 -0
- package/docs/en/components/index.md +622 -0
- package/docs/en/config/navigation.md +505 -0
- package/docs/en/config/theme-and-colors.md +395 -0
- package/docs/en/getting-started/integration.md +406 -0
- package/docs/en/guides/common-setups.md +651 -0
- package/docs/en/index.md +243 -0
- package/docs/en/markdown.md +102 -0
- package/docs/en/routing.md +64 -0
- package/docs/en/setup.md +52 -0
- package/docs/en/troubleshooting.md +704 -0
- package/docs/es/index.md +41 -0
- package/docs/fr/index.md +41 -0
- package/docs/ja/index.md +41 -0
- package/package.json +40 -0
- package/pagefind.toml +8 -0
- package/postcss.config.js +5 -0
- package/src/app.css +119 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +11 -0
- package/src/lib/assets/favicon.svg +1 -0
- package/src/lib/components/APITable.svelte +120 -0
- package/src/lib/components/APITable.test.ts +153 -0
- package/src/lib/components/Breadcrumbs.svelte +85 -0
- package/src/lib/components/Breadcrumbs.test.ts +148 -0
- package/src/lib/components/Callout.svelte +60 -0
- package/src/lib/components/Callout.test.ts +100 -0
- package/src/lib/components/CodeBlock.svelte +68 -0
- package/src/lib/components/CodeBlock.test.ts +133 -0
- package/src/lib/components/DocLayout.svelte +84 -0
- package/src/lib/components/Footer.svelte +78 -0
- package/src/lib/components/Image.svelte +100 -0
- package/src/lib/components/Image.test.ts +163 -0
- package/src/lib/components/Navbar.svelte +141 -0
- package/src/lib/components/Search.svelte +248 -0
- package/src/lib/components/Sidebar.svelte +110 -0
- package/src/lib/components/Tabs.svelte +48 -0
- package/src/lib/components/Tabs.test.ts +102 -0
- package/src/lib/config.test.ts +140 -0
- package/src/lib/config.ts +179 -0
- package/src/lib/configIntegration.test.ts +272 -0
- package/src/lib/configLoader.ts +231 -0
- package/src/lib/configParser.test.ts +217 -0
- package/src/lib/configParser.ts +234 -0
- package/src/lib/index.ts +34 -0
- package/src/lib/integration.test.ts +426 -0
- package/src/lib/navigationBuilder.test.ts +338 -0
- package/src/lib/navigationBuilder.ts +268 -0
- package/src/lib/performance.test.ts +369 -0
- package/src/lib/routing.test.ts +202 -0
- package/src/lib/routing.ts +127 -0
- package/src/lib/search-functionality.test.ts +493 -0
- package/src/lib/stores/i18n.test.ts +180 -0
- package/src/lib/stores/i18n.ts +143 -0
- package/src/lib/stores/nav.ts +36 -0
- package/src/lib/stores/search.test.ts +140 -0
- package/src/lib/stores/search.ts +162 -0
- package/src/lib/stores/theme.ts +59 -0
- package/src/lib/stores/version.test.ts +139 -0
- package/src/lib/stores/version.ts +111 -0
- package/src/lib/themeCustomization.test.ts +223 -0
- package/src/lib/themeCustomization.ts +212 -0
- package/src/lib/utils/highlight.test.ts +136 -0
- package/src/lib/utils/highlight.ts +100 -0
- package/src/lib/utils/index.ts +7 -0
- package/src/lib/utils/markdown.test.ts +357 -0
- package/src/lib/utils/markdown.ts +77 -0
- package/src/routes/+layout.server.ts +1 -0
- package/src/routes/+layout.svelte +28 -0
- package/src/routes/+page.svelte +165 -0
- package/static/robots.txt +3 -0
- package/svelte.config.js +18 -0
- package/tailwind.config.ts +55 -0
- package/template-starter/.github/workflows/build.yml +40 -0
- package/template-starter/.github/workflows/deploy-github-pages.yml +47 -0
- package/template-starter/.github/workflows/deploy-netlify.yml +41 -0
- package/template-starter/.github/workflows/deploy-vercel.yml +64 -0
- package/template-starter/NPM-PACKAGE-SETUP.md +233 -0
- package/template-starter/README.md +320 -0
- package/template-starter/docs/_config.json +39 -0
- package/template-starter/docs/api/components.md +257 -0
- package/template-starter/docs/api/overview.md +169 -0
- package/template-starter/docs/guides/configuration.md +145 -0
- package/template-starter/docs/guides/github-pages-deployment.md +254 -0
- package/template-starter/docs/guides/netlify-deployment.md +159 -0
- package/template-starter/docs/guides/vercel-deployment.md +131 -0
- package/template-starter/docs/index.md +49 -0
- package/template-starter/docs/setup.md +149 -0
- package/template-starter/package.json +31 -0
- package/template-starter/pagefind.toml +3 -0
- package/template-starter/postcss.config.js +5 -0
- package/template-starter/src/app.css +34 -0
- package/template-starter/src/app.d.ts +13 -0
- package/template-starter/src/app.html +11 -0
- package/template-starter/src/lib/components/APITable.svelte +120 -0
- package/template-starter/src/lib/components/APITable.test.ts +19 -0
- package/template-starter/src/lib/components/Breadcrumbs.svelte +85 -0
- package/template-starter/src/lib/components/Breadcrumbs.test.ts +19 -0
- package/template-starter/src/lib/components/Callout.svelte +60 -0
- package/template-starter/src/lib/components/Callout.test.ts +16 -0
- package/template-starter/src/lib/components/CodeBlock.svelte +68 -0
- package/template-starter/src/lib/components/CodeBlock.test.ts +12 -0
- package/template-starter/src/lib/components/DocLayout.svelte +84 -0
- package/template-starter/src/lib/components/Footer.svelte +78 -0
- package/template-starter/src/lib/components/Image.svelte +100 -0
- package/template-starter/src/lib/components/Image.test.ts +15 -0
- package/template-starter/src/lib/components/Navbar.svelte +141 -0
- package/template-starter/src/lib/components/Search.svelte +248 -0
- package/template-starter/src/lib/components/Sidebar.svelte +110 -0
- package/template-starter/src/lib/components/Tabs.svelte +48 -0
- package/template-starter/src/lib/components/Tabs.test.ts +17 -0
- package/template-starter/src/lib/index.ts +15 -0
- package/template-starter/src/routes/+layout.svelte +28 -0
- package/template-starter/src/routes/+page.svelte +92 -0
- package/template-starter/svelte.config.js +17 -0
- package/template-starter/tailwind.config.ts +17 -0
- package/template-starter/tsconfig.json +13 -0
- package/template-starter/vite.config.ts +6 -0
- package/tests/e2e/example.spec.ts +345 -0
- package/tsconfig.json +20 -0
- package/vite.config.ts +6 -0
- package/vitest.config.ts +34 -0
- package/vitest.setup.ts +21 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parseConfigFile, parseFrontmatter } from './configParser';
|
|
3
|
+
|
|
4
|
+
describe('Config Parser - JSON', () => {
|
|
5
|
+
it('should parse valid JSON config', () => {
|
|
6
|
+
const content = JSON.stringify({
|
|
7
|
+
name: 'My Docs',
|
|
8
|
+
docsRoute: '/docs',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const result = parseConfigFile(content, 'config.json');
|
|
12
|
+
expect(result.source).toBe('json');
|
|
13
|
+
expect(result.config.name).toBe('My Docs');
|
|
14
|
+
expect(result.config.docsRoute).toBe('/docs');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should detect JSON by file extension', () => {
|
|
18
|
+
const content = '{ "name": "test" }';
|
|
19
|
+
const result = parseConfigFile(content, 'config.json');
|
|
20
|
+
expect(result.source).toBe('json');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should handle invalid JSON gracefully', () => {
|
|
24
|
+
const content = '{ invalid json }';
|
|
25
|
+
const result = parseConfigFile(content, 'config.json');
|
|
26
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
27
|
+
expect(result.errors[0]).toContain('Invalid JSON');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should handle empty JSON object', () => {
|
|
31
|
+
const content = '{}';
|
|
32
|
+
const result = parseConfigFile(content, 'config.json');
|
|
33
|
+
expect(result.source).toBe('json');
|
|
34
|
+
expect(result.config).toEqual({});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('Config Parser - YAML', () => {
|
|
39
|
+
it('should parse valid YAML config', () => {
|
|
40
|
+
const content = `
|
|
41
|
+
name: My Docs
|
|
42
|
+
docsRoute: /docs
|
|
43
|
+
enableSearch: true
|
|
44
|
+
`.trim();
|
|
45
|
+
|
|
46
|
+
const result = parseConfigFile(content, 'config.yaml');
|
|
47
|
+
expect(result.source).toBe('yaml');
|
|
48
|
+
expect(result.config.name).toBe('My Docs');
|
|
49
|
+
expect(result.config.docsRoute).toBe('/docs');
|
|
50
|
+
expect(result.config.enableSearch).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should detect YAML by file extension', () => {
|
|
54
|
+
const content = 'name: test';
|
|
55
|
+
const result = parseConfigFile(content, 'config.yml');
|
|
56
|
+
expect(result.source).toBe('yaml');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should parse YAML with nested objects', () => {
|
|
60
|
+
const content = `
|
|
61
|
+
name: My Docs
|
|
62
|
+
theme:
|
|
63
|
+
primary: "#ff0000"
|
|
64
|
+
secondary: "#00ff00"
|
|
65
|
+
`.trim();
|
|
66
|
+
|
|
67
|
+
const result = parseConfigFile(content, 'config.yaml');
|
|
68
|
+
expect(result.config.theme?.primary).toBe('#ff0000');
|
|
69
|
+
expect(result.config.theme?.secondary).toBe('#00ff00');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should parse YAML boolean values', () => {
|
|
73
|
+
const content = `
|
|
74
|
+
enableSearch: true
|
|
75
|
+
darkMode: false
|
|
76
|
+
breadcrumbs: true
|
|
77
|
+
`.trim();
|
|
78
|
+
|
|
79
|
+
const result = parseConfigFile(content, 'config.yaml');
|
|
80
|
+
expect(result.config.enableSearch).toBe(true);
|
|
81
|
+
expect(result.config.darkMode).toBe(false);
|
|
82
|
+
expect(result.config.breadcrumbs).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should parse YAML with comments', () => {
|
|
86
|
+
const content = `
|
|
87
|
+
name: My Docs
|
|
88
|
+
docsRoute: /docs
|
|
89
|
+
`.trim();
|
|
90
|
+
|
|
91
|
+
const result = parseConfigFile(content, 'config.yaml');
|
|
92
|
+
expect(result.config.name).toBe('My Docs');
|
|
93
|
+
expect(result.config.docsRoute).toBe('/docs');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('Frontmatter Parser', () => {
|
|
98
|
+
it('should parse JSON frontmatter', () => {
|
|
99
|
+
const content = `---
|
|
100
|
+
{
|
|
101
|
+
"title": "My Page",
|
|
102
|
+
"author": "John Doe"
|
|
103
|
+
}
|
|
104
|
+
---
|
|
105
|
+
# Page Content
|
|
106
|
+
|
|
107
|
+
This is the body.`;
|
|
108
|
+
|
|
109
|
+
const result = parseFrontmatter(content);
|
|
110
|
+
expect(result.frontmatter?.title).toBe('My Page');
|
|
111
|
+
expect(result.frontmatter?.author).toBe('John Doe');
|
|
112
|
+
expect(result.body).toContain('# Page Content');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should parse YAML frontmatter', () => {
|
|
116
|
+
const content = `---
|
|
117
|
+
title: My Page
|
|
118
|
+
author: John Doe
|
|
119
|
+
date: 2024-01-01
|
|
120
|
+
---
|
|
121
|
+
# Page Content
|
|
122
|
+
|
|
123
|
+
This is the body.`;
|
|
124
|
+
|
|
125
|
+
const result = parseFrontmatter(content);
|
|
126
|
+
expect(result.frontmatter?.title).toBe('My Page');
|
|
127
|
+
expect(result.frontmatter?.author).toBe('John Doe');
|
|
128
|
+
expect(result.body).toContain('# Page Content');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should handle missing frontmatter', () => {
|
|
132
|
+
const content = `# Page Content
|
|
133
|
+
|
|
134
|
+
This is the body.`;
|
|
135
|
+
|
|
136
|
+
const result = parseFrontmatter(content);
|
|
137
|
+
expect(result.frontmatter).toBeNull();
|
|
138
|
+
expect(result.body).toBe(content);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should extract body correctly', () => {
|
|
142
|
+
const content = `---
|
|
143
|
+
title: Test
|
|
144
|
+
---
|
|
145
|
+
# Heading
|
|
146
|
+
|
|
147
|
+
Content here.`;
|
|
148
|
+
|
|
149
|
+
const result = parseFrontmatter(content);
|
|
150
|
+
expect(result.body).toBe('# Heading\n\nContent here.');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should handle empty content after frontmatter', () => {
|
|
154
|
+
const content = `---
|
|
155
|
+
title: Test
|
|
156
|
+
---
|
|
157
|
+
Content`;
|
|
158
|
+
|
|
159
|
+
const result = parseFrontmatter(content);
|
|
160
|
+
expect(result.body).toBe('Content');
|
|
161
|
+
expect(result.frontmatter?.title).toBe('Test');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should handle invalid frontmatter gracefully', () => {
|
|
165
|
+
const content = `---
|
|
166
|
+
title: Test
|
|
167
|
+
author: John
|
|
168
|
+
---
|
|
169
|
+
Content`;
|
|
170
|
+
|
|
171
|
+
const result = parseFrontmatter(content);
|
|
172
|
+
// Should parse YAML successfully if it's valid YAML
|
|
173
|
+
expect(result.frontmatter?.title).toBe('Test');
|
|
174
|
+
expect(result.body).toBe('Content');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should preserve multi-line content in body', () => {
|
|
178
|
+
const content = `---
|
|
179
|
+
title: Test
|
|
180
|
+
---
|
|
181
|
+
# Heading
|
|
182
|
+
|
|
183
|
+
- Item 1
|
|
184
|
+
- Item 2
|
|
185
|
+
|
|
186
|
+
Paragraph 1
|
|
187
|
+
|
|
188
|
+
Paragraph 2`;
|
|
189
|
+
|
|
190
|
+
const result = parseFrontmatter(content);
|
|
191
|
+
expect(result.body).toContain('- Item 1');
|
|
192
|
+
expect(result.body).toContain('Paragraph 2');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('File Format Detection', () => {
|
|
197
|
+
it('should detect JSON by content starting with {', () => {
|
|
198
|
+
const result = parseConfigFile('{ "test": true }', 'unknown');
|
|
199
|
+
expect(result.source).toBe('json');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should detect JSON by content starting with [', () => {
|
|
203
|
+
const result = parseConfigFile('[]', 'unknown');
|
|
204
|
+
expect(result.source).toBe('json');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should default to YAML for unknown format', () => {
|
|
208
|
+
const result = parseConfigFile('name: test', 'unknown');
|
|
209
|
+
expect(result.source).toBe('yaml');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should prefer file extension over content detection', () => {
|
|
213
|
+
const jsonContent = '{ "valid": "json" }';
|
|
214
|
+
const result = parseConfigFile(jsonContent, 'config.json');
|
|
215
|
+
expect(result.source).toBe('json');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config file parser supporting JSON and YAML formats
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ConfigOptions } from './config';
|
|
6
|
+
import { validateConfig } from './config';
|
|
7
|
+
|
|
8
|
+
export interface ParseResult {
|
|
9
|
+
config: ConfigOptions;
|
|
10
|
+
errors: string[];
|
|
11
|
+
source: 'json' | 'yaml' | 'unknown';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse JSON config file
|
|
16
|
+
*/
|
|
17
|
+
function parseJSON(content: string): { data: unknown; error?: string } {
|
|
18
|
+
try {
|
|
19
|
+
return { data: JSON.parse(content) };
|
|
20
|
+
} catch (err) {
|
|
21
|
+
return {
|
|
22
|
+
data: null,
|
|
23
|
+
error: `Invalid JSON: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parse YAML config file (simplified parser)
|
|
30
|
+
* Handles basic YAML key-value pairs and nested objects
|
|
31
|
+
*/
|
|
32
|
+
function parseYAML(content: string): { data: unknown; error?: string } {
|
|
33
|
+
try {
|
|
34
|
+
const result: Record<string, unknown> = {};
|
|
35
|
+
const lines = content.split('\n');
|
|
36
|
+
let currentObject: Record<string, unknown> | null = null;
|
|
37
|
+
let currentKey: string | null = null;
|
|
38
|
+
let indentStack: Array<{ indent: number; key: string; obj: Record<string, unknown> }> = [];
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
const line = lines[i];
|
|
42
|
+
|
|
43
|
+
// Skip empty lines and comments
|
|
44
|
+
if (!line.trim() || line.trim().startsWith('#')) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Calculate indentation
|
|
49
|
+
const indent = line.length - line.trimLeft().length;
|
|
50
|
+
const trimmedLine = line.trim();
|
|
51
|
+
|
|
52
|
+
// Pop stack if we've decreased indentation
|
|
53
|
+
while (indentStack.length > 0 && indentStack[indentStack.length - 1].indent >= indent) {
|
|
54
|
+
indentStack.pop();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Parse key: value
|
|
58
|
+
if (trimmedLine.includes(':')) {
|
|
59
|
+
const [key, ...valueParts] = trimmedLine.split(':');
|
|
60
|
+
const trimmedKey = key.trim();
|
|
61
|
+
const value = valueParts.join(':').trim();
|
|
62
|
+
|
|
63
|
+
// Determine parent object
|
|
64
|
+
const parent = indentStack.length > 0 ? indentStack[indentStack.length - 1].obj : result;
|
|
65
|
+
|
|
66
|
+
// Parse value
|
|
67
|
+
let parsedValue: unknown = value;
|
|
68
|
+
|
|
69
|
+
if (value === '') {
|
|
70
|
+
// Empty value - next items might be children
|
|
71
|
+
parsedValue = {};
|
|
72
|
+
indentStack.push({ indent, key: trimmedKey, obj: parsedValue as Record<string, unknown> });
|
|
73
|
+
} else if (value === 'true') {
|
|
74
|
+
parsedValue = true;
|
|
75
|
+
} else if (value === 'false') {
|
|
76
|
+
parsedValue = false;
|
|
77
|
+
} else if (/^\d+$/.test(value)) {
|
|
78
|
+
parsedValue = parseInt(value, 10);
|
|
79
|
+
} else if (/^\d+\.\d+$/.test(value)) {
|
|
80
|
+
parsedValue = parseFloat(value);
|
|
81
|
+
} else if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
82
|
+
parsedValue = value.slice(1, -1);
|
|
83
|
+
} else if (value.startsWith('[') && value.endsWith(']')) {
|
|
84
|
+
try {
|
|
85
|
+
parsedValue = JSON.parse(value);
|
|
86
|
+
} catch {
|
|
87
|
+
parsedValue = value;
|
|
88
|
+
}
|
|
89
|
+
} else if (value.startsWith('{') && value.endsWith('}')) {
|
|
90
|
+
try {
|
|
91
|
+
parsedValue = JSON.parse(value);
|
|
92
|
+
} catch {
|
|
93
|
+
parsedValue = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
parent[trimmedKey] = parsedValue;
|
|
98
|
+
currentKey = trimmedKey;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { data: result };
|
|
103
|
+
} catch (err) {
|
|
104
|
+
return {
|
|
105
|
+
data: null,
|
|
106
|
+
error: `Invalid YAML: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Parse frontmatter from markdown content
|
|
113
|
+
* Supports both JSON and YAML frontmatter
|
|
114
|
+
*/
|
|
115
|
+
export function parseFrontmatter(content: string): {
|
|
116
|
+
frontmatter: Record<string, unknown> | null;
|
|
117
|
+
body: string;
|
|
118
|
+
error?: string;
|
|
119
|
+
} {
|
|
120
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
121
|
+
|
|
122
|
+
if (!frontmatterMatch) {
|
|
123
|
+
return { frontmatter: null, body: content };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const frontmatterContent = frontmatterMatch[1];
|
|
127
|
+
const body = frontmatterMatch[2];
|
|
128
|
+
|
|
129
|
+
// Try JSON first
|
|
130
|
+
let parsed = parseJSON(frontmatterContent);
|
|
131
|
+
|
|
132
|
+
// If JSON fails, try YAML
|
|
133
|
+
if (parsed.error) {
|
|
134
|
+
parsed = parseYAML(frontmatterContent);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (parsed.error) {
|
|
138
|
+
return {
|
|
139
|
+
frontmatter: null,
|
|
140
|
+
body: content,
|
|
141
|
+
error: `Failed to parse frontmatter: ${parsed.error}`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
frontmatter: parsed.data as Record<string, unknown>,
|
|
147
|
+
body,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Detect file format from content or filename
|
|
153
|
+
*/
|
|
154
|
+
function detectFormat(content: string, filename: string): 'json' | 'yaml' {
|
|
155
|
+
// Check filename extension
|
|
156
|
+
if (filename.endsWith('.json')) return 'json';
|
|
157
|
+
if (filename.endsWith('.yaml') || filename.endsWith('.yml')) return 'yaml';
|
|
158
|
+
|
|
159
|
+
// Try to detect by content
|
|
160
|
+
const trimmed = content.trim();
|
|
161
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
162
|
+
return 'json';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return 'yaml';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Parse config file content (JSON or YAML)
|
|
170
|
+
*/
|
|
171
|
+
export function parseConfigFile(content: string, filename: string = 'config.json'): ParseResult {
|
|
172
|
+
const format = detectFormat(content, filename);
|
|
173
|
+
let parsed;
|
|
174
|
+
|
|
175
|
+
if (format === 'json') {
|
|
176
|
+
parsed = parseJSON(content);
|
|
177
|
+
} else {
|
|
178
|
+
parsed = parseYAML(content);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (parsed.error) {
|
|
182
|
+
return {
|
|
183
|
+
config: {},
|
|
184
|
+
errors: [parsed.error],
|
|
185
|
+
source: format,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const validation = validateConfig(parsed.data);
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
config: (parsed.data as ConfigOptions) || {},
|
|
193
|
+
errors: validation.errors,
|
|
194
|
+
source: format,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Load and parse a config file from a file path (browser-safe)
|
|
200
|
+
* In a browser environment, use fetch; in Node, use fs
|
|
201
|
+
*/
|
|
202
|
+
export async function loadConfigFile(filePath: string): Promise<ParseResult> {
|
|
203
|
+
try {
|
|
204
|
+
let content: string;
|
|
205
|
+
|
|
206
|
+
if (typeof window !== 'undefined') {
|
|
207
|
+
// Browser environment - use fetch
|
|
208
|
+
const response = await fetch(filePath);
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
return {
|
|
211
|
+
config: {},
|
|
212
|
+
errors: [`Failed to load config file: ${response.statusText}`],
|
|
213
|
+
source: 'unknown',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
content = await response.text();
|
|
217
|
+
} else {
|
|
218
|
+
// Node environment - would need fs module
|
|
219
|
+
return {
|
|
220
|
+
config: {},
|
|
221
|
+
errors: ['Cannot load config file in this environment'],
|
|
222
|
+
source: 'unknown',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return parseConfigFile(content, filePath);
|
|
227
|
+
} catch (err) {
|
|
228
|
+
return {
|
|
229
|
+
config: {},
|
|
230
|
+
errors: [`Error loading config file: ${err instanceof Error ? err.message : 'Unknown error'}`],
|
|
231
|
+
source: 'unknown',
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Re-export all doc components
|
|
2
|
+
export { default as Callout } from './components/Callout.svelte';
|
|
3
|
+
export { default as Tabs } from './components/Tabs.svelte';
|
|
4
|
+
export { default as CodeBlock } from './components/CodeBlock.svelte';
|
|
5
|
+
export { default as Image } from './components/Image.svelte';
|
|
6
|
+
export { default as APITable } from './components/APITable.svelte';
|
|
7
|
+
export { default as Breadcrumbs } from './components/Breadcrumbs.svelte';
|
|
8
|
+
export { default as Search } from './components/Search.svelte';
|
|
9
|
+
|
|
10
|
+
// Re-export all theme components
|
|
11
|
+
export { default as DocLayout } from './components/DocLayout.svelte';
|
|
12
|
+
export { default as Navbar } from './components/Navbar.svelte';
|
|
13
|
+
export { default as Sidebar } from './components/Sidebar.svelte';
|
|
14
|
+
export { default as Footer } from './components/Footer.svelte';
|
|
15
|
+
|
|
16
|
+
// Re-export stores
|
|
17
|
+
export { theme } from './stores/theme';
|
|
18
|
+
export { nav, sidebarOpen } from './stores/nav';
|
|
19
|
+
export { version } from './stores/version';
|
|
20
|
+
export { i18n } from './stores/i18n';
|
|
21
|
+
export { query, results, loading, resultCount, initPagefind, updateSearch, clearSearch, performSearch, subscribeToSearch } from './stores/search';
|
|
22
|
+
export type { NavItem, NavConfig, NavSection } from './stores/nav';
|
|
23
|
+
export type { VersionMetadata, VersionConfig } from './stores/version';
|
|
24
|
+
export type { Language, LanguageMetadata, I18nConfig } from './stores/i18n';
|
|
25
|
+
export type { SearchResult } from './stores/search';
|
|
26
|
+
|
|
27
|
+
// Re-export utilities
|
|
28
|
+
export {
|
|
29
|
+
renderMarkdown,
|
|
30
|
+
extractMetadata,
|
|
31
|
+
getExcerpt,
|
|
32
|
+
type MarkdownMetadata,
|
|
33
|
+
type MarkdownResult
|
|
34
|
+
} from './utils';
|