sourcey 2.1.0 → 3.0.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 +128 -210
- package/dist/cli.js +18 -57
- package/dist/cli.js.map +1 -1
- package/dist/client/scroll-tracker.js +125 -40
- package/dist/client/search.js +27 -3
- package/dist/client/tabs.js +164 -24
- package/dist/components/App.d.ts +3 -2
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +3 -3
- package/dist/components/App.js.map +1 -1
- package/dist/components/layout/Head.d.ts.map +1 -1
- package/dist/components/layout/Head.js +30 -9
- package/dist/components/layout/Head.js.map +1 -1
- package/dist/components/layout/Header.d.ts +2 -7
- package/dist/components/layout/Header.d.ts.map +1 -1
- package/dist/components/layout/Header.js +12 -15
- package/dist/components/layout/Header.js.map +1 -1
- package/dist/components/layout/Page.d.ts.map +1 -1
- package/dist/components/layout/Page.js +54 -10
- package/dist/components/layout/Page.js.map +1 -1
- package/dist/components/layout/Sidebar.js +1 -1
- package/dist/components/layout/Sidebar.js.map +1 -1
- package/dist/components/layout/TableOfContents.d.ts.map +1 -1
- package/dist/components/layout/TableOfContents.js +1 -1
- package/dist/components/layout/TableOfContents.js.map +1 -1
- package/dist/components/openapi/CodeSamples.d.ts +4 -2
- package/dist/components/openapi/CodeSamples.d.ts.map +1 -1
- package/dist/components/openapi/CodeSamples.js +9 -5
- package/dist/components/openapi/CodeSamples.js.map +1 -1
- package/dist/components/openapi/Definition.js +1 -1
- package/dist/components/openapi/Definition.js.map +1 -1
- package/dist/components/openapi/EndpointBar.d.ts.map +1 -1
- package/dist/components/openapi/EndpointBar.js +3 -3
- package/dist/components/openapi/EndpointBar.js.map +1 -1
- package/dist/components/openapi/Introduction.d.ts.map +1 -1
- package/dist/components/openapi/Introduction.js +1 -1
- package/dist/components/openapi/Introduction.js.map +1 -1
- package/dist/components/openapi/Operation.d.ts.map +1 -1
- package/dist/components/openapi/Operation.js +5 -1
- package/dist/components/openapi/Operation.js.map +1 -1
- package/dist/components/openapi/Responses.d.ts +2 -1
- package/dist/components/openapi/Responses.d.ts.map +1 -1
- package/dist/components/openapi/Responses.js +17 -6
- package/dist/components/openapi/Responses.js.map +1 -1
- package/dist/components/openapi/Security.d.ts.map +1 -1
- package/dist/components/openapi/Security.js +3 -2
- package/dist/components/openapi/Security.js.map +1 -1
- package/dist/components/openapi/Tags.d.ts.map +1 -1
- package/dist/components/openapi/Tags.js +1 -1
- package/dist/components/openapi/Tags.js.map +1 -1
- package/dist/components/schema/ExampleView.d.ts +1 -1
- package/dist/components/schema/ExampleView.d.ts.map +1 -1
- package/dist/components/schema/ExampleView.js +3 -2
- package/dist/components/schema/ExampleView.js.map +1 -1
- package/dist/components/ui/CopyButton.d.ts +6 -0
- package/dist/components/ui/CopyButton.d.ts.map +1 -0
- package/dist/components/ui/CopyButton.js +10 -0
- package/dist/components/ui/CopyButton.js.map +1 -0
- package/dist/components/ui/Markdown.js +1 -1
- package/dist/components/ui/Markdown.js.map +1 -1
- package/dist/components/ui/SocialIcon.d.ts +5 -0
- package/dist/components/ui/SocialIcon.d.ts.map +1 -0
- package/dist/components/ui/SocialIcon.js +19 -0
- package/dist/components/ui/SocialIcon.js.map +1 -0
- package/dist/config.d.ts +133 -37
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +227 -73
- package/dist/config.js.map +1 -1
- package/dist/core/doxygen-loader.d.ts +9 -0
- package/dist/core/doxygen-loader.d.ts.map +1 -0
- package/dist/core/doxygen-loader.js +68 -0
- package/dist/core/doxygen-loader.js.map +1 -0
- package/dist/core/markdown-loader.d.ts +2 -5
- package/dist/core/markdown-loader.d.ts.map +1 -1
- package/dist/core/markdown-loader.js +218 -27
- package/dist/core/markdown-loader.js.map +1 -1
- package/dist/core/navigation.d.ts +2 -2
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/navigation.js +9 -10
- package/dist/core/navigation.js.map +1 -1
- package/dist/core/search-indexer.d.ts +1 -1
- package/dist/core/search-indexer.d.ts.map +1 -1
- package/dist/core/search-indexer.js +6 -5
- package/dist/core/search-indexer.js.map +1 -1
- package/dist/dev-server.d.ts +0 -12
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +101 -79
- package/dist/dev-server.js.map +1 -1
- package/dist/index.d.ts +2 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +82 -70
- package/dist/index.js.map +1 -1
- package/dist/renderer/context.d.ts +29 -2
- package/dist/renderer/context.d.ts.map +1 -1
- package/dist/renderer/context.js +1 -1
- package/dist/renderer/context.js.map +1 -1
- package/dist/renderer/html-builder.d.ts +3 -16
- package/dist/renderer/html-builder.d.ts.map +1 -1
- package/dist/renderer/html-builder.js +6 -20
- package/dist/renderer/html-builder.js.map +1 -1
- package/dist/renderer/static-renderer.d.ts +2 -2
- package/dist/renderer/static-renderer.d.ts.map +1 -1
- package/dist/renderer/static-renderer.js +2 -2
- package/dist/renderer/static-renderer.js.map +1 -1
- package/dist/themes/default/main.css +13 -1
- package/dist/themes/default/sourcey.css +629 -41
- package/dist/utils/code-samples.d.ts +8 -3
- package/dist/utils/code-samples.d.ts.map +1 -1
- package/dist/utils/code-samples.js +188 -51
- package/dist/utils/code-samples.js.map +1 -1
- package/dist/utils/copy-svg.d.ts +9 -0
- package/dist/utils/copy-svg.d.ts.map +1 -0
- package/dist/utils/copy-svg.js +9 -0
- package/dist/utils/copy-svg.js.map +1 -0
- package/dist/utils/highlighter.d.ts.map +1 -1
- package/dist/utils/highlighter.js +18 -7
- package/dist/utils/highlighter.js.map +1 -1
- package/dist/utils/icons.d.ts +14 -0
- package/dist/utils/icons.d.ts.map +1 -0
- package/dist/utils/icons.js +59 -0
- package/dist/utils/icons.js.map +1 -0
- package/dist/utils/lang-icons.d.ts +17 -0
- package/dist/utils/lang-icons.d.ts.map +1 -0
- package/dist/utils/lang-icons.js +87 -0
- package/dist/utils/lang-icons.js.map +1 -0
- package/dist/utils/markdown.d.ts +17 -1
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js +59 -2
- package/dist/utils/markdown.js.map +1 -1
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +4 -7
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,256 +1,174 @@
|
|
|
1
1
|
# Sourcey
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Your API docs shouldn't depend on someone else's SaaS.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[](https://www.npmjs.com/package/sourcey)
|
|
7
|
-
[](https://nodejs.org)
|
|
8
|
-
[](https://github.com/sourcey/sourcey/blob/master/LICENSE)
|
|
9
|
-
|
|
10
|
-
Sourcey generates beautiful static HTML documentation from [OpenAPI](https://openapis.org) / [Swagger](http://swagger.io) specifications.
|
|
11
|
-
|
|
12
|
-
Supports **OpenAPI 3.0**, **OpenAPI 3.1**, and **Swagger 2.0** (auto-converted).
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
- **OpenAPI 3.x + Swagger 2.0** — full support, with automatic Swagger-to-OpenAPI conversion
|
|
19
|
-
- **Beautiful layout** — sidebar navigation, docs, and code examples
|
|
20
|
-
- **Dark mode** — toggle with a button, respects system preference, persists with localStorage
|
|
21
|
-
- **Client-side search** — `/` or `Ctrl+K` to search endpoints and models instantly
|
|
22
|
-
- **Auto-generated code samples** — cURL, JavaScript (fetch), and Python (requests) for every operation
|
|
23
|
-
- **Synced language tabs** — switch language in one example, all others follow
|
|
24
|
-
- **Shiki syntax highlighting** — VS Code-quality highlighting at build time
|
|
25
|
-
- **Markdown descriptions** — full markdown rendering in all description fields
|
|
26
|
-
- **Dev server with live reload** — `sourcey dev` watches your spec and reloads the browser
|
|
27
|
-
- **Theming** — override any CSS variable via `sourcey.json` — colors, fonts, spacing
|
|
28
|
-
- **Custom branding** — logo and favicon via config
|
|
29
|
-
- **Embeddable output** — generate partial HTML for embedding into your own site
|
|
30
|
-
- **Zero client-side dependencies** — no frameworks shipped to the browser
|
|
5
|
+
Sourcey is an open source documentation platform. Point it at an OpenAPI spec, add markdown guides, get a complete docs site. Static HTML you own; no dashboard, no monthly bill, no API calls to render your own documentation. Deploy anywhere.
|
|
31
6
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/sourcey)
|
|
8
|
+
[](https://github.com/sourcey/sourcey/actions)
|
|
9
|
+
[](LICENSE)
|
|
35
10
|
|
|
36
11
|
```bash
|
|
37
|
-
|
|
12
|
+
npx sourcey dev
|
|
38
13
|
```
|
|
39
14
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
sourcey build your_api.yaml -o docs/
|
|
44
|
-
```
|
|
15
|
+

|
|
45
16
|
|
|
46
|
-
|
|
17
|
+
**[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/sourcey/sourcey)
|
|
47
18
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
sourcey build <spec> [options] Build static documentation
|
|
52
|
-
sourcey dev <spec> [options] Start dev server with live reload
|
|
53
|
-
sourcey validate <spec> Validate a spec file
|
|
54
|
-
sourcey <spec> Shorthand for 'sourcey build'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Build options
|
|
58
|
-
|
|
59
|
-
| Flag | Alias | Description | Default |
|
|
60
|
-
|------|-------|-------------|---------|
|
|
61
|
-
| `--output <dir>` | `-o`, `-t` | Output directory | `dist` |
|
|
62
|
-
| `--logo <file>` | `-l` | Custom logo image | — |
|
|
63
|
-
| `--single-file` | `-1` | Embed all assets into a single HTML file | `false` |
|
|
64
|
-
| `--embed` | `-e` | Omit `<html>`/`<body>` tags for embedding | `false` |
|
|
65
|
-
| `--quiet` | `-q` | Suppress output | `false` |
|
|
66
|
-
|
|
67
|
-
### Dev server options
|
|
68
|
-
|
|
69
|
-
| Flag | Alias | Description | Default |
|
|
70
|
-
|------|-------|-------------|---------|
|
|
71
|
-
| `--port <port>` | `-p` | Port to listen on | `4400` |
|
|
72
|
-
| `--output <dir>` | `-o` | Build output directory | `.preview` |
|
|
73
|
-
| `--logo <file>` | `-l` | Custom logo image | — |
|
|
19
|
+
## Features
|
|
74
20
|
|
|
75
|
-
|
|
21
|
+
- **API reference from OpenAPI** — endpoints, parameters, request/response schemas, auto-generated code samples in 10 languages (cURL, JavaScript, TypeScript, Python, Go, Ruby, Java, PHP, Rust, C#)
|
|
22
|
+
- **Markdown guides with rich components** — steps, cards, accordions, syntax-highlighted code blocks; everything you need for prose docs alongside your API reference
|
|
23
|
+
- **TypeScript config** — `sourcey.config.ts` with `defineConfig()` autocomplete; theme, navbar, CTA buttons, footer
|
|
24
|
+
- **Theme presets** — default (sidebar + TOC), minimal (single column), api-first (Stripe-style three column); colors, fonts, layout dimensions, and custom CSS on top
|
|
25
|
+
- **Vite dev server** — SSR hot reload on every component and CSS change; spec and markdown changes trigger instant refresh
|
|
26
|
+
- **Dark mode** — semantic design tokens, light/dark logo variants, localStorage persistence
|
|
27
|
+
- **Client-side search** — instant fuzzy search across all pages and API operations
|
|
28
|
+
- **Static HTML output** — no framework runtime, no vendor lock-in. Deploy to GitHub Pages, Vercel, Netlify, S3, anywhere
|
|
29
|
+
- **Open source** — AGPL-3.0. Self-host, fork, extend. Your docs, your infrastructure
|
|
30
|
+
|
|
31
|
+
### Sourcey vs alternatives
|
|
32
|
+
|
|
33
|
+
| | Sourcey | Mintlify | GitBook | Fern | Redocly | VitePress |
|
|
34
|
+
|---|---|---|---|---|---|---|
|
|
35
|
+
| OpenAPI reference | Native | Native | No | Native | Native | Plugin |
|
|
36
|
+
| Markdown guides | Native | Native | Native | Native | Native | Native |
|
|
37
|
+
| Static output you own | Yes | No | No | No | Yes | Yes |
|
|
38
|
+
| Zero JS shipped | Yes | No | No | No | No | No (Vue SPA) |
|
|
39
|
+
| TypeScript config | Yes | JSON | GUI | YAML | YAML | TS |
|
|
40
|
+
| Hot reload dev server | Vite SSR | Cloud | Cloud | Cloud | Webpack | Vite SPA |
|
|
41
|
+
| Rich components | Yes | Yes | Limited | Yes | No | Vue |
|
|
42
|
+
| Theme presets | Yes | No | No | No | No | Yes |
|
|
43
|
+
| Self-hosted | Yes | No | No | No | Yes | Yes |
|
|
44
|
+
| Pricing | Free / AGPL | $150+/mo | Free / paid | Paid | Free / paid | Free |
|
|
45
|
+
|
|
46
|
+
## Quick start
|
|
76
47
|
|
|
77
48
|
```bash
|
|
78
|
-
#
|
|
79
|
-
sourcey build api.yaml -o
|
|
80
|
-
|
|
81
|
-
# Start dev server with live reload
|
|
82
|
-
sourcey dev api.yaml
|
|
49
|
+
# From a single OpenAPI spec
|
|
50
|
+
sourcey build api.yaml -o docs/
|
|
83
51
|
|
|
84
|
-
#
|
|
85
|
-
sourcey
|
|
52
|
+
# Multi-page site (reads sourcey.config.ts)
|
|
53
|
+
sourcey build -o docs/
|
|
86
54
|
|
|
87
|
-
#
|
|
88
|
-
sourcey
|
|
55
|
+
# Dev server with hot reload
|
|
56
|
+
sourcey dev
|
|
89
57
|
```
|
|
90
58
|
|
|
91
59
|
## Configuration
|
|
92
60
|
|
|
93
|
-
Create
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"logo": "./logo.png",
|
|
98
|
-
"favicon": "./favicon.ico",
|
|
99
|
-
"theme": {
|
|
100
|
-
"--color-primary": "99 102 241",
|
|
101
|
-
"--font-sans": "'IBM Plex Sans', sans-serif",
|
|
102
|
-
"--sidebar-width": "280px"
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Theme variables
|
|
61
|
+
Create `sourcey.config.ts` in your project root:
|
|
108
62
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
63
|
+
```typescript
|
|
64
|
+
import { defineConfig } from "sourcey";
|
|
65
|
+
|
|
66
|
+
export default defineConfig({
|
|
67
|
+
name: "My API",
|
|
68
|
+
theme: {
|
|
69
|
+
preset: "default", // "default" | "minimal" | "api-first"
|
|
70
|
+
colors: {
|
|
71
|
+
primary: "#6366F1",
|
|
72
|
+
light: "#818CF8",
|
|
73
|
+
dark: "#4F46E5",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
logo: "./logo.png",
|
|
77
|
+
navigation: {
|
|
78
|
+
tabs: [
|
|
79
|
+
{
|
|
80
|
+
tab: "Documentation",
|
|
81
|
+
groups: [
|
|
82
|
+
{
|
|
83
|
+
group: "Getting Started",
|
|
84
|
+
pages: ["introduction", "quickstart", "authentication"],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
tab: "API Reference",
|
|
90
|
+
openapi: "./openapi.yaml",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
navbar: {
|
|
95
|
+
links: [{ type: "github", href: "https://github.com/you/repo" }],
|
|
96
|
+
primary: { type: "button", label: "Dashboard", href: "https://app.example.com" },
|
|
97
|
+
},
|
|
98
|
+
footer: {
|
|
99
|
+
socials: { github: "https://github.com/you/repo" },
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
```
|
|
112
103
|
|
|
113
|
-
|
|
114
|
-
|----------|---------|-------------|
|
|
115
|
-
| `--sidebar-width` | `18rem` | Sidebar width |
|
|
116
|
-
| `--header-height` | `7rem` | Header height |
|
|
117
|
-
| `--toc-width` | `19rem` | Table of contents width |
|
|
118
|
-
| `--content-padding` | `2.5rem` | Content area padding |
|
|
119
|
-
| `--content-max-width` | `44rem` | Content max width |
|
|
104
|
+
Each tab is either an `openapi` spec or `groups` of markdown pages. Pages are referenced by slug (e.g. `"quickstart"` resolves to `quickstart.md`).
|
|
120
105
|
|
|
121
|
-
|
|
106
|
+
### Markdown components
|
|
122
107
|
|
|
123
|
-
|
|
124
|
-
|----------|---------|-------------|
|
|
125
|
-
| `--color-primary` | `99 102 241` | Primary accent (indigo) |
|
|
126
|
-
| `--color-primary-light` | `129 140 248` | Primary light variant |
|
|
127
|
-
| `--color-primary-dark` | `79 70 229` | Primary dark variant |
|
|
128
|
-
| `--color-background-light` | `255 255 255` | Page background (light) |
|
|
129
|
-
| `--color-background-dark` | `11 12 16` | Page background (dark) |
|
|
130
|
-
| `--color-gray-50` through `--color-gray-950` | — | Full gray scale |
|
|
131
|
-
| `--color-success` | `34 197 94` | Success states |
|
|
132
|
-
| `--color-overlay` | `0 0 0` | Overlay backdrop |
|
|
108
|
+
Guides support rich components in standard markdown:
|
|
133
109
|
|
|
134
|
-
|
|
110
|
+
```markdown
|
|
111
|
+
<Steps>
|
|
112
|
+
<Step title="Install">Run `npm install sourcey`</Step>
|
|
113
|
+
<Step title="Configure">Create `sourcey.config.ts`</Step>
|
|
114
|
+
<Step title="Build">Run `sourcey build`</Step>
|
|
115
|
+
</Steps>
|
|
135
116
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
| `--method-put` | `#d97706` | PUT badge |
|
|
141
|
-
| `--method-delete` | `#dc2626` | DELETE badge |
|
|
142
|
-
| `--method-patch` | `#9333ea` | PATCH badge |
|
|
117
|
+
<CardGroup cols={2}>
|
|
118
|
+
<Card title="API Reference" icon="book" href="/api">Full endpoint docs</Card>
|
|
119
|
+
<Card title="Guides" icon="map" href="/docs">Step-by-step tutorials</Card>
|
|
120
|
+
</CardGroup>
|
|
143
121
|
|
|
144
|
-
|
|
122
|
+
<AccordionGroup>
|
|
123
|
+
<Accordion title="How does auth work?">We use API keys and OAuth2.</Accordion>
|
|
124
|
+
</AccordionGroup>
|
|
125
|
+
```
|
|
145
126
|
|
|
146
|
-
|
|
147
|
-
|----------|---------|-------------|
|
|
148
|
-
| `--font-sans` | `'Inter', system-ui, sans-serif` | Body font |
|
|
149
|
-
| `--font-mono` | `'JetBrains Mono', monospace` | Code font |
|
|
127
|
+
### Theme
|
|
150
128
|
|
|
151
|
-
|
|
129
|
+
All visual configuration lives under `theme`. Colors, fonts, layout dimensions, and a preset that controls page structure:
|
|
152
130
|
|
|
153
131
|
```typescript
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
themeOverrides: {
|
|
162
|
-
'--color-primary': '225 29 72',
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
console.log(result.spec.info.title); // "My API"
|
|
167
|
-
console.log(result.spec.operations.length); // 42
|
|
132
|
+
theme: {
|
|
133
|
+
preset: "api-first",
|
|
134
|
+
colors: { primary: "#f59e0b", light: "#fbbf24", dark: "#d97706" },
|
|
135
|
+
fonts: { sans: "'Lexend', sans-serif", mono: "'Fira Code', monospace" },
|
|
136
|
+
layout: { sidebar: "16rem", content: "48rem" },
|
|
137
|
+
css: ["./brand.css"],
|
|
138
|
+
}
|
|
168
139
|
```
|
|
169
140
|
|
|
170
|
-
|
|
141
|
+
Presets control layout structure: `"default"` (sidebar + TOC), `"minimal"` (single centered column), `"api-first"` (three-column with persistent code panels). Everything else applies on top.
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
|--------|------|-------------|
|
|
174
|
-
| `specSource` | `string` | Path or URL to the spec file (required) |
|
|
175
|
-
| `outputDir` | `string` | Output directory (default: `"dist"`) |
|
|
176
|
-
| `logo` | `string` | Path to a custom logo |
|
|
177
|
-
| `favicon` | `string` | Path to a custom favicon |
|
|
178
|
-
| `singleFile` | `boolean` | Embed assets into one HTML file |
|
|
179
|
-
| `embeddable` | `boolean` | Omit `<html>`/`<body>` tags |
|
|
180
|
-
| `skipWrite` | `boolean` | Parse and normalize without writing files |
|
|
181
|
-
| `themeOverrides` | `Record<string, string>` | CSS custom property overrides |
|
|
182
|
-
|
|
183
|
-
## Keyboard Shortcuts
|
|
184
|
-
|
|
185
|
-
| Key | Action |
|
|
186
|
-
|-----|--------|
|
|
187
|
-
| `/` or `Ctrl+K` | Open search |
|
|
188
|
-
| `Escape` | Close search or sidebar |
|
|
189
|
-
| `↑` / `↓` | Navigate search results |
|
|
190
|
-
| `Enter` | Go to selected result |
|
|
143
|
+
## CLI
|
|
191
144
|
|
|
192
|
-
|
|
145
|
+
```bash
|
|
146
|
+
sourcey dev Dev server (reads sourcey.config.ts)
|
|
147
|
+
sourcey build Build site (reads sourcey.config.ts)
|
|
148
|
+
sourcey build api.yaml Quick build from a single spec
|
|
149
|
+
sourcey validate api.yaml Validate a spec file
|
|
150
|
+
```
|
|
193
151
|
|
|
194
|
-
|
|
|
195
|
-
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
152
|
+
| Command | Flag | Description |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| `build` | `--output, -o` | Output directory (default: `dist`) |
|
|
155
|
+
| `build` | `--embed, -e` | Embeddable output (no html/body wrapper) |
|
|
156
|
+
| `build` | `--quiet, -q` | Suppress output |
|
|
157
|
+
| `dev` | `--port, -p` | Dev server port (default: `4400`) |
|
|
198
158
|
|
|
199
159
|
## Development
|
|
200
160
|
|
|
201
161
|
```bash
|
|
202
162
|
git clone https://github.com/sourcey/sourcey.git
|
|
203
|
-
cd sourcey
|
|
204
|
-
npm
|
|
205
|
-
npm run build
|
|
206
|
-
npm test
|
|
207
|
-
```
|
|
163
|
+
cd sourcey && npm install
|
|
164
|
+
npm run build && npm test
|
|
208
165
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
src/
|
|
213
|
-
cli.ts CLI entry point (citty)
|
|
214
|
-
index.ts Programmatic API
|
|
215
|
-
config.ts sourcey.json loader
|
|
216
|
-
dev-server.ts Dev server with live reload
|
|
217
|
-
core/ Spec processing pipeline
|
|
218
|
-
loader.ts Load from file/URL
|
|
219
|
-
parser.ts Validate and dereference $refs
|
|
220
|
-
converter.ts Swagger 2.0 → OpenAPI 3.x
|
|
221
|
-
normalizer.ts OpenAPI → internal model
|
|
222
|
-
types.ts Internal types
|
|
223
|
-
components/ Preact components (SSG)
|
|
224
|
-
layout/ Page, Sidebar, Head
|
|
225
|
-
openapi/ Operation, Parameters, Responses, etc.
|
|
226
|
-
schema/ SchemaView, ExampleView
|
|
227
|
-
ui/ Badge, Markdown, SectionLabel
|
|
228
|
-
renderer/ HTML generation
|
|
229
|
-
static-renderer.ts Preact → HTML string
|
|
230
|
-
html-builder.ts Assemble HTML + CSS + JS
|
|
231
|
-
context.ts Render context
|
|
232
|
-
client/ Browser JavaScript (vanilla JS)
|
|
233
|
-
sidebar.js Drawer toggle, close on outside click/Escape
|
|
234
|
-
scroll-tracker.js IntersectionObserver nav highlighting
|
|
235
|
-
tabs.js Synced language tab switching
|
|
236
|
-
copy.js Clipboard copy with feedback
|
|
237
|
-
theme-toggle.js Dark/light mode toggle
|
|
238
|
-
search.js Client-side search dialog
|
|
239
|
-
themes/
|
|
240
|
-
default/ Default theme CSS
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Testing
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
npm test # Run all tests
|
|
247
|
-
npm run test:watch # Watch mode
|
|
248
|
-
npm run typecheck # TypeScript type checking
|
|
249
|
-
npm run lint # ESLint
|
|
166
|
+
# Run the demo site
|
|
167
|
+
cd demo && npx tsx ../src/cli.ts dev
|
|
250
168
|
```
|
|
251
169
|
|
|
252
170
|
## License
|
|
253
171
|
|
|
254
|
-
AGPL-3.0
|
|
172
|
+
[AGPL-3.0](LICENSE). Free to use, self-host, and modify. If you run Sourcey as a hosted service, you open-source your stack.
|
|
255
173
|
|
|
256
|
-
Commercial licensing available
|
|
174
|
+
Commercial licensing available; contact [sourcey.com](https://sourcey.com).
|
package/dist/cli.js
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { defineCommand, runMain } from "citty";
|
|
3
3
|
import { buildDocs, buildSiteDocs } from "./index.js";
|
|
4
|
-
import { loadConfig
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
5
|
const build = defineCommand({
|
|
6
6
|
meta: {
|
|
7
7
|
name: "build",
|
|
8
|
-
description: "Build documentation from
|
|
8
|
+
description: "Build documentation from sourcey.config.ts or a standalone OpenAPI spec",
|
|
9
9
|
},
|
|
10
10
|
args: {
|
|
11
11
|
spec: {
|
|
12
12
|
type: "positional",
|
|
13
|
-
description: "Path
|
|
13
|
+
description: "Path to an OpenAPI spec (quick mode; skips config)",
|
|
14
14
|
required: false,
|
|
15
15
|
},
|
|
16
16
|
output: {
|
|
17
17
|
type: "string",
|
|
18
|
-
alias: ["o"
|
|
18
|
+
alias: ["o"],
|
|
19
19
|
description: "Output directory",
|
|
20
20
|
default: "dist",
|
|
21
21
|
},
|
|
22
|
-
logo: {
|
|
23
|
-
type: "string",
|
|
24
|
-
alias: ["l"],
|
|
25
|
-
description: "Path to a custom logo file",
|
|
26
|
-
},
|
|
27
22
|
embed: {
|
|
28
23
|
type: "boolean",
|
|
29
24
|
alias: ["e"],
|
|
30
|
-
description: "
|
|
25
|
+
description: "Embeddable output (no html/body wrapper)",
|
|
31
26
|
default: false,
|
|
32
27
|
},
|
|
33
28
|
quiet: {
|
|
@@ -39,20 +34,14 @@ const build = defineCommand({
|
|
|
39
34
|
},
|
|
40
35
|
async run({ args }) {
|
|
41
36
|
const startTime = Date.now();
|
|
42
|
-
const config = await loadConfig();
|
|
43
37
|
try {
|
|
44
38
|
if (args.spec) {
|
|
45
|
-
|
|
46
|
-
if (!args.quiet) {
|
|
39
|
+
if (!args.quiet)
|
|
47
40
|
console.log(`\nSourcey — generating docs from ${args.spec}\n`);
|
|
48
|
-
}
|
|
49
41
|
const result = await buildDocs({
|
|
50
42
|
specSource: args.spec,
|
|
51
43
|
outputDir: args.output,
|
|
52
|
-
logo: args.logo || config.logo,
|
|
53
|
-
favicon: config.favicon,
|
|
54
44
|
embeddable: args.embed,
|
|
55
|
-
themeOverrides: config.theme,
|
|
56
45
|
});
|
|
57
46
|
if (!args.quiet) {
|
|
58
47
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
@@ -62,13 +51,14 @@ const build = defineCommand({
|
|
|
62
51
|
console.log(` Time: ${elapsed}s\n`);
|
|
63
52
|
}
|
|
64
53
|
}
|
|
65
|
-
else
|
|
66
|
-
|
|
67
|
-
if (!args.quiet)
|
|
54
|
+
else {
|
|
55
|
+
const config = await loadConfig();
|
|
56
|
+
if (!args.quiet)
|
|
68
57
|
console.log(`\nSourcey — building documentation site\n`);
|
|
69
|
-
}
|
|
70
58
|
const result = await buildSiteDocs({
|
|
59
|
+
config,
|
|
71
60
|
outputDir: args.output,
|
|
61
|
+
embeddable: args.embed,
|
|
72
62
|
});
|
|
73
63
|
if (!args.quiet) {
|
|
74
64
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
@@ -77,11 +67,6 @@ const build = defineCommand({
|
|
|
77
67
|
console.log(` Time: ${elapsed}s\n`);
|
|
78
68
|
}
|
|
79
69
|
}
|
|
80
|
-
else {
|
|
81
|
-
console.error("\nError: No spec file provided and no sourcey.json with navigation found.");
|
|
82
|
-
console.error("Usage: sourcey build <spec-file> or create a sourcey.json with navigation config.\n");
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
70
|
}
|
|
86
71
|
catch (error) {
|
|
87
72
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -93,54 +78,32 @@ const build = defineCommand({
|
|
|
93
78
|
const dev = defineCommand({
|
|
94
79
|
meta: {
|
|
95
80
|
name: "dev",
|
|
96
|
-
description: "Start a dev server with live reload",
|
|
81
|
+
description: "Start a dev server with live reload (reads sourcey.config.ts)",
|
|
97
82
|
},
|
|
98
83
|
args: {
|
|
99
|
-
spec: {
|
|
100
|
-
type: "positional",
|
|
101
|
-
description: "Path to the OpenAPI/Swagger spec file (optional if sourcey.json exists)",
|
|
102
|
-
required: false,
|
|
103
|
-
},
|
|
104
84
|
port: {
|
|
105
85
|
type: "string",
|
|
106
86
|
alias: ["p"],
|
|
107
87
|
description: "Port to listen on",
|
|
108
88
|
default: "4400",
|
|
109
89
|
},
|
|
110
|
-
output: {
|
|
111
|
-
type: "string",
|
|
112
|
-
alias: ["o"],
|
|
113
|
-
description: "Output directory for built files",
|
|
114
|
-
default: ".preview",
|
|
115
|
-
},
|
|
116
|
-
logo: {
|
|
117
|
-
type: "string",
|
|
118
|
-
alias: ["l"],
|
|
119
|
-
description: "Path to a custom logo file",
|
|
120
|
-
},
|
|
121
90
|
},
|
|
122
91
|
async run({ args }) {
|
|
123
|
-
const config = await loadConfig();
|
|
124
92
|
const { startDevServer } = await import("./dev-server.js");
|
|
125
93
|
await startDevServer({
|
|
126
|
-
specSource: args.spec || undefined,
|
|
127
|
-
outputDir: args.output,
|
|
128
94
|
port: parseInt(args.port, 10),
|
|
129
|
-
logo: args.logo || config.logo,
|
|
130
|
-
favicon: config.favicon,
|
|
131
|
-
themeOverrides: config.theme,
|
|
132
95
|
});
|
|
133
96
|
},
|
|
134
97
|
});
|
|
135
98
|
const validate = defineCommand({
|
|
136
99
|
meta: {
|
|
137
100
|
name: "validate",
|
|
138
|
-
description: "Validate an OpenAPI
|
|
101
|
+
description: "Validate an OpenAPI spec file",
|
|
139
102
|
},
|
|
140
103
|
args: {
|
|
141
104
|
spec: {
|
|
142
105
|
type: "positional",
|
|
143
|
-
description: "Path or URL to the OpenAPI
|
|
106
|
+
description: "Path or URL to the OpenAPI spec",
|
|
144
107
|
required: true,
|
|
145
108
|
},
|
|
146
109
|
},
|
|
@@ -164,8 +127,8 @@ const validate = defineCommand({
|
|
|
164
127
|
const main = defineCommand({
|
|
165
128
|
meta: {
|
|
166
129
|
name: "sourcey",
|
|
167
|
-
version: "2.0.0
|
|
168
|
-
description: "
|
|
130
|
+
version: "2.0.0",
|
|
131
|
+
description: "Open source documentation platform for OpenAPI specs and markdown guides",
|
|
169
132
|
},
|
|
170
133
|
subCommands: {
|
|
171
134
|
build,
|
|
@@ -175,18 +138,16 @@ const main = defineCommand({
|
|
|
175
138
|
args: {
|
|
176
139
|
spec: {
|
|
177
140
|
type: "positional",
|
|
178
|
-
description: "Path
|
|
141
|
+
description: "Path to an OpenAPI spec (shorthand for 'sourcey build <spec>')",
|
|
179
142
|
required: false,
|
|
180
143
|
},
|
|
181
144
|
},
|
|
182
145
|
async run({ args, rawArgs }) {
|
|
183
|
-
// Skip if a subcommand was matched (citty still calls parent run)
|
|
184
146
|
if (rawArgs.includes("build") || rawArgs.includes("dev") || rawArgs.includes("validate"))
|
|
185
147
|
return;
|
|
186
148
|
if (args.spec) {
|
|
187
|
-
// `sourcey <specfile>` → `sourcey build <specfile>`
|
|
188
149
|
await build.run({
|
|
189
|
-
args: { _: [], spec: args.spec, output: "dist",
|
|
150
|
+
args: { _: [], spec: args.spec, output: "dist", embed: false, quiet: false },
|
|
190
151
|
rawArgs: [],
|
|
191
152
|
cmd: build,
|
|
192
153
|
});
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|