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.
- package/bin/sdocs.js +1 -1
- package/dist/app-gen.d.ts +10 -0
- package/dist/app-gen.js +147 -0
- package/dist/cli.js +71 -0
- package/dist/client/App.svelte +151 -0
- package/dist/client/App.svelte.d.ts +14 -0
- package/dist/client/CollapsiblePanel.svelte +63 -0
- package/dist/client/CollapsiblePanel.svelte.d.ts +9 -0
- package/dist/client/ComponentView.svelte +321 -0
- package/dist/client/ComponentView.svelte.d.ts +10 -0
- package/dist/client/ControlsPanel.svelte +191 -0
- package/dist/client/ControlsPanel.svelte.d.ts +13 -0
- package/dist/client/DataTable.svelte +78 -0
- package/dist/client/DataTable.svelte.d.ts +11 -0
- package/dist/client/HomePage.svelte +92 -0
- package/dist/client/HomePage.svelte.d.ts +8 -0
- package/dist/client/LayoutView.svelte +27 -0
- package/dist/client/LayoutView.svelte.d.ts +8 -0
- package/dist/client/PageView.svelte +130 -0
- package/dist/client/PageView.svelte.d.ts +8 -0
- package/dist/client/PreviewFrame.svelte +100 -0
- package/dist/client/PreviewFrame.svelte.d.ts +10 -0
- package/dist/client/Sidebar.svelte +329 -0
- package/dist/client/Sidebar.svelte.d.ts +16 -0
- package/dist/client/controls/CheckboxControl.svelte +37 -0
- package/dist/client/controls/CheckboxControl.svelte.d.ts +8 -0
- package/dist/client/controls/ColorControl.svelte +47 -0
- package/dist/client/controls/ColorControl.svelte.d.ts +8 -0
- package/dist/client/controls/DimensionControl.svelte +56 -0
- package/dist/client/controls/DimensionControl.svelte.d.ts +8 -0
- package/dist/client/controls/NumberControl.svelte +44 -0
- package/dist/client/controls/NumberControl.svelte.d.ts +8 -0
- package/dist/client/controls/SelectControl.svelte +48 -0
- package/dist/client/controls/SelectControl.svelte.d.ts +9 -0
- package/dist/client/controls/TextControl.svelte +43 -0
- package/dist/client/controls/TextControl.svelte.d.ts +8 -0
- package/dist/client/router.svelte.d.ts +11 -0
- package/dist/client/router.svelte.js +45 -0
- package/dist/client/theme.css +34 -0
- package/dist/client/tree-builder.d.ts +30 -0
- package/dist/client/tree-builder.js +162 -0
- package/dist/commands/build.d.ts +1 -0
- package/dist/commands/build.js +38 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +40 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +41 -0
- package/dist/commands/preview.d.ts +1 -0
- package/dist/commands/preview.js +25 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +57 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -4
- package/dist/server/discovery.d.ts +6 -0
- package/dist/server/discovery.js +24 -0
- package/dist/server/highlighter.d.ts +4 -0
- package/dist/server/highlighter.js +31 -0
- package/dist/server/meta-parser.d.ts +11 -0
- package/dist/server/meta-parser.js +107 -0
- package/dist/server/prop-parser.d.ts +5 -0
- package/dist/server/prop-parser.js +275 -0
- package/dist/server/sdocx-parser.d.ts +11 -0
- package/dist/server/sdocx-parser.js +197 -0
- package/dist/server/snippet-compiler.d.ts +27 -0
- package/dist/server/snippet-compiler.js +145 -0
- package/dist/server/snippet-extractor.d.ts +11 -0
- package/dist/server/snippet-extractor.js +37 -0
- package/dist/server/toc-extractor.d.ts +5 -0
- package/dist/server/toc-extractor.js +37 -0
- package/dist/types.d.ts +100 -148
- package/dist/vite.d.ts +5 -2
- package/dist/vite.js +266 -2
- package/package.json +50 -74
- package/README.md +0 -43
- package/dist/Sdocs.svelte +0 -1210
- package/dist/Sdocs.svelte.d.ts +0 -5
- package/dist/cli/app-plugin.d.ts +0 -7
- package/dist/cli/app-plugin.js +0 -69
- package/dist/cli/config.d.ts +0 -12
- package/dist/cli/config.js +0 -34
- package/dist/cli/index.js +0 -72
- package/dist/cli/server.d.ts +0 -2
- package/dist/cli/server.js +0 -63
- package/dist/docgen.d.ts +0 -47
- package/dist/docgen.js +0 -463
- package/dist/internal/ComponentPreview.svelte +0 -58
- package/dist/internal/ComponentPreview.svelte.d.ts +0 -17
- package/dist/internal/CssPropsTable.svelte +0 -239
- package/dist/internal/CssPropsTable.svelte.d.ts +0 -11
- package/dist/internal/Home.svelte +0 -92
- package/dist/internal/Home.svelte.d.ts +0 -9
- package/dist/internal/MethodsTable.svelte +0 -72
- package/dist/internal/MethodsTable.svelte.d.ts +0 -7
- package/dist/internal/PropsTable.svelte +0 -342
- package/dist/internal/PropsTable.svelte.d.ts +0 -12
- package/dist/internal/Showcase.svelte +0 -130
- package/dist/internal/Showcase.svelte.d.ts +0 -21
- package/dist/ui/Badge/Badge.docs.svelte +0 -46
- package/dist/ui/Badge/Badge.docs.svelte.d.ts +0 -26
- package/dist/ui/Badge/Badge.svelte +0 -59
- package/dist/ui/Badge/Badge.svelte.d.ts +0 -17
- package/dist/ui/Badge/index.d.ts +0 -1
- package/dist/ui/Badge/index.js +0 -1
- package/dist/ui/Checkbox/Checkbox.docs.svelte +0 -51
- package/dist/ui/Checkbox/Checkbox.docs.svelte.d.ts +0 -27
- package/dist/ui/Checkbox/Checkbox.svelte +0 -169
- package/dist/ui/Checkbox/Checkbox.svelte.d.ts +0 -18
- package/dist/ui/Checkbox/index.d.ts +0 -1
- package/dist/ui/Checkbox/index.js +0 -1
- package/dist/ui/CodeBlock/CodeBlock.docs.svelte +0 -28
- package/dist/ui/CodeBlock/CodeBlock.docs.svelte.d.ts +0 -24
- package/dist/ui/CodeBlock/CodeBlock.svelte +0 -101
- package/dist/ui/CodeBlock/CodeBlock.svelte.d.ts +0 -7
- package/dist/ui/CodeBlock/index.d.ts +0 -1
- package/dist/ui/CodeBlock/index.js +0 -1
- package/dist/ui/Frame/Frame.docs.svelte +0 -140
- package/dist/ui/Frame/Frame.docs.svelte.d.ts +0 -26
- package/dist/ui/Frame/Frame.svelte +0 -88
- package/dist/ui/Frame/Frame.svelte.d.ts +0 -15
- package/dist/ui/Frame/index.d.ts +0 -1
- package/dist/ui/Frame/index.js +0 -1
- package/dist/ui/InputNumber/InputNumber.docs.svelte +0 -50
- package/dist/ui/InputNumber/InputNumber.docs.svelte.d.ts +0 -26
- package/dist/ui/InputNumber/InputNumber.svelte +0 -275
- package/dist/ui/InputNumber/InputNumber.svelte.d.ts +0 -26
- package/dist/ui/InputNumber/index.d.ts +0 -1
- package/dist/ui/InputNumber/index.js +0 -1
- package/dist/ui/InputText/InputText.docs.svelte +0 -43
- package/dist/ui/InputText/InputText.docs.svelte.d.ts +0 -26
- package/dist/ui/InputText/InputText.svelte +0 -116
- package/dist/ui/InputText/InputText.svelte.d.ts +0 -22
- package/dist/ui/InputText/index.d.ts +0 -1
- package/dist/ui/InputText/index.js +0 -1
- package/dist/ui/Panel/CollapsiblePanel.docs.svelte +0 -45
- package/dist/ui/Panel/CollapsiblePanel.docs.svelte.d.ts +0 -25
- package/dist/ui/Panel/CollapsiblePanel.svelte +0 -93
- package/dist/ui/Panel/CollapsiblePanel.svelte.d.ts +0 -14
- package/dist/ui/Panel/index.d.ts +0 -1
- package/dist/ui/Panel/index.js +0 -1
- package/dist/ui/Placeholder/Placeholder.docs.svelte +0 -49
- package/dist/ui/Placeholder/Placeholder.docs.svelte.d.ts +0 -26
- package/dist/ui/Placeholder/Placeholder.svelte +0 -99
- package/dist/ui/Placeholder/Placeholder.svelte.d.ts +0 -21
- package/dist/ui/Placeholder/index.d.ts +0 -1
- package/dist/ui/Placeholder/index.js +0 -1
- package/dist/ui/Radio/Radio.docs.svelte +0 -67
- package/dist/ui/Radio/Radio.docs.svelte.d.ts +0 -27
- package/dist/ui/Radio/Radio.svelte +0 -165
- package/dist/ui/Radio/Radio.svelte.d.ts +0 -22
- package/dist/ui/Radio/RadioGroup.docs.svelte +0 -70
- package/dist/ui/Radio/RadioGroup.docs.svelte.d.ts +0 -27
- package/dist/ui/Radio/RadioGroup.svelte +0 -98
- package/dist/ui/Radio/RadioGroup.svelte.d.ts +0 -27
- package/dist/ui/Radio/index.d.ts +0 -2
- package/dist/ui/Radio/index.js +0 -2
- package/dist/ui/SegmentControl/SegmentControl.docs.svelte +0 -54
- package/dist/ui/SegmentControl/SegmentControl.docs.svelte.d.ts +0 -25
- package/dist/ui/SegmentControl/SegmentControl.svelte +0 -120
- package/dist/ui/SegmentControl/SegmentControl.svelte.d.ts +0 -18
- package/dist/ui/SegmentControl/index.d.ts +0 -1
- package/dist/ui/SegmentControl/index.js +0 -1
- package/dist/ui/Stack/Stack.docs.svelte +0 -63
- package/dist/ui/Stack/Stack.docs.svelte.d.ts +0 -26
- package/dist/ui/Stack/Stack.svelte +0 -45
- package/dist/ui/Stack/Stack.svelte.d.ts +0 -19
- package/dist/ui/Stack/index.d.ts +0 -1
- package/dist/ui/Stack/index.js +0 -1
- package/dist/ui/Table/Body.svelte +0 -17
- package/dist/ui/Table/Body.svelte.d.ts +0 -11
- package/dist/ui/Table/Caption.svelte +0 -17
- package/dist/ui/Table/Caption.svelte.d.ts +0 -11
- package/dist/ui/Table/Cell.svelte +0 -24
- package/dist/ui/Table/Cell.svelte.d.ts +0 -15
- package/dist/ui/Table/Foot.svelte +0 -17
- package/dist/ui/Table/Foot.svelte.d.ts +0 -11
- package/dist/ui/Table/Head.svelte +0 -17
- package/dist/ui/Table/Head.svelte.d.ts +0 -11
- package/dist/ui/Table/Header.svelte +0 -27
- package/dist/ui/Table/Header.svelte.d.ts +0 -17
- package/dist/ui/Table/Row.svelte +0 -19
- package/dist/ui/Table/Row.svelte.d.ts +0 -13
- package/dist/ui/Table/Table.docs.svelte +0 -197
- package/dist/ui/Table/Table.docs.svelte.d.ts +0 -28
- package/dist/ui/Table/Table.svelte +0 -140
- package/dist/ui/Table/Table.svelte.d.ts +0 -27
- package/dist/ui/Table/index.js +0 -10
- package/dist/ui/css/colors.css +0 -377
- package/dist/ui/css/global.css +0 -10
- package/dist/ui/index.d.ts +0 -12
- package/dist/ui/index.js +0 -12
- package/dist/virtual-sdocs.d.ts +0 -20
- package/dist/vite-plugin.d.ts +0 -18
- package/dist/vite-plugin.js +0 -206
- /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
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -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 {
|
|
2
|
-
export type {
|
|
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
|
@@ -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,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 {};
|