sdocs 0.0.2 → 0.0.4

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 (194) hide show
  1. package/bin/sdocs.js +1 -1
  2. package/dist/app-gen.d.ts +10 -0
  3. package/dist/app-gen.js +147 -0
  4. package/dist/cli.js +71 -0
  5. package/dist/client/App.svelte +151 -0
  6. package/dist/client/App.svelte.d.ts +14 -0
  7. package/dist/client/CollapsiblePanel.svelte +63 -0
  8. package/dist/client/CollapsiblePanel.svelte.d.ts +9 -0
  9. package/dist/client/ComponentView.svelte +321 -0
  10. package/dist/client/ComponentView.svelte.d.ts +10 -0
  11. package/dist/client/ControlsPanel.svelte +191 -0
  12. package/dist/client/ControlsPanel.svelte.d.ts +13 -0
  13. package/dist/client/DataTable.svelte +78 -0
  14. package/dist/client/DataTable.svelte.d.ts +11 -0
  15. package/dist/client/HomePage.svelte +92 -0
  16. package/dist/client/HomePage.svelte.d.ts +8 -0
  17. package/dist/client/LayoutView.svelte +27 -0
  18. package/dist/client/LayoutView.svelte.d.ts +8 -0
  19. package/dist/client/PageView.svelte +130 -0
  20. package/dist/client/PageView.svelte.d.ts +8 -0
  21. package/dist/client/PreviewFrame.svelte +100 -0
  22. package/dist/client/PreviewFrame.svelte.d.ts +10 -0
  23. package/dist/client/Sidebar.svelte +329 -0
  24. package/dist/client/Sidebar.svelte.d.ts +16 -0
  25. package/dist/client/controls/CheckboxControl.svelte +37 -0
  26. package/dist/client/controls/CheckboxControl.svelte.d.ts +8 -0
  27. package/dist/client/controls/ColorControl.svelte +47 -0
  28. package/dist/client/controls/ColorControl.svelte.d.ts +8 -0
  29. package/dist/client/controls/DimensionControl.svelte +56 -0
  30. package/dist/client/controls/DimensionControl.svelte.d.ts +8 -0
  31. package/dist/client/controls/NumberControl.svelte +44 -0
  32. package/dist/client/controls/NumberControl.svelte.d.ts +8 -0
  33. package/dist/client/controls/SelectControl.svelte +48 -0
  34. package/dist/client/controls/SelectControl.svelte.d.ts +9 -0
  35. package/dist/client/controls/TextControl.svelte +43 -0
  36. package/dist/client/controls/TextControl.svelte.d.ts +8 -0
  37. package/dist/client/router.svelte.d.ts +11 -0
  38. package/dist/client/router.svelte.js +45 -0
  39. package/dist/client/theme.css +34 -0
  40. package/dist/client/tree-builder.d.ts +30 -0
  41. package/dist/client/tree-builder.js +162 -0
  42. package/dist/commands/build.d.ts +1 -0
  43. package/dist/commands/build.js +38 -0
  44. package/dist/commands/dev.d.ts +1 -0
  45. package/dist/commands/dev.js +40 -0
  46. package/dist/commands/init.d.ts +1 -0
  47. package/dist/commands/init.js +41 -0
  48. package/dist/commands/preview.d.ts +1 -0
  49. package/dist/commands/preview.js +25 -0
  50. package/dist/config.d.ts +7 -0
  51. package/dist/config.js +57 -0
  52. package/dist/index.d.ts +2 -2
  53. package/dist/index.js +1 -4
  54. package/dist/server/discovery.d.ts +6 -0
  55. package/dist/server/discovery.js +24 -0
  56. package/dist/server/highlighter.d.ts +4 -0
  57. package/dist/server/highlighter.js +31 -0
  58. package/dist/server/meta-parser.d.ts +11 -0
  59. package/dist/server/meta-parser.js +107 -0
  60. package/dist/server/prop-parser.d.ts +5 -0
  61. package/dist/server/prop-parser.js +275 -0
  62. package/dist/server/sdocx-parser.d.ts +11 -0
  63. package/dist/server/sdocx-parser.js +197 -0
  64. package/dist/server/snippet-compiler.d.ts +27 -0
  65. package/dist/server/snippet-compiler.js +145 -0
  66. package/dist/server/snippet-extractor.d.ts +11 -0
  67. package/dist/server/snippet-extractor.js +37 -0
  68. package/dist/server/toc-extractor.d.ts +5 -0
  69. package/dist/server/toc-extractor.js +37 -0
  70. package/dist/types.d.ts +100 -148
  71. package/dist/vite.d.ts +5 -2
  72. package/dist/vite.js +266 -2
  73. package/package.json +50 -74
  74. package/README.md +0 -43
  75. package/dist/Sdocs.svelte +0 -1210
  76. package/dist/Sdocs.svelte.d.ts +0 -5
  77. package/dist/cli/app-plugin.d.ts +0 -7
  78. package/dist/cli/app-plugin.js +0 -69
  79. package/dist/cli/config.d.ts +0 -12
  80. package/dist/cli/config.js +0 -34
  81. package/dist/cli/index.js +0 -72
  82. package/dist/cli/server.d.ts +0 -2
  83. package/dist/cli/server.js +0 -63
  84. package/dist/docgen.d.ts +0 -47
  85. package/dist/docgen.js +0 -463
  86. package/dist/internal/ComponentPreview.svelte +0 -58
  87. package/dist/internal/ComponentPreview.svelte.d.ts +0 -17
  88. package/dist/internal/CssPropsTable.svelte +0 -239
  89. package/dist/internal/CssPropsTable.svelte.d.ts +0 -11
  90. package/dist/internal/Home.svelte +0 -92
  91. package/dist/internal/Home.svelte.d.ts +0 -9
  92. package/dist/internal/MethodsTable.svelte +0 -72
  93. package/dist/internal/MethodsTable.svelte.d.ts +0 -7
  94. package/dist/internal/PropsTable.svelte +0 -342
  95. package/dist/internal/PropsTable.svelte.d.ts +0 -12
  96. package/dist/internal/Showcase.svelte +0 -130
  97. package/dist/internal/Showcase.svelte.d.ts +0 -21
  98. package/dist/ui/Badge/Badge.docs.svelte +0 -46
  99. package/dist/ui/Badge/Badge.docs.svelte.d.ts +0 -26
  100. package/dist/ui/Badge/Badge.svelte +0 -59
  101. package/dist/ui/Badge/Badge.svelte.d.ts +0 -17
  102. package/dist/ui/Badge/index.d.ts +0 -1
  103. package/dist/ui/Badge/index.js +0 -1
  104. package/dist/ui/Checkbox/Checkbox.docs.svelte +0 -51
  105. package/dist/ui/Checkbox/Checkbox.docs.svelte.d.ts +0 -27
  106. package/dist/ui/Checkbox/Checkbox.svelte +0 -169
  107. package/dist/ui/Checkbox/Checkbox.svelte.d.ts +0 -18
  108. package/dist/ui/Checkbox/index.d.ts +0 -1
  109. package/dist/ui/Checkbox/index.js +0 -1
  110. package/dist/ui/CodeBlock/CodeBlock.docs.svelte +0 -28
  111. package/dist/ui/CodeBlock/CodeBlock.docs.svelte.d.ts +0 -24
  112. package/dist/ui/CodeBlock/CodeBlock.svelte +0 -101
  113. package/dist/ui/CodeBlock/CodeBlock.svelte.d.ts +0 -7
  114. package/dist/ui/CodeBlock/index.d.ts +0 -1
  115. package/dist/ui/CodeBlock/index.js +0 -1
  116. package/dist/ui/Frame/Frame.docs.svelte +0 -140
  117. package/dist/ui/Frame/Frame.docs.svelte.d.ts +0 -26
  118. package/dist/ui/Frame/Frame.svelte +0 -88
  119. package/dist/ui/Frame/Frame.svelte.d.ts +0 -15
  120. package/dist/ui/Frame/index.d.ts +0 -1
  121. package/dist/ui/Frame/index.js +0 -1
  122. package/dist/ui/InputNumber/InputNumber.docs.svelte +0 -50
  123. package/dist/ui/InputNumber/InputNumber.docs.svelte.d.ts +0 -26
  124. package/dist/ui/InputNumber/InputNumber.svelte +0 -275
  125. package/dist/ui/InputNumber/InputNumber.svelte.d.ts +0 -26
  126. package/dist/ui/InputNumber/index.d.ts +0 -1
  127. package/dist/ui/InputNumber/index.js +0 -1
  128. package/dist/ui/InputText/InputText.docs.svelte +0 -43
  129. package/dist/ui/InputText/InputText.docs.svelte.d.ts +0 -26
  130. package/dist/ui/InputText/InputText.svelte +0 -116
  131. package/dist/ui/InputText/InputText.svelte.d.ts +0 -22
  132. package/dist/ui/InputText/index.d.ts +0 -1
  133. package/dist/ui/InputText/index.js +0 -1
  134. package/dist/ui/Panel/CollapsiblePanel.docs.svelte +0 -45
  135. package/dist/ui/Panel/CollapsiblePanel.docs.svelte.d.ts +0 -25
  136. package/dist/ui/Panel/CollapsiblePanel.svelte +0 -93
  137. package/dist/ui/Panel/CollapsiblePanel.svelte.d.ts +0 -14
  138. package/dist/ui/Panel/index.d.ts +0 -1
  139. package/dist/ui/Panel/index.js +0 -1
  140. package/dist/ui/Placeholder/Placeholder.docs.svelte +0 -49
  141. package/dist/ui/Placeholder/Placeholder.docs.svelte.d.ts +0 -26
  142. package/dist/ui/Placeholder/Placeholder.svelte +0 -99
  143. package/dist/ui/Placeholder/Placeholder.svelte.d.ts +0 -21
  144. package/dist/ui/Placeholder/index.d.ts +0 -1
  145. package/dist/ui/Placeholder/index.js +0 -1
  146. package/dist/ui/Radio/Radio.docs.svelte +0 -67
  147. package/dist/ui/Radio/Radio.docs.svelte.d.ts +0 -27
  148. package/dist/ui/Radio/Radio.svelte +0 -165
  149. package/dist/ui/Radio/Radio.svelte.d.ts +0 -22
  150. package/dist/ui/Radio/RadioGroup.docs.svelte +0 -70
  151. package/dist/ui/Radio/RadioGroup.docs.svelte.d.ts +0 -27
  152. package/dist/ui/Radio/RadioGroup.svelte +0 -98
  153. package/dist/ui/Radio/RadioGroup.svelte.d.ts +0 -27
  154. package/dist/ui/Radio/index.d.ts +0 -2
  155. package/dist/ui/Radio/index.js +0 -2
  156. package/dist/ui/SegmentControl/SegmentControl.docs.svelte +0 -54
  157. package/dist/ui/SegmentControl/SegmentControl.docs.svelte.d.ts +0 -25
  158. package/dist/ui/SegmentControl/SegmentControl.svelte +0 -120
  159. package/dist/ui/SegmentControl/SegmentControl.svelte.d.ts +0 -18
  160. package/dist/ui/SegmentControl/index.d.ts +0 -1
  161. package/dist/ui/SegmentControl/index.js +0 -1
  162. package/dist/ui/Stack/Stack.docs.svelte +0 -63
  163. package/dist/ui/Stack/Stack.docs.svelte.d.ts +0 -26
  164. package/dist/ui/Stack/Stack.svelte +0 -45
  165. package/dist/ui/Stack/Stack.svelte.d.ts +0 -19
  166. package/dist/ui/Stack/index.d.ts +0 -1
  167. package/dist/ui/Stack/index.js +0 -1
  168. package/dist/ui/Table/Body.svelte +0 -17
  169. package/dist/ui/Table/Body.svelte.d.ts +0 -11
  170. package/dist/ui/Table/Caption.svelte +0 -17
  171. package/dist/ui/Table/Caption.svelte.d.ts +0 -11
  172. package/dist/ui/Table/Cell.svelte +0 -24
  173. package/dist/ui/Table/Cell.svelte.d.ts +0 -15
  174. package/dist/ui/Table/Foot.svelte +0 -17
  175. package/dist/ui/Table/Foot.svelte.d.ts +0 -11
  176. package/dist/ui/Table/Head.svelte +0 -17
  177. package/dist/ui/Table/Head.svelte.d.ts +0 -11
  178. package/dist/ui/Table/Header.svelte +0 -27
  179. package/dist/ui/Table/Header.svelte.d.ts +0 -17
  180. package/dist/ui/Table/Row.svelte +0 -19
  181. package/dist/ui/Table/Row.svelte.d.ts +0 -13
  182. package/dist/ui/Table/Table.docs.svelte +0 -197
  183. package/dist/ui/Table/Table.docs.svelte.d.ts +0 -28
  184. package/dist/ui/Table/Table.svelte +0 -140
  185. package/dist/ui/Table/Table.svelte.d.ts +0 -27
  186. package/dist/ui/Table/index.js +0 -10
  187. package/dist/ui/css/colors.css +0 -377
  188. package/dist/ui/css/global.css +0 -10
  189. package/dist/ui/index.d.ts +0 -12
  190. package/dist/ui/index.js +0 -12
  191. package/dist/virtual-sdocs.d.ts +0 -20
  192. package/dist/vite-plugin.d.ts +0 -18
  193. package/dist/vite-plugin.js +0 -206
  194. /package/dist/{cli/index.d.ts → cli.d.ts} +0 -0
