@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.
- package/README.md +155 -23
- package/dist/components/APITable.svelte.d.ts +21 -0
- package/dist/components/Breadcrumbs.svelte.d.ts +14 -0
- package/dist/components/Callout.svelte.d.ts +15 -0
- package/dist/components/CodeBlock.svelte.d.ts +12 -0
- package/{src/lib → dist}/components/DocLayout.svelte +18 -6
- package/dist/components/DocLayout.svelte.d.ts +18 -0
- package/dist/components/DocsPage.svelte +39 -0
- package/dist/components/DocsPage.svelte.d.ts +8 -0
- package/dist/components/Documentation.svelte +639 -0
- package/dist/components/Footer.svelte.d.ts +10 -0
- package/dist/components/Image.svelte.d.ts +15 -0
- package/{src/lib → dist}/components/Navbar.svelte +4 -4
- package/dist/components/Navbar.svelte.d.ts +10 -0
- package/{src/lib → dist}/components/Search.svelte +2 -2
- package/dist/components/Search.svelte.d.ts +6 -0
- package/{template-starter/src/lib → dist}/components/Sidebar.svelte +2 -2
- package/dist/components/Sidebar.svelte.d.ts +9 -0
- package/dist/components/Tabs.svelte.d.ts +16 -0
- package/dist/config.d.ts +93 -0
- package/dist/config.js +89 -0
- package/dist/configLoader.d.ts +48 -0
- package/dist/configLoader.js +187 -0
- package/dist/configParser.d.ts +27 -0
- package/dist/configParser.js +208 -0
- package/{template-starter/src/lib/index.ts → dist/index.d.ts} +6 -7
- package/dist/index.js +18 -0
- package/dist/navigationBuilder.d.ts +64 -0
- package/dist/navigationBuilder.js +225 -0
- package/dist/plugin.d.ts +30 -0
- package/dist/plugin.js +172 -0
- package/dist/routing.d.ts +48 -0
- package/dist/routing.js +92 -0
- package/dist/stores/i18n.d.ts +20 -0
- package/dist/stores/i18n.js +119 -0
- package/dist/stores/nav.d.ts +20 -0
- package/dist/stores/nav.js +15 -0
- package/dist/stores/search.d.ts +49 -0
- package/dist/stores/search.js +127 -0
- package/dist/stores/theme.d.ts +7 -0
- package/dist/stores/theme.js +152 -0
- package/dist/stores/version.d.ts +18 -0
- package/dist/stores/version.js +93 -0
- package/dist/themeCustomization.d.ts +46 -0
- package/dist/themeCustomization.js +188 -0
- package/dist/utils/highlight.d.ts +13 -0
- package/dist/utils/highlight.js +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/markdown.d.ts +40 -0
- package/dist/utils/markdown.js +165 -0
- package/package.json +44 -23
- package/COMPONENTS.md +0 -365
- package/COVERAGE_REPORT.md +0 -663
- package/SEARCH_VERIFICATION.md +0 -229
- package/TEST_SUMMARY.md +0 -344
- package/bin/init.js +0 -821
- package/docs/COMPONENT_LIBRARY_INTEGRATION_REPORT.md +0 -153
- package/docs/DARK_MODE_AUDIT_REPORT.md +0 -403
- package/docs/E2E_TESTS.md +0 -354
- package/docs/TESTING.md +0 -754
- package/docs/THEME_INHERITANCE.md +0 -192
- package/docs/de/index.md +0 -41
- package/docs/en/COMPONENTS.md +0 -443
- package/docs/en/api/examples.md +0 -100
- package/docs/en/api/overview.md +0 -69
- package/docs/en/components/index.md +0 -622
- package/docs/en/config/navigation.md +0 -505
- package/docs/en/config/theme-and-colors.md +0 -395
- package/docs/en/getting-started/integration.md +0 -406
- package/docs/en/guides/common-setups.md +0 -651
- package/docs/en/index.md +0 -243
- package/docs/en/markdown.md +0 -102
- package/docs/en/routing.md +0 -64
- package/docs/en/setup.md +0 -52
- package/docs/en/troubleshooting.md +0 -704
- package/docs/es/index.md +0 -41
- package/docs/fr/index.md +0 -41
- package/docs/ja/index.md +0 -41
- package/pagefind.toml +0 -8
- package/postcss.config.js +0 -5
- package/src/app.css +0 -119
- package/src/app.d.ts +0 -13
- package/src/app.html +0 -11
- package/src/lib/components/APITable.test.ts +0 -153
- package/src/lib/components/Breadcrumbs.test.ts +0 -148
- package/src/lib/components/Callout.test.ts +0 -100
- package/src/lib/components/CodeBlock.test.ts +0 -133
- package/src/lib/components/Image.test.ts +0 -163
- package/src/lib/components/Sidebar.svelte +0 -110
- package/src/lib/components/Tabs.test.ts +0 -102
- package/src/lib/config.test.ts +0 -140
- package/src/lib/config.ts +0 -179
- package/src/lib/configIntegration.test.ts +0 -272
- package/src/lib/configLoader.ts +0 -231
- package/src/lib/configParser.test.ts +0 -217
- package/src/lib/configParser.ts +0 -234
- package/src/lib/index.ts +0 -37
- package/src/lib/integration.test.ts +0 -426
- package/src/lib/navigationBuilder.test.ts +0 -338
- package/src/lib/navigationBuilder.ts +0 -268
- package/src/lib/performance.test.ts +0 -369
- package/src/lib/routing.test.ts +0 -202
- package/src/lib/routing.ts +0 -127
- package/src/lib/search-functionality.test.ts +0 -493
- package/src/lib/stores/i18n.test.ts +0 -180
- package/src/lib/stores/i18n.ts +0 -143
- package/src/lib/stores/nav.ts +0 -36
- package/src/lib/stores/search.test.ts +0 -140
- package/src/lib/stores/search.ts +0 -162
- package/src/lib/stores/theme.test.ts +0 -117
- package/src/lib/stores/theme.ts +0 -167
- package/src/lib/stores/version.test.ts +0 -139
- package/src/lib/stores/version.ts +0 -111
- package/src/lib/themeCustomization.test.ts +0 -223
- package/src/lib/themeCustomization.ts +0 -212
- package/src/lib/utils/highlight.test.ts +0 -136
- package/src/lib/utils/highlight.ts +0 -100
- package/src/lib/utils/index.ts +0 -7
- package/src/lib/utils/markdown.test.ts +0 -357
- package/src/lib/utils/markdown.ts +0 -77
- package/src/routes/+layout.server.ts +0 -1
- package/src/routes/+layout.svelte +0 -29
- package/src/routes/+page.svelte +0 -165
- package/src/routes/quote-demo/+page.svelte +0 -141
- package/static/robots.txt +0 -3
- package/svelte.config.js +0 -15
- package/tailwind.config.ts +0 -55
- package/template-starter/.github/workflows/build.yml +0 -40
- package/template-starter/.github/workflows/deploy-github-pages.yml +0 -47
- package/template-starter/.github/workflows/deploy-netlify.yml +0 -41
- package/template-starter/.github/workflows/deploy-vercel.yml +0 -64
- package/template-starter/NPM-PACKAGE-SETUP.md +0 -233
- package/template-starter/README.md +0 -320
- package/template-starter/docs/_config.json +0 -39
- package/template-starter/docs/api/components.md +0 -257
- package/template-starter/docs/api/overview.md +0 -169
- package/template-starter/docs/guides/configuration.md +0 -145
- package/template-starter/docs/guides/github-pages-deployment.md +0 -254
- package/template-starter/docs/guides/netlify-deployment.md +0 -159
- package/template-starter/docs/guides/vercel-deployment.md +0 -131
- package/template-starter/docs/index.md +0 -49
- package/template-starter/docs/setup.md +0 -149
- package/template-starter/package.json +0 -31
- package/template-starter/pagefind.toml +0 -3
- package/template-starter/postcss.config.js +0 -5
- package/template-starter/src/app.css +0 -34
- package/template-starter/src/app.d.ts +0 -13
- package/template-starter/src/app.html +0 -11
- package/template-starter/src/lib/components/APITable.svelte +0 -120
- package/template-starter/src/lib/components/APITable.test.ts +0 -96
- package/template-starter/src/lib/components/Breadcrumbs.svelte +0 -85
- package/template-starter/src/lib/components/Breadcrumbs.test.ts +0 -82
- package/template-starter/src/lib/components/Callout.svelte +0 -60
- package/template-starter/src/lib/components/Callout.test.ts +0 -91
- package/template-starter/src/lib/components/CodeBlock.svelte +0 -68
- package/template-starter/src/lib/components/CodeBlock.test.ts +0 -62
- package/template-starter/src/lib/components/DocLayout.svelte +0 -84
- package/template-starter/src/lib/components/Footer.svelte +0 -78
- package/template-starter/src/lib/components/Image.svelte +0 -100
- package/template-starter/src/lib/components/Image.test.ts +0 -81
- package/template-starter/src/lib/components/Navbar.svelte +0 -141
- package/template-starter/src/lib/components/Search.svelte +0 -248
- package/template-starter/src/lib/components/Tabs.svelte +0 -48
- package/template-starter/src/lib/components/Tabs.test.ts +0 -89
- package/template-starter/src/routes/+layout.svelte +0 -28
- package/template-starter/src/routes/+page.svelte +0 -92
- package/template-starter/svelte.config.js +0 -17
- package/template-starter/tailwind.config.ts +0 -17
- package/template-starter/tsconfig.json +0 -13
- package/template-starter/vite.config.ts +0 -6
- package/tests/e2e/example.spec.ts +0 -345
- package/tsconfig.json +0 -20
- package/vite.config.ts +0 -6
- package/vitest.config.ts +0 -33
- package/vitest.setup.ts +0 -21
- /package/{src/lib → dist}/assets/favicon.svg +0 -0
- /package/{src/lib → dist}/components/APITable.svelte +0 -0
- /package/{src/lib → dist}/components/Breadcrumbs.svelte +0 -0
- /package/{src/lib → dist}/components/Callout.svelte +0 -0
- /package/{src/lib → dist}/components/CodeBlock.svelte +0 -0
- /package/{src/lib → dist}/components/Footer.svelte +0 -0
- /package/{src/lib → dist}/components/Image.svelte +0 -0
- /package/{src/lib → dist}/components/Tabs.svelte +0 -0
- /package/{src/lib → dist}/svelte-component-library.d.ts +0 -0
package/src/lib/config.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration schema and types for the documentation system
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface ThemeConfig {
|
|
6
|
-
/** Primary color (hex, rgb, or CSS color name) */
|
|
7
|
-
primary?: string;
|
|
8
|
-
/** Secondary color */
|
|
9
|
-
secondary?: string;
|
|
10
|
-
/** Text color for light mode */
|
|
11
|
-
textLight?: string;
|
|
12
|
-
/** Text color for dark mode */
|
|
13
|
-
textDark?: string;
|
|
14
|
-
/** Background color for light mode */
|
|
15
|
-
bgLight?: string;
|
|
16
|
-
/** Background color for dark mode */
|
|
17
|
-
bgDark?: string;
|
|
18
|
-
/** Font family for body text */
|
|
19
|
-
fontFamily?: string;
|
|
20
|
-
/** Font family for headings */
|
|
21
|
-
headingFont?: string;
|
|
22
|
-
/** Sidebar background color */
|
|
23
|
-
sidebarBg?: string;
|
|
24
|
-
/** Navbar background color */
|
|
25
|
-
navbarBg?: string;
|
|
26
|
-
/** Code block background color */
|
|
27
|
-
codeBg?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface NavItem {
|
|
31
|
-
label: string;
|
|
32
|
-
href?: string;
|
|
33
|
-
children?: NavItem[];
|
|
34
|
-
icon?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface NavSection {
|
|
38
|
-
title: string;
|
|
39
|
-
items: NavItem[];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface NavigationConfig {
|
|
43
|
-
title?: string;
|
|
44
|
-
logo?: string;
|
|
45
|
-
sections?: NavSection[];
|
|
46
|
-
/** Auto-generate navigation from folder structure */
|
|
47
|
-
autoGenerate?: boolean;
|
|
48
|
-
/** Exclude paths from auto-generation */
|
|
49
|
-
excludePaths?: string[];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface ConfigOptions {
|
|
53
|
-
/** Name of the documentation project */
|
|
54
|
-
name?: string;
|
|
55
|
-
/** Mount point for docs (e.g., /docs, /help, /guides) */
|
|
56
|
-
docsRoute?: string;
|
|
57
|
-
/** Path to docs folder relative to project root */
|
|
58
|
-
docsFolderPath?: string;
|
|
59
|
-
/** Base URL path for links */
|
|
60
|
-
basePath?: string;
|
|
61
|
-
/** Theme configuration */
|
|
62
|
-
theme?: ThemeConfig;
|
|
63
|
-
/** Navigation configuration */
|
|
64
|
-
navigation?: NavigationConfig;
|
|
65
|
-
/** Enable search functionality */
|
|
66
|
-
enableSearch?: boolean;
|
|
67
|
-
/** Custom CSS file path */
|
|
68
|
-
customCss?: string;
|
|
69
|
-
/** Layout template name (default, minimal, full-width) */
|
|
70
|
-
layout?: 'default' | 'minimal' | 'full-width';
|
|
71
|
-
/** Enable dark mode toggle */
|
|
72
|
-
darkMode?: boolean;
|
|
73
|
-
/** Default theme (light or dark) */
|
|
74
|
-
defaultTheme?: 'light' | 'dark';
|
|
75
|
-
/** Enable breadcrumbs */
|
|
76
|
-
breadcrumbs?: boolean;
|
|
77
|
-
/** Enable prev/next navigation */
|
|
78
|
-
prevNext?: boolean;
|
|
79
|
-
/** Site title for header */
|
|
80
|
-
siteTitle?: string;
|
|
81
|
-
/** Site description for meta tags */
|
|
82
|
-
siteDescription?: string;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Default configuration values
|
|
87
|
-
*/
|
|
88
|
-
export const DEFAULT_CONFIG: ConfigOptions = {
|
|
89
|
-
name: 'Documentation',
|
|
90
|
-
docsRoute: '/docs',
|
|
91
|
-
docsFolderPath: './docs',
|
|
92
|
-
basePath: '/docs',
|
|
93
|
-
enableSearch: true,
|
|
94
|
-
layout: 'default',
|
|
95
|
-
darkMode: true,
|
|
96
|
-
defaultTheme: 'light',
|
|
97
|
-
breadcrumbs: true,
|
|
98
|
-
prevNext: true,
|
|
99
|
-
theme: {
|
|
100
|
-
primary: '#0066cc',
|
|
101
|
-
secondary: '#ff6b6b',
|
|
102
|
-
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
103
|
-
headingFont: 'system-ui, -apple-system, sans-serif',
|
|
104
|
-
},
|
|
105
|
-
navigation: {
|
|
106
|
-
autoGenerate: true,
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Validates a configuration object
|
|
112
|
-
*/
|
|
113
|
-
export function validateConfig(config: unknown): { valid: boolean; errors: string[] } {
|
|
114
|
-
const errors: string[] = [];
|
|
115
|
-
|
|
116
|
-
if (typeof config !== 'object' || config === null) {
|
|
117
|
-
errors.push('Configuration must be an object');
|
|
118
|
-
return { valid: false, errors };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const cfg = config as Record<string, unknown>;
|
|
122
|
-
|
|
123
|
-
// Validate docsRoute
|
|
124
|
-
if (cfg.docsRoute !== undefined) {
|
|
125
|
-
if (typeof cfg.docsRoute !== 'string') {
|
|
126
|
-
errors.push('docsRoute must be a string');
|
|
127
|
-
} else if (!cfg.docsRoute.startsWith('/')) {
|
|
128
|
-
errors.push('docsRoute must start with /');
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Validate layout
|
|
133
|
-
if (cfg.layout !== undefined) {
|
|
134
|
-
if (!['default', 'minimal', 'full-width'].includes(cfg.layout as string)) {
|
|
135
|
-
errors.push('layout must be one of: default, minimal, full-width');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Validate defaultTheme
|
|
140
|
-
if (cfg.defaultTheme !== undefined) {
|
|
141
|
-
if (!['light', 'dark'].includes(cfg.defaultTheme as string)) {
|
|
142
|
-
errors.push('defaultTheme must be either light or dark');
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Validate theme config
|
|
147
|
-
if (cfg.theme !== undefined) {
|
|
148
|
-
if (typeof cfg.theme !== 'object' || cfg.theme === null) {
|
|
149
|
-
errors.push('theme must be an object');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Validate navigation config
|
|
154
|
-
if (cfg.navigation !== undefined) {
|
|
155
|
-
if (typeof cfg.navigation !== 'object' || cfg.navigation === null) {
|
|
156
|
-
errors.push('navigation must be an object');
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return { valid: errors.length === 0, errors };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Merges user config with defaults
|
|
165
|
-
*/
|
|
166
|
-
export function mergeConfig(userConfig: ConfigOptions, defaults: ConfigOptions = DEFAULT_CONFIG): ConfigOptions {
|
|
167
|
-
return {
|
|
168
|
-
...defaults,
|
|
169
|
-
...userConfig,
|
|
170
|
-
theme: {
|
|
171
|
-
...defaults.theme,
|
|
172
|
-
...(userConfig.theme || {}),
|
|
173
|
-
},
|
|
174
|
-
navigation: {
|
|
175
|
-
...defaults.navigation,
|
|
176
|
-
...(userConfig.navigation || {}),
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mergeConfig, validateConfig, DEFAULT_CONFIG } from './config';
|
|
3
|
-
import { parseConfigFile } from './configParser';
|
|
4
|
-
import { createRouteConfig, validateRoute, buildNavLink, isDocsRoute } from './routing';
|
|
5
|
-
import { generateNavigationFromFiles } from './navigationBuilder';
|
|
6
|
-
import { generateCSSVariables, validateTheme, getThemeTemplate } from './themeCustomization';
|
|
7
|
-
|
|
8
|
-
describe('Configuration System Integration', () => {
|
|
9
|
-
describe('Full Config Workflow', () => {
|
|
10
|
-
it('should load and validate a complete configuration', () => {
|
|
11
|
-
const configContent = JSON.stringify({
|
|
12
|
-
name: 'My Documentation',
|
|
13
|
-
docsRoute: '/help',
|
|
14
|
-
theme: {
|
|
15
|
-
primary: '#0066cc',
|
|
16
|
-
secondary: '#ff6b6b',
|
|
17
|
-
},
|
|
18
|
-
navigation: {
|
|
19
|
-
title: 'Help Center',
|
|
20
|
-
autoGenerate: true,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const parseResult = parseConfigFile(configContent, 'config.json');
|
|
25
|
-
expect(parseResult.errors).toHaveLength(0);
|
|
26
|
-
|
|
27
|
-
const validation = validateConfig(parseResult.config);
|
|
28
|
-
expect(validation.valid).toBe(true);
|
|
29
|
-
|
|
30
|
-
const merged = mergeConfig(parseResult.config);
|
|
31
|
-
expect(merged.docsRoute).toBe('/help');
|
|
32
|
-
expect(merged.theme?.primary).toBe('#0066cc');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should handle config with custom route mount point', () => {
|
|
36
|
-
const config = mergeConfig({
|
|
37
|
-
docsRoute: '/guides',
|
|
38
|
-
docsFolderPath: './guides',
|
|
39
|
-
basePath: '/guides',
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
expect(config.docsRoute).toBe('/guides');
|
|
43
|
-
expect(config.basePath).toBe('/guides');
|
|
44
|
-
|
|
45
|
-
// Validate the route
|
|
46
|
-
expect(validateRoute(config.docsRoute!)).toBe(true);
|
|
47
|
-
|
|
48
|
-
// Create route config
|
|
49
|
-
const routeConfig = createRouteConfig(config);
|
|
50
|
-
expect(routeConfig.docsRoute).toBe('/guides');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should build correct navigation links with custom route', () => {
|
|
54
|
-
const config = mergeConfig({ docsRoute: '/help' });
|
|
55
|
-
const docsRoute = config.docsRoute || '/docs';
|
|
56
|
-
|
|
57
|
-
const link1 = buildNavLink('setup', docsRoute);
|
|
58
|
-
expect(link1).toBe('/help/setup');
|
|
59
|
-
|
|
60
|
-
const link2 = buildNavLink('api/overview', docsRoute);
|
|
61
|
-
expect(link2).toBe('/help/api/overview');
|
|
62
|
-
|
|
63
|
-
const link3 = buildNavLink('', docsRoute);
|
|
64
|
-
expect(link3).toBe('/help');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should verify routes with custom mount point', () => {
|
|
68
|
-
const config = mergeConfig({ docsRoute: '/documentation' });
|
|
69
|
-
const docsRoute = config.docsRoute || '/docs';
|
|
70
|
-
|
|
71
|
-
expect(isDocsRoute('/documentation', docsRoute)).toBe(true);
|
|
72
|
-
expect(isDocsRoute('/documentation/api', docsRoute)).toBe(true);
|
|
73
|
-
expect(isDocsRoute('/help', docsRoute)).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('Theme Configuration Integration', () => {
|
|
78
|
-
it('should apply theme configuration from config file', () => {
|
|
79
|
-
const themeConfig = getThemeTemplate('default');
|
|
80
|
-
const cssVars = generateCSSVariables(themeConfig);
|
|
81
|
-
|
|
82
|
-
expect(cssVars['--color-primary']).toBeDefined();
|
|
83
|
-
expect(cssVars['--color-secondary']).toBeDefined();
|
|
84
|
-
expect(cssVars['--font-family-body']).toBeDefined();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should validate custom theme config', () => {
|
|
88
|
-
const config = mergeConfig({
|
|
89
|
-
theme: {
|
|
90
|
-
primary: '#ff0000',
|
|
91
|
-
secondary: '#00ff00',
|
|
92
|
-
fontFamily: 'Arial, sans-serif',
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const themeValidation = validateTheme(config.theme!);
|
|
97
|
-
expect(themeValidation.valid).toBe(true);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should override default theme with config', () => {
|
|
101
|
-
const config = mergeConfig({
|
|
102
|
-
theme: {
|
|
103
|
-
primary: '#custom-color',
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
expect(config.theme?.primary).toBe('#custom-color');
|
|
108
|
-
// Should still have default secondary
|
|
109
|
-
expect(config.theme?.secondary).toBe(DEFAULT_CONFIG.theme?.secondary);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should generate CSS for theme customization', () => {
|
|
113
|
-
const darkTheme = getThemeTemplate('dark');
|
|
114
|
-
const cssVars = generateCSSVariables(darkTheme);
|
|
115
|
-
|
|
116
|
-
const stylesheet = Object.entries(cssVars)
|
|
117
|
-
.map(([key, value]) => ` ${key}: ${value};`)
|
|
118
|
-
.join('\n');
|
|
119
|
-
|
|
120
|
-
expect(stylesheet).toContain('--color-primary');
|
|
121
|
-
expect(stylesheet).toContain('--font-family');
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe('Navigation Configuration Integration', () => {
|
|
126
|
-
it('should generate navigation from config', () => {
|
|
127
|
-
const files = [
|
|
128
|
-
{ path: 'docs/index.md', name: 'index', title: 'Home', isIndex: true },
|
|
129
|
-
{ path: 'docs/setup.md', name: 'setup', title: 'Setup', isIndex: false },
|
|
130
|
-
{ path: 'docs/api/overview.md', name: 'overview', title: 'Overview', isIndex: false },
|
|
131
|
-
{ path: 'docs/api/reference.md', name: 'reference', title: 'Reference', isIndex: false },
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
const nav = generateNavigationFromFiles(files, '/docs');
|
|
135
|
-
expect(nav.length).toBeGreaterThan(0);
|
|
136
|
-
|
|
137
|
-
// Should have an API section
|
|
138
|
-
const apiSection = nav.find((s) => s.title.includes('api') || s.title.includes('API'));
|
|
139
|
-
if (apiSection) {
|
|
140
|
-
expect(apiSection.items.length).toBeGreaterThan(0);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should respect exclude patterns in navigation', () => {
|
|
145
|
-
const configContent = JSON.stringify({
|
|
146
|
-
navigation: {
|
|
147
|
-
excludePaths: ['draft', 'private'],
|
|
148
|
-
autoGenerate: true,
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const parseResult = parseConfigFile(configContent, 'config.json');
|
|
153
|
-
expect(parseResult.errors).toHaveLength(0);
|
|
154
|
-
expect(parseResult.config.navigation?.excludePaths).toEqual(['draft', 'private']);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe('Multi-Route Configuration', () => {
|
|
159
|
-
it('should support switching between different doc routes', () => {
|
|
160
|
-
// Project 1: /docs route
|
|
161
|
-
const config1 = mergeConfig({ docsRoute: '/docs' });
|
|
162
|
-
expect(config1.docsRoute).toBe('/docs');
|
|
163
|
-
expect(isDocsRoute('/docs/setup', config1.docsRoute!)).toBe(true);
|
|
164
|
-
expect(isDocsRoute('/help/setup', config1.docsRoute!)).toBe(false);
|
|
165
|
-
|
|
166
|
-
// Project 2: /help route
|
|
167
|
-
const config2 = mergeConfig({ docsRoute: '/help' });
|
|
168
|
-
expect(config2.docsRoute).toBe('/help');
|
|
169
|
-
expect(isDocsRoute('/help/setup', config2.docsRoute!)).toBe(true);
|
|
170
|
-
expect(isDocsRoute('/docs/setup', config2.docsRoute!)).toBe(false);
|
|
171
|
-
|
|
172
|
-
// Project 3: /guides route
|
|
173
|
-
const config3 = mergeConfig({ docsRoute: '/guides' });
|
|
174
|
-
expect(config3.docsRoute).toBe('/guides');
|
|
175
|
-
expect(isDocsRoute('/guides/tutorial', config3.docsRoute!)).toBe(true);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('End-to-End Configuration Scenario', () => {
|
|
180
|
-
it('should handle a complete doc system setup', () => {
|
|
181
|
-
// Simulate loading a config file
|
|
182
|
-
const configJSON = JSON.stringify({
|
|
183
|
-
name: 'API Documentation',
|
|
184
|
-
docsRoute: '/api-docs',
|
|
185
|
-
docsFolderPath: './docs/api',
|
|
186
|
-
enableSearch: true,
|
|
187
|
-
layout: 'full-width',
|
|
188
|
-
theme: {
|
|
189
|
-
primary: '#2563eb',
|
|
190
|
-
secondary: '#dc2626',
|
|
191
|
-
fontFamily: 'Inter, sans-serif',
|
|
192
|
-
headingFont: 'Poppins, sans-serif',
|
|
193
|
-
},
|
|
194
|
-
navigation: {
|
|
195
|
-
title: 'API Reference',
|
|
196
|
-
autoGenerate: true,
|
|
197
|
-
excludePaths: ['examples', 'draft'],
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// Parse the config
|
|
202
|
-
const parseResult = parseConfigFile(configJSON, 'config.json');
|
|
203
|
-
expect(parseResult.errors).toHaveLength(0);
|
|
204
|
-
|
|
205
|
-
// Validate it
|
|
206
|
-
const validation = validateConfig(parseResult.config);
|
|
207
|
-
expect(validation.valid).toBe(true);
|
|
208
|
-
|
|
209
|
-
// Merge with defaults
|
|
210
|
-
const finalConfig = mergeConfig(parseResult.config);
|
|
211
|
-
|
|
212
|
-
// Verify all parts work together
|
|
213
|
-
expect(finalConfig.name).toBe('API Documentation');
|
|
214
|
-
expect(finalConfig.docsRoute).toBe('/api-docs');
|
|
215
|
-
expect(finalConfig.enableSearch).toBe(true);
|
|
216
|
-
expect(finalConfig.layout).toBe('full-width');
|
|
217
|
-
|
|
218
|
-
// Verify theme
|
|
219
|
-
const themeValidation = validateTheme(finalConfig.theme!);
|
|
220
|
-
expect(themeValidation.valid).toBe(true);
|
|
221
|
-
|
|
222
|
-
const cssVars = generateCSSVariables(finalConfig.theme!);
|
|
223
|
-
expect(cssVars['--color-primary']).toBe('#2563eb');
|
|
224
|
-
expect(cssVars['--font-family-body']).toBe('Inter, sans-serif');
|
|
225
|
-
|
|
226
|
-
// Verify routing
|
|
227
|
-
const routeConfig = createRouteConfig(finalConfig);
|
|
228
|
-
expect(validateRoute(routeConfig.docsRoute)).toBe(true);
|
|
229
|
-
|
|
230
|
-
// Verify navigation config
|
|
231
|
-
expect(finalConfig.navigation?.title).toBe('API Reference');
|
|
232
|
-
expect(finalConfig.navigation?.excludePaths).toEqual(['examples', 'draft']);
|
|
233
|
-
|
|
234
|
-
// Verify navigation with custom route
|
|
235
|
-
const testLink = buildNavLink('endpoints/users', routeConfig.docsRoute);
|
|
236
|
-
expect(testLink).toBe('/api-docs/endpoints/users');
|
|
237
|
-
|
|
238
|
-
// Verify route detection
|
|
239
|
-
expect(isDocsRoute('/api-docs', routeConfig.docsRoute)).toBe(true);
|
|
240
|
-
expect(isDocsRoute('/api-docs/endpoints', routeConfig.docsRoute)).toBe(true);
|
|
241
|
-
expect(isDocsRoute('/docs', routeConfig.docsRoute)).toBe(false);
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
describe('Configuration Validation Scenarios', () => {
|
|
246
|
-
it('should reject invalid configurations', () => {
|
|
247
|
-
const invalidConfigs = [
|
|
248
|
-
{ docsRoute: 123 }, // Not a string
|
|
249
|
-
{ layout: 'invalid-layout' },
|
|
250
|
-
{ defaultTheme: 'blue' }, // Invalid theme value
|
|
251
|
-
{ theme: 'not-an-object' }, // Theme must be object
|
|
252
|
-
];
|
|
253
|
-
|
|
254
|
-
invalidConfigs.forEach((config) => {
|
|
255
|
-
const validation = validateConfig(config);
|
|
256
|
-
expect(validation.valid).toBe(false);
|
|
257
|
-
expect(validation.errors.length).toBeGreaterThan(0);
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it('should provide helpful error messages', () => {
|
|
262
|
-
const invalidConfig = {
|
|
263
|
-
layout: 'unknown',
|
|
264
|
-
defaultTheme: 'invalid',
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
const validation = validateConfig(invalidConfig);
|
|
268
|
-
expect(validation.errors.length).toBeGreaterThan(0);
|
|
269
|
-
expect(validation.errors.some((e) => e.includes('layout') || e.includes('defaultTheme'))).toBe(true);
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
});
|
package/src/lib/configLoader.ts
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration loader and manager
|
|
3
|
-
* Loads, validates, and manages the docs system configuration
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ConfigOptions } from './config';
|
|
7
|
-
import { DEFAULT_CONFIG, mergeConfig, validateConfig } from './config';
|
|
8
|
-
import { parseConfigFile, loadConfigFile, parseFrontmatter } from './configParser';
|
|
9
|
-
import { createRouteConfig, validateRoute } from './routing';
|
|
10
|
-
import { validateTheme } from './themeCustomization';
|
|
11
|
-
import { validateNavigation } from './navigationBuilder';
|
|
12
|
-
|
|
13
|
-
export interface ConfigLoadResult {
|
|
14
|
-
success: boolean;
|
|
15
|
-
config: ConfigOptions;
|
|
16
|
-
errors: string[];
|
|
17
|
-
warnings: string[];
|
|
18
|
-
source: 'default' | 'loaded' | 'merged';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Load configuration from a file
|
|
23
|
-
*/
|
|
24
|
-
export async function loadConfiguration(
|
|
25
|
-
configPath: string = '/docs/_config.json'
|
|
26
|
-
): Promise<ConfigLoadResult> {
|
|
27
|
-
const errors: string[] = [];
|
|
28
|
-
const warnings: string[] = [];
|
|
29
|
-
let userConfig: ConfigOptions = {};
|
|
30
|
-
|
|
31
|
-
// Try to load the config file
|
|
32
|
-
const result = await loadConfigFile(configPath);
|
|
33
|
-
|
|
34
|
-
if (result.errors.length > 0 && !configPath.includes('_config')) {
|
|
35
|
-
// If it's not a standard config file, it might not exist - that's ok
|
|
36
|
-
errors.push(...result.errors);
|
|
37
|
-
} else if (result.errors.length > 0) {
|
|
38
|
-
// For standard config file, log errors but continue with defaults
|
|
39
|
-
warnings.push(...result.errors);
|
|
40
|
-
} else {
|
|
41
|
-
userConfig = result.config;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Validate the loaded config
|
|
45
|
-
const validation = validateConfig(userConfig);
|
|
46
|
-
if (!validation.valid) {
|
|
47
|
-
warnings.push(...validation.errors);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Validate sub-configs
|
|
51
|
-
if (userConfig.theme) {
|
|
52
|
-
const themeValidation = validateTheme(userConfig.theme);
|
|
53
|
-
if (!themeValidation.valid) {
|
|
54
|
-
warnings.push(`Theme validation errors: ${themeValidation.errors.join(', ')}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (userConfig.navigation) {
|
|
59
|
-
const navValidation = validateNavigation(userConfig.navigation);
|
|
60
|
-
if (!navValidation.valid) {
|
|
61
|
-
warnings.push(`Navigation validation errors: ${navValidation.errors.join(', ')}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Validate route
|
|
66
|
-
if (userConfig.docsRoute && !validateRoute(userConfig.docsRoute)) {
|
|
67
|
-
errors.push(`Invalid docsRoute: ${userConfig.docsRoute}`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Merge with defaults
|
|
71
|
-
const finalConfig = mergeConfig(userConfig, DEFAULT_CONFIG);
|
|
72
|
-
|
|
73
|
-
// Validate final config
|
|
74
|
-
const finalValidation = validateConfig(finalConfig);
|
|
75
|
-
if (!finalValidation.valid) {
|
|
76
|
-
errors.push(...finalValidation.errors);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const success = errors.length === 0;
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
success,
|
|
83
|
-
config: finalConfig,
|
|
84
|
-
errors,
|
|
85
|
-
warnings,
|
|
86
|
-
source: success ? 'loaded' : warnings.length > 0 ? 'merged' : 'default',
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Load and cache configuration (for browser environment)
|
|
92
|
-
*/
|
|
93
|
-
let cachedConfig: ConfigOptions | null = null;
|
|
94
|
-
let configLoadPromise: Promise<ConfigLoadResult> | null = null;
|
|
95
|
-
|
|
96
|
-
export async function getConfiguration(configPath: string = '/docs/_config.json'): Promise<ConfigOptions> {
|
|
97
|
-
if (cachedConfig) {
|
|
98
|
-
return cachedConfig;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (!configLoadPromise) {
|
|
102
|
-
configLoadPromise = loadConfiguration(configPath);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const result = await configLoadPromise;
|
|
106
|
-
cachedConfig = result.config;
|
|
107
|
-
return result.config;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Clear configuration cache (useful for testing or reloading)
|
|
112
|
-
*/
|
|
113
|
-
export function clearConfigCache(): void {
|
|
114
|
-
cachedConfig = null;
|
|
115
|
-
configLoadPromise = null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Parse frontmatter from markdown content and merge with config
|
|
120
|
-
*/
|
|
121
|
-
export function parseMarkdownFrontmatter(content: string): {
|
|
122
|
-
frontmatter: Record<string, unknown>;
|
|
123
|
-
body: string;
|
|
124
|
-
errors: string[];
|
|
125
|
-
} {
|
|
126
|
-
const result = parseFrontmatter(content);
|
|
127
|
-
|
|
128
|
-
if (result.error) {
|
|
129
|
-
return {
|
|
130
|
-
frontmatter: {},
|
|
131
|
-
body: result.body,
|
|
132
|
-
errors: [result.error],
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
frontmatter: result.frontmatter || {},
|
|
138
|
-
body: result.body,
|
|
139
|
-
errors: [],
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Validate a custom config object
|
|
145
|
-
*/
|
|
146
|
-
export function validateCustomConfig(config: unknown): { valid: boolean; errors: string[] } {
|
|
147
|
-
const validation = validateConfig(config);
|
|
148
|
-
|
|
149
|
-
if (!validation.valid) {
|
|
150
|
-
return validation;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const cfg = config as ConfigOptions;
|
|
154
|
-
const errors: string[] = [];
|
|
155
|
-
|
|
156
|
-
// Additional validations
|
|
157
|
-
if (cfg.theme) {
|
|
158
|
-
const themeValidation = validateTheme(cfg.theme);
|
|
159
|
-
if (!themeValidation.valid) {
|
|
160
|
-
errors.push(`Theme: ${themeValidation.errors.join(', ')}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (cfg.navigation) {
|
|
165
|
-
const navValidation = validateNavigation(cfg.navigation);
|
|
166
|
-
if (!navValidation.valid) {
|
|
167
|
-
errors.push(`Navigation: ${navValidation.errors.join(', ')}`);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (cfg.docsRoute && !validateRoute(cfg.docsRoute)) {
|
|
172
|
-
errors.push(`Invalid docsRoute: ${cfg.docsRoute}`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return { valid: errors.length === 0, errors };
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Create a configuration from minimal user input
|
|
180
|
-
*/
|
|
181
|
-
export function createMinimalConfig(options: Partial<ConfigOptions> = {}): ConfigOptions {
|
|
182
|
-
return mergeConfig(options, DEFAULT_CONFIG);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Export configuration as JSON
|
|
187
|
-
*/
|
|
188
|
-
export function exportConfigAsJSON(config: ConfigOptions): string {
|
|
189
|
-
return JSON.stringify(config, null, 2);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Export configuration as YAML
|
|
194
|
-
*/
|
|
195
|
-
export function exportConfigAsYAML(config: ConfigOptions): string {
|
|
196
|
-
const lines: string[] = [];
|
|
197
|
-
|
|
198
|
-
function addValue(key: string, value: unknown, indent: number = 0): void {
|
|
199
|
-
const indentStr = ' '.repeat(indent);
|
|
200
|
-
|
|
201
|
-
if (value === null || value === undefined) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (typeof value === 'string') {
|
|
206
|
-
lines.push(`${indentStr}${key}: ${value}`);
|
|
207
|
-
} else if (typeof value === 'boolean' || typeof value === 'number') {
|
|
208
|
-
lines.push(`${indentStr}${key}: ${value}`);
|
|
209
|
-
} else if (Array.isArray(value)) {
|
|
210
|
-
lines.push(`${indentStr}${key}:`);
|
|
211
|
-
value.forEach((item, idx) => {
|
|
212
|
-
if (typeof item === 'object') {
|
|
213
|
-
addValue(`- `, item, indent + 1);
|
|
214
|
-
} else {
|
|
215
|
-
lines.push(`${indentStr} - ${item}`);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
} else if (typeof value === 'object') {
|
|
219
|
-
lines.push(`${indentStr}${key}:`);
|
|
220
|
-
Object.entries(value).forEach(([k, v]) => {
|
|
221
|
-
addValue(k, v, indent + 1);
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
Object.entries(config).forEach(([key, value]) => {
|
|
227
|
-
addValue(key, value);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
return lines.join('\n');
|
|
231
|
-
}
|