@litodocs/cli 0.6.0 → 0.7.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 +325 -124
- package/lito-manifest.schema.json +118 -0
- package/package.json +1 -1
- package/src/cli.js +48 -0
- package/src/commands/build.js +26 -17
- package/src/commands/dev.js +17 -12
- package/src/commands/doctor.js +311 -0
- package/src/commands/info.js +192 -0
- package/src/commands/init.js +284 -0
- package/src/commands/preview.js +98 -0
- package/src/commands/validate.js +124 -0
- package/src/core/config.js +62 -18
- package/src/core/framework-runner.js +208 -0
- package/src/core/landing-sync.js +708 -0
- package/src/core/output.js +10 -4
- package/src/core/sync.js +141 -15
- package/src/core/template-registry.js +8 -5
package/src/core/config.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import pkg from "fs-extra";
|
|
2
|
-
const { readFile, writeFile, ensureDir } = pkg;
|
|
2
|
+
const { readFile, writeFile, ensureDir, pathExists } = pkg;
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { generateThemeStyles } from "./colors.js";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Generate configuration for the project
|
|
8
|
+
* @param {string} projectDir - The scaffolded project directory
|
|
9
|
+
* @param {object} options - CLI options
|
|
10
|
+
* @param {object|null} frameworkConfig - Framework configuration (optional)
|
|
11
|
+
*/
|
|
12
|
+
export async function generateConfig(projectDir, options, frameworkConfig = null) {
|
|
7
13
|
const {
|
|
8
14
|
baseUrl,
|
|
9
15
|
name,
|
|
@@ -68,27 +74,65 @@ export async function generateConfig(projectDir, options) {
|
|
|
68
74
|
await writeFile(join(stylesDir, "generated-theme.css"), "/* No generated theme styles */", "utf-8");
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
// Update astro.config.mjs with base URL and site URL
|
|
72
|
-
|
|
77
|
+
// Update astro.config.mjs with base URL and site URL (only for Astro)
|
|
78
|
+
const frameworkName = frameworkConfig?.name || 'astro';
|
|
79
|
+
|
|
80
|
+
if (frameworkName === 'astro' && ((baseUrl && baseUrl !== "/") || config.metadata?.url)) {
|
|
73
81
|
const astroConfigPath = join(projectDir, "astro.config.mjs");
|
|
74
|
-
|
|
82
|
+
if (await pathExists(astroConfigPath)) {
|
|
83
|
+
let content = await readFile(astroConfigPath, "utf-8");
|
|
84
|
+
|
|
85
|
+
let injection = "export default defineConfig({\n";
|
|
86
|
+
|
|
87
|
+
if (baseUrl && baseUrl !== "/") {
|
|
88
|
+
injection += ` base: '${baseUrl}',\n`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (config.metadata?.url) {
|
|
92
|
+
injection += ` site: '${config.metadata.url}',\n`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add base/site option to defineConfig
|
|
96
|
+
content = content.replace(
|
|
97
|
+
"export default defineConfig({",
|
|
98
|
+
injection
|
|
99
|
+
);
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (baseUrl && baseUrl !== "/") {
|
|
79
|
-
injection += ` base: '${baseUrl}',\n`;
|
|
101
|
+
await writeFile(astroConfigPath, content, "utf-8");
|
|
80
102
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Update vite.config.js for React/Vue frameworks
|
|
106
|
+
if (['react', 'vue'].includes(frameworkName) && baseUrl && baseUrl !== "/") {
|
|
107
|
+
const viteConfigPath = join(projectDir, "vite.config.js");
|
|
108
|
+
if (await pathExists(viteConfigPath)) {
|
|
109
|
+
let content = await readFile(viteConfigPath, "utf-8");
|
|
110
|
+
|
|
111
|
+
// Add base option to defineConfig
|
|
112
|
+
if (content.includes("defineConfig({")) {
|
|
113
|
+
content = content.replace(
|
|
114
|
+
"defineConfig({",
|
|
115
|
+
`defineConfig({\n base: '${baseUrl}',`
|
|
116
|
+
);
|
|
117
|
+
await writeFile(viteConfigPath, content, "utf-8");
|
|
118
|
+
}
|
|
84
119
|
}
|
|
120
|
+
}
|
|
85
121
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
122
|
+
// Update next.config.js for Next.js
|
|
123
|
+
if (frameworkName === 'next' && baseUrl && baseUrl !== "/") {
|
|
124
|
+
const nextConfigPath = join(projectDir, "next.config.js");
|
|
125
|
+
if (await pathExists(nextConfigPath)) {
|
|
126
|
+
let content = await readFile(nextConfigPath, "utf-8");
|
|
91
127
|
|
|
92
|
-
|
|
128
|
+
// Add basePath to Next.js config
|
|
129
|
+
if (!content.includes("basePath")) {
|
|
130
|
+
content = content.replace(
|
|
131
|
+
"module.exports = {",
|
|
132
|
+
`module.exports = {\n basePath: '${baseUrl}',`
|
|
133
|
+
);
|
|
134
|
+
await writeFile(nextConfigPath, content, "utf-8");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
93
137
|
}
|
|
94
138
|
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { runBinary } from './package-manager.js';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import pkg from 'fs-extra';
|
|
4
|
+
const { pathExists, readJson } = pkg;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Framework configuration schema
|
|
8
|
+
* Templates can define their framework in lito-manifest.json or template-manifest.json
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_FRAMEWORK_CONFIGS = {
|
|
11
|
+
astro: {
|
|
12
|
+
name: 'astro',
|
|
13
|
+
commands: {
|
|
14
|
+
dev: ['astro', ['dev']],
|
|
15
|
+
build: ['astro', ['build']],
|
|
16
|
+
},
|
|
17
|
+
contentDir: 'src/pages',
|
|
18
|
+
publicDir: 'public',
|
|
19
|
+
configFile: 'astro.config.mjs',
|
|
20
|
+
layoutInjection: true,
|
|
21
|
+
layoutPath: 'layouts/MarkdownLayout.astro',
|
|
22
|
+
apiLayoutPath: 'layouts/APILayout.astro',
|
|
23
|
+
},
|
|
24
|
+
react: {
|
|
25
|
+
name: 'react',
|
|
26
|
+
commands: {
|
|
27
|
+
dev: ['vite', ['--host']],
|
|
28
|
+
build: ['vite', ['build']],
|
|
29
|
+
},
|
|
30
|
+
contentDir: 'src/content',
|
|
31
|
+
publicDir: 'public',
|
|
32
|
+
configFile: 'vite.config.js',
|
|
33
|
+
layoutInjection: false,
|
|
34
|
+
useMDX: true,
|
|
35
|
+
// HMR trigger file that will be updated when content changes
|
|
36
|
+
hmrTriggerFile: 'src/.lito-hmr-trigger.js',
|
|
37
|
+
},
|
|
38
|
+
next: {
|
|
39
|
+
name: 'next',
|
|
40
|
+
commands: {
|
|
41
|
+
dev: ['next', ['dev']],
|
|
42
|
+
build: ['next', ['build']],
|
|
43
|
+
},
|
|
44
|
+
contentDir: 'content',
|
|
45
|
+
publicDir: 'public',
|
|
46
|
+
configFile: 'next.config.js',
|
|
47
|
+
layoutInjection: false,
|
|
48
|
+
useMDX: true,
|
|
49
|
+
},
|
|
50
|
+
vue: {
|
|
51
|
+
name: 'vue',
|
|
52
|
+
commands: {
|
|
53
|
+
dev: ['vite', ['--host']],
|
|
54
|
+
build: ['vite', ['build']],
|
|
55
|
+
},
|
|
56
|
+
contentDir: 'src/content',
|
|
57
|
+
publicDir: 'public',
|
|
58
|
+
configFile: 'vite.config.js',
|
|
59
|
+
layoutInjection: false,
|
|
60
|
+
// HMR trigger file that will be updated when content changes
|
|
61
|
+
hmrTriggerFile: 'src/.lito-hmr-trigger.js',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect framework from template directory
|
|
67
|
+
* Checks for lito-manifest.json, template-manifest.json, or infers from config files
|
|
68
|
+
*/
|
|
69
|
+
export async function detectFramework(projectDir) {
|
|
70
|
+
// Check for lito-manifest.json first (preferred)
|
|
71
|
+
const litoManifestPath = join(projectDir, 'lito-manifest.json');
|
|
72
|
+
if (await pathExists(litoManifestPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const manifest = await readJson(litoManifestPath);
|
|
75
|
+
if (manifest.framework) {
|
|
76
|
+
return mergeFrameworkConfig(manifest.framework, manifest);
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// Fall through to other detection methods
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check for template-manifest.json (legacy)
|
|
84
|
+
const templateManifestPath = join(projectDir, 'template-manifest.json');
|
|
85
|
+
if (await pathExists(templateManifestPath)) {
|
|
86
|
+
try {
|
|
87
|
+
const manifest = await readJson(templateManifestPath);
|
|
88
|
+
if (manifest.framework) {
|
|
89
|
+
return mergeFrameworkConfig(manifest.framework, manifest);
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
// Fall through to inference
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Infer from config files
|
|
97
|
+
if (await pathExists(join(projectDir, 'astro.config.mjs')) ||
|
|
98
|
+
await pathExists(join(projectDir, 'astro.config.js'))) {
|
|
99
|
+
return DEFAULT_FRAMEWORK_CONFIGS.astro;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (await pathExists(join(projectDir, 'next.config.js')) ||
|
|
103
|
+
await pathExists(join(projectDir, 'next.config.mjs')) ||
|
|
104
|
+
await pathExists(join(projectDir, 'next.config.ts'))) {
|
|
105
|
+
return DEFAULT_FRAMEWORK_CONFIGS.next;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check package.json for framework hints
|
|
109
|
+
const packageJsonPath = join(projectDir, 'package.json');
|
|
110
|
+
if (await pathExists(packageJsonPath)) {
|
|
111
|
+
try {
|
|
112
|
+
const packageJson = await readJson(packageJsonPath);
|
|
113
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
114
|
+
|
|
115
|
+
if (deps['next']) return DEFAULT_FRAMEWORK_CONFIGS.next;
|
|
116
|
+
if (deps['astro']) return DEFAULT_FRAMEWORK_CONFIGS.astro;
|
|
117
|
+
if (deps['vue'] && deps['vite']) return DEFAULT_FRAMEWORK_CONFIGS.vue;
|
|
118
|
+
if (deps['react'] && deps['vite']) return DEFAULT_FRAMEWORK_CONFIGS.react;
|
|
119
|
+
} catch {
|
|
120
|
+
// Fall through to default
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Default to Astro (backward compatible)
|
|
125
|
+
return DEFAULT_FRAMEWORK_CONFIGS.astro;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Merge custom framework config with defaults
|
|
130
|
+
*/
|
|
131
|
+
function mergeFrameworkConfig(frameworkName, manifest) {
|
|
132
|
+
const baseConfig = DEFAULT_FRAMEWORK_CONFIGS[frameworkName] || {
|
|
133
|
+
name: frameworkName,
|
|
134
|
+
contentDir: 'src/content',
|
|
135
|
+
publicDir: 'public',
|
|
136
|
+
layoutInjection: false,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
...baseConfig,
|
|
141
|
+
...manifest.frameworkConfig,
|
|
142
|
+
name: frameworkName,
|
|
143
|
+
// Allow manifest to override commands
|
|
144
|
+
commands: {
|
|
145
|
+
...baseConfig.commands,
|
|
146
|
+
...manifest.commands,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Run the framework's dev server
|
|
153
|
+
*/
|
|
154
|
+
export async function runFrameworkDev(projectDir, frameworkConfig, port = '4321') {
|
|
155
|
+
const { commands } = frameworkConfig;
|
|
156
|
+
const [binary, args] = commands.dev;
|
|
157
|
+
|
|
158
|
+
const devArgs = [...args];
|
|
159
|
+
|
|
160
|
+
// Add port based on framework
|
|
161
|
+
if (frameworkConfig.name === 'astro') {
|
|
162
|
+
devArgs.push('--port', port);
|
|
163
|
+
} else if (frameworkConfig.name === 'next') {
|
|
164
|
+
devArgs.push('-p', port);
|
|
165
|
+
} else {
|
|
166
|
+
// Vite-based frameworks
|
|
167
|
+
devArgs.push('--port', port);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
await runBinary(projectDir, binary, devArgs);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Run the framework's build command
|
|
175
|
+
*/
|
|
176
|
+
export async function runFrameworkBuild(projectDir, frameworkConfig) {
|
|
177
|
+
const { commands } = frameworkConfig;
|
|
178
|
+
const [binary, args] = commands.build;
|
|
179
|
+
|
|
180
|
+
await runBinary(projectDir, binary, args);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get the output directory for the built site
|
|
185
|
+
*/
|
|
186
|
+
export function getOutputDir(frameworkConfig) {
|
|
187
|
+
switch (frameworkConfig.name) {
|
|
188
|
+
case 'astro':
|
|
189
|
+
return 'dist';
|
|
190
|
+
case 'next':
|
|
191
|
+
return '.next';
|
|
192
|
+
case 'react':
|
|
193
|
+
case 'vue':
|
|
194
|
+
return 'dist';
|
|
195
|
+
default:
|
|
196
|
+
return 'dist';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if framework needs search indexing (pagefind)
|
|
202
|
+
*/
|
|
203
|
+
export function needsSearchIndex(frameworkConfig) {
|
|
204
|
+
// Only static-output frameworks need pagefind
|
|
205
|
+
return ['astro', 'react', 'vue'].includes(frameworkConfig.name);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { DEFAULT_FRAMEWORK_CONFIGS };
|