@@ -0,0 +1,45 @@
1
+ /** Hash-based router for sdocs. Uses #/Segment/Segment/... format. */
2
+ /** Current hash path segments (reactive) */
3
+ let currentPath = $state([]);
4
+ /** Get the current path segments */
5
+ export function getPath() {
6
+ return currentPath;
7
+ }
8
+ /** Navigate to a path */
9
+ export function navigate(segments) {
10
+ const hash = segments.length > 0
11
+ ? '#/' + segments.map(encodeSegment).join('/')
12
+ : '#/';
13
+ window.location.hash = hash;
14
+ }
15
+ /** Parse hash into path segments */
16
+ function parseHash() {
17
+ const hash = window.location.hash;
18
+ if (!hash || hash === '#' || hash === '#/')
19
+ return [];
20
+ const path = hash.startsWith('#/') ? hash.slice(2) : hash.slice(1);
21
+ return path.split('/').filter(Boolean).map(decodeSegment);
22
+ }
23
+ /** Encode a segment: spaces → hyphens */
24
+ function encodeSegment(s) {
25
+ return s.replace(/\s+/g, '-');
26
+ }
27
+ /** Decode a segment: hyphens → spaces */
28
+ function decodeSegment(s) {
29
+ return s.replace(/-/g, ' ');
30
+ }
31
+ /** Initialize the router — call once on app startup */
32
+ export function initRouter() {
33
+ currentPath = parseHash();
34
+ window.addEventListener('hashchange', () => {
35
+ currentPath = parseHash();
36
+ });
37
+ }
38
+ /** Build a title path from meta.title (e.g. 'Demo / Button' → ['Demo', 'Button']) */
39
+ export function titleToPath(title) {
40
+ return title.split('/').map((s) => s.trim()).filter(Boolean);
41
+ }
42
+ /** Build a hash string from a title path (for href attributes) */
43
+ export function pathToHash(segments) {
44
+ return '#/' + segments.map(encodeSegment).join('/');
45
+ }
@@ -0,0 +1,34 @@
1
+ /* sdocs color system — semantic CSS variables */
2
+
3
+ :root,
4
+ [data-sdocs-theme="light"] {
5
+ --sdocs-bg: #ffffff;
6
+ --sdocs-bg-subtle: #f8fafc;
7
+ --sdocs-bg-hover: #f1f5f9;
8
+ --sdocs-border: #e2e8f0;
9
+ --sdocs-border-muted: #cbd5e1;
10
+ --sdocs-text: #475569;
11
+ --sdocs-text-secondary: #64748b;
12
+ --sdocs-text-muted: #94a3b8;
13
+ --sdocs-text-heading: #1e293b;
14
+ --sdocs-text-strong: #334155;
15
+ --sdocs-primary: #3b82f6;
16
+ --sdocs-primary-bg: rgba(59, 130, 246, 0.1);
17
+ --sdocs-shadow: rgba(0, 0, 0, 0.1);
18
+ }
19
+
20
+ [data-sdocs-theme="dark"] {
21
+ --sdocs-bg: #0f172a;
22
+ --sdocs-bg-subtle: #1e293b;
23
+ --sdocs-bg-hover: #334155;
24
+ --sdocs-border: #334155;
25
+ --sdocs-border-muted: #475569;
26
+ --sdocs-text: #cbd5e1;
27
+ --sdocs-text-secondary: #94a3b8;
28
+ --sdocs-text-muted: #64748b;
29
+ --sdocs-text-heading: #f1f5f9;
30
+ --sdocs-text-strong: #e2e8f0;
31
+ --sdocs-primary: #60a5fa;
32
+ --sdocs-primary-bg: rgba(96, 165, 250, 0.15);
33
+ --sdocs-shadow: rgba(0, 0, 0, 0.3);
34
+ }
@@ -0,0 +1,30 @@
1
+ import type { DocEntry } from '../types.js';
2
+ export type TreeNodeType = 'folder' | 'group' | 'component' | 'page' | 'layout';
3
+ export interface TreeNode {
4
+ name: string;
5
+ type: TreeNodeType;
6
+ /** Full path segments from root (for routing) */
7
+ path: string[];
8
+ /** Children nodes */
9
+ children: TreeNode[];
10
+ /** The doc entry (only for component/page/layout nodes) */
11
+ doc?: DocEntry;
12
+ /** Snippet names for component nodes (excludes Default) */
13
+ examples?: string[];
14
+ /** Whether this node should be expanded by default */
15
+ defaultExpanded?: boolean;
16
+ }
17
+ interface SidebarConfig {
18
+ order?: Record<string, string[]>;
19
+ open?: string[];
20
+ }
21
+ /** Build a tree from flat doc entries */
22
+ export declare function buildTree(docs: DocEntry[], sidebar?: SidebarConfig): TreeNode[];
23
+ /** Check if a path matches a tree node (for active state) */
24
+ export declare function pathMatchesNode(currentPath: string[], node: TreeNode): boolean;
25
+ /** Find the doc entry for a given path */
26
+ export declare function findDocByPath(docs: DocEntry[], path: string[]): {
27
+ doc: DocEntry;
28
+ snippetName?: string;
29
+ } | null;
30
+ export {};
@@ -0,0 +1,162 @@
1
+ /** Build a tree from flat doc entries */
2
+ export function buildTree(docs, sidebar) {
3
+ const root = [];
4
+ const folderMap = new Map();
5
+ for (const doc of docs) {
6
+ const title = doc.meta.title ?? 'Untitled';
7
+ const segments = title.split('/').map((s) => s.trim()).filter(Boolean);
8
+ if (segments.length === 0)
9
+ continue;
10
+ const kind = doc.kind;
11
+ const itemName = segments[segments.length - 1];
12
+ const folderSegments = segments.slice(0, -1);
13
+ // Ensure all parent folders exist
14
+ let parent = root;
15
+ const currentPath = [];
16
+ for (let i = 0; i < folderSegments.length; i++) {
17
+ let segName = folderSegments[i];
18
+ const isGroup = i === 0 && segName.startsWith(':');
19
+ if (isGroup)
20
+ segName = segName.slice(1);
21
+ currentPath.push(segName);
22
+ const key = currentPath.join('/');
23
+ let folder = folderMap.get(key);
24
+ if (!folder) {
25
+ folder = {
26
+ name: segName,
27
+ type: isGroup ? 'group' : 'folder',
28
+ path: [...currentPath],
29
+ children: [],
30
+ defaultExpanded: isGroup || sidebar?.open?.includes(segName),
31
+ };
32
+ folderMap.set(key, folder);
33
+ parent.push(folder);
34
+ }
35
+ parent = folder.children;
36
+ }
37
+ // Create the item node
38
+ const itemPath = [...currentPath, itemName];
39
+ if (kind === 'component') {
40
+ const examples = doc.snippets
41
+ ?.filter((s) => s.name !== 'Default')
42
+ .map((s) => s.name) ?? [];
43
+ const componentNode = {
44
+ name: itemName,
45
+ type: 'component',
46
+ path: itemPath,
47
+ children: [],
48
+ doc,
49
+ examples,
50
+ };
51
+ // Add "Docs" child
52
+ componentNode.children.push({
53
+ name: 'Docs',
54
+ type: 'component',
55
+ path: itemPath,
56
+ children: [],
57
+ doc,
58
+ });
59
+ // Add example children
60
+ for (const ex of examples) {
61
+ componentNode.children.push({
62
+ name: ex,
63
+ type: 'component',
64
+ path: [...itemPath, ex],
65
+ children: [],
66
+ doc,
67
+ });
68
+ }
69
+ parent.push(componentNode);
70
+ }
71
+ else {
72
+ parent.push({
73
+ name: itemName,
74
+ type: kind,
75
+ path: itemPath,
76
+ children: [],
77
+ doc,
78
+ });
79
+ }
80
+ }
81
+ // Apply ordering
82
+ if (sidebar?.order) {
83
+ applyOrder(root, 'root', sidebar.order);
84
+ }
85
+ return root;
86
+ }
87
+ /** Apply sort order to children at each level */
88
+ function applyOrder(nodes, folderKey, orderConfig) {
89
+ const order = orderConfig[folderKey];
90
+ if (order) {
91
+ sortByOrder(nodes, order);
92
+ }
93
+ else {
94
+ // Default: alphabetical
95
+ nodes.sort((a, b) => a.name.localeCompare(b.name));
96
+ }
97
+ // Recurse into folders/groups
98
+ for (const node of nodes) {
99
+ if (node.children.length > 0 && (node.type === 'folder' || node.type === 'group')) {
100
+ const childKey = folderKey === 'root' ? node.name : `${folderKey}/${node.name}`;
101
+ applyOrder(node.children, childKey, orderConfig);
102
+ }
103
+ }
104
+ }
105
+ /** Sort nodes by explicit order, with * as wildcard for the rest */
106
+ function sortByOrder(nodes, order) {
107
+ const wildcardIndex = order.indexOf('*');
108
+ const before = wildcardIndex >= 0 ? order.slice(0, wildcardIndex) : order;
109
+ const after = wildcardIndex >= 0 ? order.slice(wildcardIndex + 1) : [];
110
+ const named = new Map();
111
+ const rest = [];
112
+ for (const node of nodes) {
113
+ if (before.includes(node.name) || after.includes(node.name)) {
114
+ named.set(node.name, node);
115
+ }
116
+ else {
117
+ rest.push(node);
118
+ }
119
+ }
120
+ // Rest sorted alphabetically
121
+ rest.sort((a, b) => a.name.localeCompare(b.name));
122
+ nodes.length = 0;
123
+ for (const name of before) {
124
+ const node = named.get(name);
125
+ if (node)
126
+ nodes.push(node);
127
+ }
128
+ nodes.push(...rest);
129
+ for (const name of after) {
130
+ const node = named.get(name);
131
+ if (node)
132
+ nodes.push(node);
133
+ }
134
+ }
135
+ /** Check if a path matches a tree node (for active state) */
136
+ export function pathMatchesNode(currentPath, node) {
137
+ if (node.path.length !== currentPath.length)
138
+ return false;
139
+ return node.path.every((seg, i) => seg === currentPath[i]);
140
+ }
141
+ /** Find the doc entry for a given path */
142
+ export function findDocByPath(docs, path) {
143
+ if (path.length === 0)
144
+ return null;
145
+ for (const doc of docs) {
146
+ const title = doc.meta.title ?? '';
147
+ const segments = title.split('/').map((s) => s.trim()).filter(Boolean);
148
+ // Exact match → component docs view
149
+ if (segments.length === path.length && segments.every((s, i) => s === path[i])) {
150
+ return { doc };
151
+ }
152
+ // One extra segment → example
153
+ if (segments.length === path.length - 1 && segments.every((s, i) => s === path[i])) {
154
+ const snippetName = path[path.length - 1];
155
+ const hasSnippet = doc.snippets?.some((s) => s.name === snippetName);
156
+ if (hasSnippet) {
157
+ return { doc, snippetName };
158
+ }
159
+ }
160
+ }
161
+ return null;
162
+ }
@@ -0,0 +1 @@
1
+ export declare function buildCommand(): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import { resolve } from 'node:path';
2
+ import { build } from 'vite';
3
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
4
+ import { loadConfig } from '../config.js';
5
+ import { sdocsPlugin } from '../vite.js';
6
+ import { generateBuildFiles, cleanBuildFiles } from '../app-gen.js';
7
+ export async function buildCommand() {
8
+ const cwd = process.cwd();
9
+ const config = await loadConfig(cwd);
10
+ console.log('[sdocs] Building static site...');
11
+ // Generate .sdocs/ with entry + preview HTML files
12
+ const { sdocsDir, inputs } = await generateBuildFiles(config, cwd);
13
+ const inputCount = Object.keys(inputs).length;
14
+ console.log(`[sdocs] Generated ${inputCount} page(s) (1 main + ${inputCount - 1} previews)`);
15
+ // Resolve include patterns to absolute paths
16
+ const absoluteIncludes = config.include.map((p) => resolve(cwd, p));
17
+ try {
18
+ await build({
19
+ configFile: false,
20
+ root: sdocsDir,
21
+ plugins: [
22
+ svelte(),
23
+ sdocsPlugin({ ...config, include: absoluteIncludes, _buildMode: true }),
24
+ ],
25
+ build: {
26
+ outDir: resolve(cwd, 'dist'),
27
+ emptyOutDir: true,
28
+ rollupOptions: {
29
+ input: inputs,
30
+ },
31
+ },
32
+ });
33
+ console.log(`[sdocs] Build complete → dist/`);
34
+ }
35
+ finally {
36
+ await cleanBuildFiles(cwd);
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ export declare function devCommand(): Promise<void>;
@@ -0,0 +1,40 @@
1
+ import { resolve } from 'node:path';
2
+ import { createServer } from 'vite';
3
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
4
+ import { loadConfig } from '../config.js';
5
+ import { sdocsPlugin } from '../vite.js';
6
+ import { generateDevFiles, cleanBuildFiles } from '../app-gen.js';
7
+ export async function devCommand() {
8
+ const cwd = process.cwd();
9
+ const config = await loadConfig(cwd);
10
+ console.log('[sdocs] Starting dev server...');
11
+ // Generate .sdocs/ temp directory with entry files
12
+ const sdocsDir = await generateDevFiles(config, cwd);
13
+ // Resolve include patterns to absolute paths (relative to cwd, not .sdocs/)
14
+ const absoluteIncludes = config.include.map((p) => resolve(cwd, p));
15
+ const server = await createServer({
16
+ configFile: false,
17
+ root: sdocsDir,
18
+ plugins: [
19
+ svelte(),
20
+ sdocsPlugin({ ...config, include: absoluteIncludes }),
21
+ ],
22
+ server: {
23
+ port: config.port,
24
+ open: config.open,
25
+ fs: {
26
+ allow: [cwd],
27
+ },
28
+ },
29
+ });
30
+ await server.listen();
31
+ server.printUrls();
32
+ // Cleanup on exit
33
+ const cleanup = async () => {
34
+ await server.close();
35
+ await cleanBuildFiles(cwd);
36
+ process.exit(0);
37
+ };
38
+ process.on('SIGINT', cleanup);
39
+ process.on('SIGTERM', cleanup);
40
+ }
@@ -0,0 +1 @@
1
+ export declare function initCommand(): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { findConfigFile } from '../config.js';
5
+ const DEFAULT_CONFIG = `/** @type {import('sdocs').SdocsConfig} */
6
+ export default {
7
+ // Glob pattern(s) to find sdoc files
8
+ // include: ['./src/**/*.sdoc', './src/**/*.sdocx'],
9
+
10
+ // Dev server port (default: 5174)
11
+ // port: 5174,
12
+
13
+ // Open browser on start (default: false)
14
+ // open: false,
15
+
16
+ // CSS loaded in preview iframes
17
+ // css: './src/styles/global.css',
18
+ // Or named stylesheets:
19
+ // css: { light: './src/styles/light.css', dark: './src/styles/dark.css' },
20
+
21
+ // Sidebar logo text (default: 'sdocs')
22
+ // logo: 'sdocs',
23
+
24
+ // Sidebar configuration
25
+ // sidebar: {
26
+ // order: { root: ['Components', '*', 'Documentation'] },
27
+ // open: ['Components'],
28
+ // },
29
+ };
30
+ `;
31
+ export async function initCommand() {
32
+ const cwd = process.cwd();
33
+ const existing = findConfigFile(cwd);
34
+ if (existing) {
35
+ console.log(`[sdocs] Config already exists: ${existing}`);
36
+ return;
37
+ }
38
+ const configPath = resolve(cwd, 'sdocs.config.js');
39
+ await writeFile(configPath, DEFAULT_CONFIG);
40
+ console.log('[sdocs] Created sdocs.config.js');
41
+ }
@@ -0,0 +1 @@
1
+ export declare function previewCommand(): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { resolve } from 'node:path';
2
+ import { existsSync } from 'node:fs';
3
+ import { preview } from 'vite';
4
+ import { loadConfig } from '../config.js';
5
+ export async function previewCommand() {
6
+ const cwd = process.cwd();
7
+ const config = await loadConfig(cwd);
8
+ const distDir = resolve(cwd, 'dist');
9
+ if (!existsSync(distDir)) {
10
+ console.error('[sdocs] No dist/ folder found. Run `sdocs build` first.');
11
+ process.exit(1);
12
+ }
13
+ console.log('[sdocs] Serving built site...');
14
+ const server = await preview({
15
+ configFile: false,
16
+ build: {
17
+ outDir: distDir,
18
+ },
19
+ preview: {
20
+ port: config.port,
21
+ open: config.open,
22
+ },
23
+ });
24
+ server.printUrls();
25
+ }
@@ -0,0 +1,7 @@
1
+ import type { SdocsConfig, ResolvedSdocsConfig } from './types.js';
2
+ /** Find the config file path in the given directory */
3
+ export declare function findConfigFile(root: string): string | null;
4
+ /** Load and resolve the sdocs config with defaults */
5
+ export declare function loadConfig(root: string): Promise<ResolvedSdocsConfig>;
6
+ /** Merge user config with defaults */
7
+ export declare function resolveConfig(userConfig: SdocsConfig): ResolvedSdocsConfig;
package/dist/config.js ADDED
@@ -0,0 +1,57 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ const CONFIG_NAMES = ['sdocs.config.ts', 'sdocs.config.mjs', 'sdocs.config.js'];
5
+ const DEFAULTS = {
6
+ include: ['./src/**/*.sdoc', './src/**/*.sdocx'],
7
+ port: 5174,
8
+ open: false,
9
+ css: null,
10
+ logo: 'sdocs',
11
+ sidebar: {
12
+ order: {},
13
+ open: [],
14
+ },
15
+ };
16
+ /** Find the config file path in the given directory */
17
+ export function findConfigFile(root) {
18
+ for (const name of CONFIG_NAMES) {
19
+ const fullPath = resolve(root, name);
20
+ if (existsSync(fullPath))
21
+ return fullPath;
22
+ }
23
+ return null;
24
+ }
25
+ /** Load and resolve the sdocs config with defaults */
26
+ export async function loadConfig(root) {
27
+ const configPath = findConfigFile(root);
28
+ if (!configPath)
29
+ return { ...DEFAULTS };
30
+ const userConfig = await importConfig(configPath);
31
+ return resolveConfig(userConfig);
32
+ }
33
+ /** Import a config file (supports .js, .mjs, .ts via Vite) */
34
+ async function importConfig(configPath) {
35
+ // Use dynamic import with file:// URL for ESM compatibility
36
+ const mod = await import(pathToFileURL(configPath).href);
37
+ return mod.default ?? mod;
38
+ }
39
+ /** Merge user config with defaults */
40
+ export function resolveConfig(userConfig) {
41
+ const include = userConfig.include
42
+ ? Array.isArray(userConfig.include)
43
+ ? userConfig.include
44
+ : [userConfig.include]
45
+ : DEFAULTS.include;
46
+ return {
47
+ include,
48
+ port: userConfig.port ?? DEFAULTS.port,
49
+ open: userConfig.open ?? DEFAULTS.open,
50
+ css: userConfig.css ?? DEFAULTS.css,
51
+ logo: userConfig.logo ?? DEFAULTS.logo,
52
+ sidebar: {
53
+ order: userConfig.sidebar?.order ?? DEFAULTS.sidebar.order,
54
+ open: userConfig.sidebar?.open ?? DEFAULTS.sidebar.open,
55
+ },
56
+ };
57
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { default as Sdocs } from './Sdocs.svelte';
2
- export type { ControlType, ArgType, ArgTypes, CssPropType, CssProps, DocMeta, Example, DocFile, SdocsProps } from './types.js';
1
+ export { sdocsPlugin } from './vite.js';
2
+ export type { SdocsConfig, ResolvedSdocsConfig, SdocMeta, DocEntry, ParsedProp, ParsedMethod, ParsedState, ParsedCssProp, ComponentData, ExtractedSnippet, } from './types.js';
package/dist/index.js CHANGED
@@ -1,4 +1 @@
1
- // Main component
2
- export { default as Sdocs } from './Sdocs.svelte';
3
- // Note: Vite plugin is exported separately from 'sdocs/vite'
4
- // to avoid bundling Node.js code into client builds
1
+ export { sdocsPlugin } from './vite.js';
@@ -0,0 +1,6 @@
1
+ /** Discover all .sdoc/.sdocx files matching the include patterns */
2
+ export declare function discoverDocFiles(include: string[], root: string): Promise<string[]>;
3
+ /** Determine the sdoc kind from the file path */
4
+ export declare function getSdocKind(filePath: string): 'component' | 'page' | 'layout';
5
+ /** Get the absolute path for a relative import */
6
+ export declare function resolveImportPath(importPath: string, fromFile: string): string;
@@ -0,0 +1,24 @@
1
+ import { glob } from 'tinyglobby';
2
+ import { resolve } from 'node:path';
3
+ /** Discover all .sdoc/.sdocx files matching the include patterns */
4
+ export async function discoverDocFiles(include, root) {
5
+ const files = await glob(include, {
6
+ cwd: root,
7
+ absolute: true,
8
+ });
9
+ return files.sort();
10
+ }
11
+ /** Determine the sdoc kind from the file path */
12
+ export function getSdocKind(filePath) {
13
+ const name = filePath.split('/').pop() ?? '';
14
+ if (name.includes('.page.'))
15
+ return 'page';
16
+ if (name.includes('.layout.'))
17
+ return 'layout';
18
+ return 'component';
19
+ }
20
+ /** Get the absolute path for a relative import */
21
+ export function resolveImportPath(importPath, fromFile) {
22
+ const dir = fromFile.substring(0, fromFile.lastIndexOf('/'));
23
+ return resolve(dir, importPath);
24
+ }
@@ -0,0 +1,4 @@
1
+ /** Highlight source code and return HTML */
2
+ export declare function highlight(code: string, lang?: string): Promise<string>;
3
+ /** Dispose the highlighter (for cleanup) */
4
+ export declare function disposeHighlighter(): Promise<void>;
@@ -0,0 +1,31 @@
1
+ import { createHighlighter } from 'shiki';
2
+ let highlighterPromise = null;
3
+ /** Get or create the shared Shiki highlighter instance */
4
+ async function getHighlighter() {
5
+ if (!highlighterPromise) {
6
+ highlighterPromise = createHighlighter({
7
+ themes: ['github-light', 'github-dark'],
8
+ langs: ['svelte', 'typescript', 'javascript', 'css', 'html'],
9
+ });
10
+ }
11
+ return highlighterPromise;
12
+ }
13
+ /** Highlight source code and return HTML */
14
+ export async function highlight(code, lang = 'svelte') {
15
+ const highlighter = await getHighlighter();
16
+ return highlighter.codeToHtml(code, {
17
+ lang,
18
+ themes: {
19
+ light: 'github-light',
20
+ dark: 'github-dark',
21
+ },
22
+ });
23
+ }
24
+ /** Dispose the highlighter (for cleanup) */
25
+ export async function disposeHighlighter() {
26
+ if (highlighterPromise) {
27
+ const highlighter = await highlighterPromise;
28
+ highlighter.dispose();
29
+ highlighterPromise = null;
30
+ }
31
+ }
@@ -0,0 +1,11 @@
1
+ import type { SdocMeta } from '../types.js';
2
+ interface MetaParseResult {
3
+ meta: SdocMeta;
4
+ componentPath: string | null;
5
+ imports: string[];
6
+ }
7
+ /** Extract meta and imports from a .sdoc file */
8
+ export declare function parseDocFile(filePath: string): Promise<MetaParseResult>;
9
+ /** Parse meta from .sdoc source */
10
+ export declare function parseDocSource(source: string, filePath: string): MetaParseResult;
11
+ export {};