@litodocs/cli 0.5.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/LICENSE +21 -0
- package/README.md +260 -0
- package/bin/cli.js +8 -0
- package/package.json +50 -0
- package/src/cli.js +116 -0
- package/src/commands/build.js +105 -0
- package/src/commands/dev.js +133 -0
- package/src/commands/eject.js +89 -0
- package/src/commands/template.js +80 -0
- package/src/core/astro.js +9 -0
- package/src/core/colors.js +142 -0
- package/src/core/config-sync.js +117 -0
- package/src/core/config.js +94 -0
- package/src/core/output.js +15 -0
- package/src/core/package-manager.js +96 -0
- package/src/core/providers.js +78 -0
- package/src/core/scaffold.js +53 -0
- package/src/core/sync.js +364 -0
- package/src/core/template-fetcher.js +242 -0
- package/src/core/template-registry.js +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lito docs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Lito
|
|
2
|
+
|
|
3
|
+
Beautiful documentation sites from Markdown. Fast, simple, and open-source.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✨ **Simple Setup** - Point to your docs folder and go
|
|
8
|
+
🚀 **Astro-Powered** - Leverages Astro's speed and SEO optimization
|
|
9
|
+
📝 **Markdown & MDX** - Full support for both formats with frontmatter
|
|
10
|
+
🎨 **Customizable Templates** - Use GitHub-hosted or local templates
|
|
11
|
+
🔥 **Hot Reload** - Dev server with live file watching
|
|
12
|
+
⚡ **Fast Builds** - Static site generation for optimal performance
|
|
13
|
+
🎯 **SEO Optimized** - Meta tags, semantic HTML, and proper structure
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Global Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @litodocs/cli
|
|
21
|
+
# or
|
|
22
|
+
pnpm add -g @litodocs/cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Local Development
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd lito
|
|
29
|
+
pnpm install
|
|
30
|
+
chmod +x bin/cli.js
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Build Command
|
|
36
|
+
|
|
37
|
+
Generate a static documentation site:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
lito build --input ./my-docs --output ./dist
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Options:**
|
|
44
|
+
|
|
45
|
+
- `-i, --input <path>` (required) - Path to your docs folder
|
|
46
|
+
- `-o, --output <path>` - Output directory (default: `./dist`)
|
|
47
|
+
- `-t, --template <name>` - Template to use (see [Templates](#templates))
|
|
48
|
+
- `-b, --base-url <url>` - Base URL for the site (default: `/`)
|
|
49
|
+
- `--provider <name>` - optimize for hosting provider (vercel, netlify, cloudflare, static)
|
|
50
|
+
- `--rendering <mode>` - Rendering mode (static, server, hybrid)
|
|
51
|
+
- `--search` - Enable search functionality
|
|
52
|
+
- `--refresh` - Force re-download template from GitHub
|
|
53
|
+
|
|
54
|
+
### Dev Command
|
|
55
|
+
|
|
56
|
+
Start a development server with hot reload:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
lito dev --input ./my-docs
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Options:**
|
|
63
|
+
|
|
64
|
+
- `-i, --input <path>` (required) - Path to your docs folder
|
|
65
|
+
- `-t, --template <name>` - Template to use
|
|
66
|
+
- `-b, --base-url <url>` - Base URL for the site
|
|
67
|
+
- `-p, --port <number>` - Port for dev server (default: `4321`)
|
|
68
|
+
- `--search` - Enable search functionality
|
|
69
|
+
- `--refresh` - Force re-download template
|
|
70
|
+
|
|
71
|
+
### Eject Command
|
|
72
|
+
|
|
73
|
+
Export the full Astro project source code to customize it further:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
lito eject --input ./my-docs --output ./my-project
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Deployment
|
|
80
|
+
|
|
81
|
+
Lito includes built-in optimizations for major hosting providers. Use the `--provider` flag during build:
|
|
82
|
+
|
|
83
|
+
### Vercel
|
|
84
|
+
```bash
|
|
85
|
+
lito build -i ./docs --provider vercel
|
|
86
|
+
```
|
|
87
|
+
Generates `vercel.json` and optimizes for Vercel's edge network.
|
|
88
|
+
|
|
89
|
+
### Netlify
|
|
90
|
+
```bash
|
|
91
|
+
lito build -i ./docs --provider netlify
|
|
92
|
+
```
|
|
93
|
+
Generates `netlify.toml` with security headers.
|
|
94
|
+
|
|
95
|
+
### Cloudflare Pages
|
|
96
|
+
```bash
|
|
97
|
+
lito build -i ./docs --provider cloudflare --rendering server
|
|
98
|
+
```
|
|
99
|
+
Configures the project for Cloudflare's edge runtime with SSR support.
|
|
100
|
+
|
|
101
|
+
## Analytics
|
|
102
|
+
|
|
103
|
+
Lito supports Google Analytics 4 out of the box with zero performance penalty (powered by Partytown).
|
|
104
|
+
|
|
105
|
+
Add this to your `docs-config.json`:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"integrations": {
|
|
110
|
+
"analytics": {
|
|
111
|
+
"provider": "google-analytics",
|
|
112
|
+
"measurementId": "G-XXXXXXXXXX"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Templates
|
|
119
|
+
|
|
120
|
+
Lito supports flexible template sources:
|
|
121
|
+
|
|
122
|
+
### Default Template
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
lito dev -i ./docs
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### GitHub Templates
|
|
129
|
+
|
|
130
|
+
Use templates hosted on GitHub:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# From a GitHub repo
|
|
134
|
+
lito dev -i ./docs --template github:owner/repo
|
|
135
|
+
|
|
136
|
+
# Specific branch or tag
|
|
137
|
+
lito dev -i ./docs --template github:owner/repo#v1.0.0
|
|
138
|
+
|
|
139
|
+
# Template in a subdirectory
|
|
140
|
+
lito dev -i ./docs --template github:owner/repo/templates/modern
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Local Templates
|
|
144
|
+
|
|
145
|
+
Use a local template folder:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
lito dev -i ./docs --template ./my-custom-template
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Template Management
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# List available templates
|
|
155
|
+
lito template list
|
|
156
|
+
|
|
157
|
+
# Clear template cache
|
|
158
|
+
lito template cache --clear
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Update Templates
|
|
162
|
+
|
|
163
|
+
Templates are cached for 24 hours. Force update with:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
lito dev -i ./docs --refresh
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Documentation Structure
|
|
170
|
+
|
|
171
|
+
Your docs folder should contain Markdown (`.md`) or MDX (`.mdx`) files:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
my-docs/
|
|
175
|
+
├── index.md
|
|
176
|
+
├── getting-started.md
|
|
177
|
+
├── api/
|
|
178
|
+
│ ├── reference.md
|
|
179
|
+
│ └── examples.md
|
|
180
|
+
└── guides/
|
|
181
|
+
└── advanced.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Frontmatter
|
|
185
|
+
|
|
186
|
+
Add frontmatter to your markdown files for better metadata:
|
|
187
|
+
|
|
188
|
+
```markdown
|
|
189
|
+
---
|
|
190
|
+
title: Getting Started
|
|
191
|
+
description: Learn how to get started quickly
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
# Getting Started
|
|
195
|
+
|
|
196
|
+
Your content here...
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Architecture
|
|
200
|
+
|
|
201
|
+
The CLI tool:
|
|
202
|
+
|
|
203
|
+
1. **Resolves Template** - Fetches from GitHub or uses local template
|
|
204
|
+
2. **Scaffolds** - Creates a temporary Astro project from the template
|
|
205
|
+
3. **Syncs** - Copies your docs into `src/pages/` for automatic routing
|
|
206
|
+
4. **Configures** - Generates dynamic `astro.config.mjs` with your options
|
|
207
|
+
5. **Builds/Serves** - Spawns native Astro CLI commands
|
|
208
|
+
6. **Watches** (dev mode) - Uses `chokidar` to monitor file changes
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
### Project Structure
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
lito/
|
|
216
|
+
├── bin/
|
|
217
|
+
│ └── cli.js # CLI entry point
|
|
218
|
+
├── src/
|
|
219
|
+
│ ├── cli.js # Commander setup
|
|
220
|
+
│ ├── commands/
|
|
221
|
+
│ │ ├── build.js # Build command
|
|
222
|
+
│ │ ├── dev.js # Dev command with watcher
|
|
223
|
+
│ │ ├── eject.js # Eject command
|
|
224
|
+
│ │ └── template.js # Template management
|
|
225
|
+
│ ├── core/
|
|
226
|
+
│ │ ├── scaffold.js # Project scaffolding
|
|
227
|
+
│ │ ├── sync.js # File syncing
|
|
228
|
+
│ │ ├── config.js # Config generation
|
|
229
|
+
│ │ ├── astro.js # Astro CLI spawning
|
|
230
|
+
│ │ ├── template-fetcher.js # GitHub template fetching
|
|
231
|
+
│ │ └── template-registry.js # Template name registry
|
|
232
|
+
│ └── template/ # Bundled fallback template
|
|
233
|
+
└── package.json
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Running Tests
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Create sample docs
|
|
240
|
+
mkdir sample-docs
|
|
241
|
+
echo "# Hello\n\nWelcome!" > sample-docs/index.md
|
|
242
|
+
|
|
243
|
+
# Test build
|
|
244
|
+
node bin/cli.js build -i sample-docs -o test-output
|
|
245
|
+
|
|
246
|
+
# Test dev server
|
|
247
|
+
node bin/cli.js dev -i sample-docs
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Contributing
|
|
251
|
+
|
|
252
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
253
|
+
|
|
254
|
+
## License
|
|
255
|
+
|
|
256
|
+
MIT
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
**Built with ❤️ using Astro and Node.js**
|
package/bin/cli.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@litodocs/cli",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Beautiful documentation sites from Markdown. Fast, simple, and open-source.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"lito": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/Lito-docs/cli.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/Lito-docs/cli/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/Lito-docs/cli#readme",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"documentation",
|
|
23
|
+
"docs",
|
|
24
|
+
"markdown",
|
|
25
|
+
"mdx",
|
|
26
|
+
"astro",
|
|
27
|
+
"static-site-generator",
|
|
28
|
+
"documentation-generator",
|
|
29
|
+
"lito",
|
|
30
|
+
"open-source"
|
|
31
|
+
],
|
|
32
|
+
"author": "Lito-docs",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@astrojs/mdx": "^3.1.0",
|
|
42
|
+
"@clack/prompts": "^0.11.0",
|
|
43
|
+
"astro": "^4.16.0",
|
|
44
|
+
"chokidar": "^4.0.0",
|
|
45
|
+
"commander": "^12.1.0",
|
|
46
|
+
"execa": "^9.0.0",
|
|
47
|
+
"fs-extra": "^11.2.0",
|
|
48
|
+
"picocolors": "^1.1.1"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
import { buildCommand } from "./commands/build.js";
|
|
4
|
+
import { devCommand } from "./commands/dev.js";
|
|
5
|
+
import { ejectCommand } from "./commands/eject.js";
|
|
6
|
+
import {
|
|
7
|
+
templateListCommand,
|
|
8
|
+
templateCacheCommand,
|
|
9
|
+
} from "./commands/template.js";
|
|
10
|
+
|
|
11
|
+
export async function cli() {
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name("lito")
|
|
16
|
+
.description(
|
|
17
|
+
"Beautiful documentation sites from Markdown. Fast, simple, and open-source."
|
|
18
|
+
)
|
|
19
|
+
.version("0.5.0");
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command("build")
|
|
23
|
+
.description("Build the documentation site")
|
|
24
|
+
.requiredOption("-i, --input <path>", "Path to the docs folder")
|
|
25
|
+
.option(
|
|
26
|
+
"-o, --output <path>",
|
|
27
|
+
"Output directory for the built site",
|
|
28
|
+
"./dist"
|
|
29
|
+
)
|
|
30
|
+
.option(
|
|
31
|
+
"-t, --template <name>",
|
|
32
|
+
"Template to use (default, github:owner/repo, or local path)",
|
|
33
|
+
"default"
|
|
34
|
+
)
|
|
35
|
+
.option("-b, --base-url <url>", "Base URL for the site", "/")
|
|
36
|
+
.option("--name <name>", "Project name")
|
|
37
|
+
.option("--description <description>", "Project description")
|
|
38
|
+
.option("--primary-color <color>", "Primary theme color (hex)")
|
|
39
|
+
.option("--accent-color <color>", "Accent theme color (hex)")
|
|
40
|
+
.option("--favicon <path>", "Favicon path")
|
|
41
|
+
.option("--logo <path>", "Logo path")
|
|
42
|
+
.option("--provider <name>", "Hosting provider optimization (vercel, netlify, cloudflare, static)", "static")
|
|
43
|
+
.option("--rendering <type>", "Rendering mode (static, server, hybrid)", "static")
|
|
44
|
+
.option("--search", "Enable search functionality", false)
|
|
45
|
+
.option("--refresh", "Force re-download template (bypass cache)", false)
|
|
46
|
+
.action(buildCommand);
|
|
47
|
+
|
|
48
|
+
program
|
|
49
|
+
.command("dev")
|
|
50
|
+
.description("Start development server with watch mode")
|
|
51
|
+
.requiredOption("-i, --input <path>", "Path to the docs folder")
|
|
52
|
+
.option(
|
|
53
|
+
"-t, --template <name>",
|
|
54
|
+
"Template to use (default, github:owner/repo, or local path)",
|
|
55
|
+
"default"
|
|
56
|
+
)
|
|
57
|
+
.option("-b, --base-url <url>", "Base URL for the site", "/")
|
|
58
|
+
.option("--name <name>", "Project name")
|
|
59
|
+
.option("--description <description>", "Project description")
|
|
60
|
+
.option("--primary-color <color>", "Primary theme color (hex)")
|
|
61
|
+
.option("--accent-color <color>", "Accent theme color (hex)")
|
|
62
|
+
.option("--favicon <path>", "Favicon path")
|
|
63
|
+
.option("--logo <path>", "Logo path")
|
|
64
|
+
.option("--search", "Enable search functionality", false)
|
|
65
|
+
.option("-p, --port <number>", "Port for dev server", "4321")
|
|
66
|
+
.option("--refresh", "Force re-download template (bypass cache)", false)
|
|
67
|
+
.action(devCommand);
|
|
68
|
+
|
|
69
|
+
program
|
|
70
|
+
.command("eject")
|
|
71
|
+
.description("Export the full Astro project source code")
|
|
72
|
+
.requiredOption("-i, --input <path>", "Path to the docs folder")
|
|
73
|
+
.option(
|
|
74
|
+
"-o, --output <path>",
|
|
75
|
+
"Output directory for the project",
|
|
76
|
+
"./astro-docs-project"
|
|
77
|
+
)
|
|
78
|
+
.option(
|
|
79
|
+
"-t, --template <name>",
|
|
80
|
+
"Template to use (default, github:owner/repo, or local path)",
|
|
81
|
+
"default"
|
|
82
|
+
)
|
|
83
|
+
.option("-b, --base-url <url>", "Base URL for the site", "/")
|
|
84
|
+
.option("--name <name>", "Project name")
|
|
85
|
+
.option("--description <description>", "Project description")
|
|
86
|
+
.option("--primary-color <color>", "Primary theme color (hex)")
|
|
87
|
+
.option("--accent-color <color>", "Accent theme color (hex)")
|
|
88
|
+
.option("--favicon <path>", "Favicon path")
|
|
89
|
+
.option("--logo <path>", "Logo path")
|
|
90
|
+
.option("--search", "Enable search functionality", false)
|
|
91
|
+
.option("--refresh", "Force re-download template (bypass cache)", false)
|
|
92
|
+
.action(ejectCommand);
|
|
93
|
+
|
|
94
|
+
// Template management commands
|
|
95
|
+
const templateCmd = program
|
|
96
|
+
.command("template")
|
|
97
|
+
.description("Manage documentation templates");
|
|
98
|
+
|
|
99
|
+
templateCmd
|
|
100
|
+
.command("list")
|
|
101
|
+
.description("List available templates")
|
|
102
|
+
.action(templateListCommand);
|
|
103
|
+
|
|
104
|
+
templateCmd
|
|
105
|
+
.command("cache")
|
|
106
|
+
.description("Manage template cache")
|
|
107
|
+
.option("--clear", "Clear all cached templates")
|
|
108
|
+
.action(templateCacheCommand);
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await program.parseAsync(process.argv);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(pc.red("Error:"), error.message);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { intro, outro, spinner, log, isCancel, cancel } from '@clack/prompts';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import { scaffoldProject, cleanupProject } from '../core/scaffold.js';
|
|
6
|
+
import { syncDocs } from '../core/sync.js';
|
|
7
|
+
import { generateConfig } from '../core/config.js';
|
|
8
|
+
import { runAstroBuild } from '../core/astro.js';
|
|
9
|
+
import { syncDocsConfig } from '../core/config-sync.js';
|
|
10
|
+
import { copyOutput } from '../core/output.js';
|
|
11
|
+
import { getTemplatePath } from '../core/template-fetcher.js';
|
|
12
|
+
|
|
13
|
+
export async function buildCommand(options) {
|
|
14
|
+
try {
|
|
15
|
+
// Validate input path
|
|
16
|
+
const inputPath = resolve(options.input);
|
|
17
|
+
if (!existsSync(inputPath)) {
|
|
18
|
+
log.error(`Input path does not exist: ${pc.cyan(inputPath)}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.clear();
|
|
23
|
+
intro(pc.inverse(pc.cyan(' Lito - Build ')));
|
|
24
|
+
|
|
25
|
+
const s = spinner();
|
|
26
|
+
|
|
27
|
+
// Step 0: Resolve template
|
|
28
|
+
s.start('Resolving template...');
|
|
29
|
+
const templatePath = await getTemplatePath(options.template, options.refresh);
|
|
30
|
+
s.stop(templatePath ? `Using template: ${pc.cyan(templatePath)}` : 'Using bundled template');
|
|
31
|
+
|
|
32
|
+
// Step 1: Scaffold temporary Astro project
|
|
33
|
+
s.start('Setting up Astro project...');
|
|
34
|
+
const projectDir = await scaffoldProject(templatePath);
|
|
35
|
+
s.stop('Astro project scaffolded');
|
|
36
|
+
|
|
37
|
+
// Step 2: Prepare project (Install dependencies, Sync docs, Generate navigation)
|
|
38
|
+
const { installDependencies, runBinary } = await import('../core/package-manager.js');
|
|
39
|
+
s.start('Preparing project (installing dependencies, syncing files)...');
|
|
40
|
+
|
|
41
|
+
const userConfigPath = resolve(options.input, 'docs-config.json');
|
|
42
|
+
|
|
43
|
+
await Promise.all([
|
|
44
|
+
installDependencies(projectDir, { silent: true }),
|
|
45
|
+
syncDocs(inputPath, projectDir),
|
|
46
|
+
syncDocsConfig(projectDir, inputPath, userConfigPath)
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
s.stop('Project prepared (dependencies installed, docs synced, navigation generated)');
|
|
50
|
+
|
|
51
|
+
// Step 4: Generate config
|
|
52
|
+
s.start('Generating Astro configuration...');
|
|
53
|
+
await generateConfig(projectDir, options);
|
|
54
|
+
s.stop('Configuration generated');
|
|
55
|
+
|
|
56
|
+
// Step 4.5: Configure for provider
|
|
57
|
+
if (options.provider && options.provider !== 'static') {
|
|
58
|
+
s.start(`Configuring for ${options.provider} (${options.rendering})...`);
|
|
59
|
+
const { configureProvider } = await import('../core/providers.js');
|
|
60
|
+
await configureProvider(projectDir, options.provider, options.rendering);
|
|
61
|
+
s.stop(`Configured for ${options.provider}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Step 5: Build with Astro
|
|
65
|
+
s.start('Building site with Astro...');
|
|
66
|
+
await runAstroBuild(projectDir);
|
|
67
|
+
s.stop('Site built successfully');
|
|
68
|
+
|
|
69
|
+
// Step 5.5: Generate Pagefind search index
|
|
70
|
+
s.start('Generating search index...');
|
|
71
|
+
await runBinary(projectDir, 'pagefind', ['--site', 'dist']);
|
|
72
|
+
s.stop('Search index generated');
|
|
73
|
+
|
|
74
|
+
// Step 6: Copy output
|
|
75
|
+
const outputPath = resolve(options.output);
|
|
76
|
+
s.start(`Copying output to ${pc.cyan(outputPath)}...`);
|
|
77
|
+
await copyOutput(projectDir, outputPath);
|
|
78
|
+
s.stop('Output copied');
|
|
79
|
+
|
|
80
|
+
// Cleanup temp directory
|
|
81
|
+
s.start('Cleaning up...');
|
|
82
|
+
await cleanupProject();
|
|
83
|
+
s.stop('Cleanup complete');
|
|
84
|
+
|
|
85
|
+
outro(pc.green('Build completed successfully!'));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (isCancel(error)) {
|
|
88
|
+
cancel('Operation cancelled.');
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Attempt to cleanup even on error
|
|
93
|
+
try {
|
|
94
|
+
await cleanupProject();
|
|
95
|
+
} catch (e) {
|
|
96
|
+
// failed to cleanup
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
log.error(pc.red(error.message));
|
|
100
|
+
if (error.stack) {
|
|
101
|
+
log.error(pc.gray(error.stack));
|
|
102
|
+
}
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { intro, outro, spinner, log, note, isCancel, cancel } from '@clack/prompts';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import chokidar from 'chokidar';
|
|
6
|
+
import { scaffoldProject, cleanupProject } from '../core/scaffold.js';
|
|
7
|
+
import { syncDocs } from '../core/sync.js';
|
|
8
|
+
import { generateConfig } from '../core/config.js';
|
|
9
|
+
import { runAstroDev } from '../core/astro.js';
|
|
10
|
+
import { syncDocsConfig } from '../core/config-sync.js';
|
|
11
|
+
import { getTemplatePath } from '../core/template-fetcher.js';
|
|
12
|
+
|
|
13
|
+
export async function devCommand(options) {
|
|
14
|
+
try {
|
|
15
|
+
// Validate input path
|
|
16
|
+
const inputPath = resolve(options.input);
|
|
17
|
+
if (!existsSync(inputPath)) {
|
|
18
|
+
log.error(`Input path does not exist: ${pc.cyan(inputPath)}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.clear();
|
|
23
|
+
intro(pc.inverse(pc.cyan(' Lito - Dev Server ')));
|
|
24
|
+
|
|
25
|
+
const s = spinner();
|
|
26
|
+
|
|
27
|
+
// Step 0: Resolve template
|
|
28
|
+
s.start('Resolving template...');
|
|
29
|
+
const templatePath = await getTemplatePath(options.template, options.refresh);
|
|
30
|
+
s.stop(templatePath ? `Using template: ${pc.cyan(templatePath)}` : 'Using bundled template');
|
|
31
|
+
|
|
32
|
+
// Step 1: Scaffold temporary Astro project
|
|
33
|
+
s.start('Setting up Astro project...');
|
|
34
|
+
const projectDir = await scaffoldProject(templatePath);
|
|
35
|
+
s.stop('Astro project scaffolded');
|
|
36
|
+
|
|
37
|
+
// Register cleanup handlers
|
|
38
|
+
const cleanup = async () => {
|
|
39
|
+
s.start('Cleaning up...');
|
|
40
|
+
await cleanupProject();
|
|
41
|
+
s.stop('Cleanup complete');
|
|
42
|
+
process.exit(0);
|
|
43
|
+
};
|
|
44
|
+
process.on('SIGINT', cleanup);
|
|
45
|
+
process.on('SIGTERM', cleanup);
|
|
46
|
+
|
|
47
|
+
// Step 2: Prepare project (Install dependencies, Sync docs, Generate navigation)
|
|
48
|
+
const { installDependencies } = await import('../core/package-manager.js');
|
|
49
|
+
s.start('Preparing project (installing dependencies, syncing files)...');
|
|
50
|
+
|
|
51
|
+
const userConfigPath = resolve(options.input, 'docs-config.json');
|
|
52
|
+
|
|
53
|
+
await Promise.all([
|
|
54
|
+
installDependencies(projectDir, { silent: true }),
|
|
55
|
+
syncDocs(inputPath, projectDir),
|
|
56
|
+
syncDocsConfig(projectDir, inputPath, userConfigPath)
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
s.stop('Project prepared (dependencies installed, docs synced, navigation generated)');
|
|
60
|
+
|
|
61
|
+
// Step 4: Generate config
|
|
62
|
+
s.start('Generating Astro configuration...');
|
|
63
|
+
await generateConfig(projectDir, options);
|
|
64
|
+
s.stop('Configuration generated');
|
|
65
|
+
|
|
66
|
+
// Step 4: Setup file watcher with debouncing
|
|
67
|
+
log.info(pc.cyan('Watching for file changes...'));
|
|
68
|
+
|
|
69
|
+
let syncTimeout = null;
|
|
70
|
+
let isSyncing = false;
|
|
71
|
+
|
|
72
|
+
const debouncedSync = async () => {
|
|
73
|
+
if (isSyncing) return;
|
|
74
|
+
|
|
75
|
+
if (syncTimeout) {
|
|
76
|
+
clearTimeout(syncTimeout);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
syncTimeout = setTimeout(async () => {
|
|
80
|
+
if (isSyncing) return;
|
|
81
|
+
isSyncing = true;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await Promise.all([
|
|
85
|
+
syncDocs(inputPath, projectDir),
|
|
86
|
+
syncDocsConfig(projectDir, inputPath, userConfigPath)
|
|
87
|
+
]);
|
|
88
|
+
log.success('Documentation and config re-synced');
|
|
89
|
+
} catch (error) {
|
|
90
|
+
log.error('Sync failed: ' + error.message);
|
|
91
|
+
} finally {
|
|
92
|
+
isSyncing = false;
|
|
93
|
+
}
|
|
94
|
+
}, 300); // 300ms debounce
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const watcher = chokidar.watch(inputPath, {
|
|
98
|
+
ignored: /(^|[\/\\])\../,
|
|
99
|
+
persistent: true,
|
|
100
|
+
ignoreInitial: true, // Don't trigger for existing files
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
watcher.on('change', async (path) => {
|
|
104
|
+
log.info(`File changed: ${pc.dim(path)}`);
|
|
105
|
+
debouncedSync();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
watcher.on('add', async (path) => {
|
|
109
|
+
log.success(`File added: ${pc.dim(path)}`);
|
|
110
|
+
debouncedSync();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
watcher.on('unlink', async (path) => {
|
|
114
|
+
log.warning(`File removed: ${pc.dim(path)}`);
|
|
115
|
+
debouncedSync();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Step 5: Start Astro dev server
|
|
119
|
+
note(`Starting Astro dev server at http://localhost:${options.port}`, 'Dev Server');
|
|
120
|
+
await runAstroDev(projectDir, options.port);
|
|
121
|
+
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (isCancel(error)) {
|
|
124
|
+
cancel('Operation cancelled.');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
log.error(pc.red('Dev server failed: ' + error.message));
|
|
128
|
+
if (error.stack) {
|
|
129
|
+
log.error(pc.gray(error.stack));
|
|
130
|
+
}
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|