@nuasite/cli 0.16.1 → 0.17.1
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 +27 -1
- package/dist/index.js +393 -22
- package/dist/types/clean.d.ts +19 -0
- package/dist/types/clean.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/types/utils.d.ts +2 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/clean.ts +402 -0
- package/src/index.ts +16 -23
- package/src/utils.ts +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAM1E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuasite/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"prepack": "bun run ../../scripts/workspace-deps/resolve-deps.ts"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@nuasite/agent-summary": "0.
|
|
26
|
+
"@nuasite/agent-summary": "0.17.1",
|
|
27
27
|
"astro": "^6.0.2",
|
|
28
28
|
"stacktracey": "2.1.8"
|
|
29
29
|
},
|
package/src/clean.ts
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { basename, join } from 'node:path'
|
|
3
|
+
import { findAstroConfig } from './utils'
|
|
4
|
+
|
|
5
|
+
export interface CleanOptions {
|
|
6
|
+
cwd?: string
|
|
7
|
+
dryRun?: boolean
|
|
8
|
+
yes?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type FeatureKey = 'cms' | 'pageMarkdown' | 'mdx' | 'sitemap' | 'tailwindcss' | 'checks'
|
|
12
|
+
const FEATURE_KEYS: FeatureKey[] = ['cms', 'pageMarkdown', 'mdx', 'sitemap', 'tailwindcss', 'checks']
|
|
13
|
+
|
|
14
|
+
/** Tooling / orchestration packages — removed during clean */
|
|
15
|
+
const NUASITE_TOOLING = [
|
|
16
|
+
'@nuasite/nua',
|
|
17
|
+
'@nuasite/core',
|
|
18
|
+
'@nuasite/cli',
|
|
19
|
+
'@nuasite/cms',
|
|
20
|
+
'@nuasite/llm-enhancements',
|
|
21
|
+
'@nuasite/checks',
|
|
22
|
+
'@nuasite/agent-summary',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
const PACKAGES_TO_ADD: Record<string, string> = {
|
|
26
|
+
'astro': '^6.0.2',
|
|
27
|
+
'@astrojs/check': '^0.9.7',
|
|
28
|
+
'@astrojs/mdx': '^5.0.0',
|
|
29
|
+
'@astrojs/rss': '^4.0.17',
|
|
30
|
+
'@astrojs/sitemap': '^3.7.1',
|
|
31
|
+
'@tailwindcss/vite': '^4.2.1',
|
|
32
|
+
'tailwindcss': '^4.2.1',
|
|
33
|
+
'typescript': '^5',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function detectDisabledFeatures(content: string): Set<FeatureKey> {
|
|
37
|
+
const disabled = new Set<FeatureKey>()
|
|
38
|
+
for (const key of FEATURE_KEYS) {
|
|
39
|
+
if (new RegExp(`\\b${key}\\s*:\\s*false\\b`).test(content)) {
|
|
40
|
+
disabled.add(key)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return disabled
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Find the matching closing brace/bracket/paren, aware of string literals.
|
|
48
|
+
*/
|
|
49
|
+
function findMatchingClose(text: string, start: number): number {
|
|
50
|
+
const open = text[start]!
|
|
51
|
+
const close = open === '{' ? '}' : open === '[' ? ']' : ')'
|
|
52
|
+
let depth = 0
|
|
53
|
+
let inString: string | false = false
|
|
54
|
+
|
|
55
|
+
for (let i = start; i < text.length; i++) {
|
|
56
|
+
const ch = text[i]
|
|
57
|
+
|
|
58
|
+
if (inString) {
|
|
59
|
+
if (ch === '\\') {
|
|
60
|
+
i++
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
if (ch === inString) inString = false
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (ch === "'" || ch === '"' || ch === '`') {
|
|
68
|
+
inString = ch
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (ch === open) depth++
|
|
73
|
+
if (ch === close) {
|
|
74
|
+
depth--
|
|
75
|
+
if (depth === 0) return i
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return -1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Extract the text between the outermost { } of defineConfig({ ... })
|
|
84
|
+
*/
|
|
85
|
+
export function extractConfigBody(content: string): string {
|
|
86
|
+
const match = content.match(/defineConfig\s*\(\s*\{/)
|
|
87
|
+
if (!match || match.index === undefined) return ''
|
|
88
|
+
|
|
89
|
+
const openBrace = content.indexOf('{', match.index + 'defineConfig'.length)
|
|
90
|
+
const closeBrace = findMatchingClose(content, openBrace)
|
|
91
|
+
if (closeBrace === -1) return ''
|
|
92
|
+
|
|
93
|
+
return content.slice(openBrace + 1, closeBrace)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove a top-level property from an object literal body text.
|
|
98
|
+
*/
|
|
99
|
+
export function removeProperty(body: string, propName: string): string {
|
|
100
|
+
const regex = new RegExp(`(\\n[ \\t]*)${propName}\\s*:\\s*`)
|
|
101
|
+
const match = regex.exec(body)
|
|
102
|
+
if (!match || match.index === undefined) return body
|
|
103
|
+
|
|
104
|
+
const propLineStart = match.index + 1 // skip the leading \n
|
|
105
|
+
const afterMatch = match.index + match[0].length
|
|
106
|
+
|
|
107
|
+
// Skip whitespace (not newlines) before the value
|
|
108
|
+
let i = afterMatch
|
|
109
|
+
while (i < body.length && (body[i] === ' ' || body[i] === '\t')) i++
|
|
110
|
+
|
|
111
|
+
let valueEnd: number
|
|
112
|
+
|
|
113
|
+
if (body[i] === '{' || body[i] === '[') {
|
|
114
|
+
valueEnd = findMatchingClose(body, i)
|
|
115
|
+
if (valueEnd === -1) return body
|
|
116
|
+
valueEnd++ // include closing brace/bracket
|
|
117
|
+
} else {
|
|
118
|
+
// Simple value (false, true, number, string, variable)
|
|
119
|
+
while (i < body.length && body[i] !== ',' && body[i] !== '\n') i++
|
|
120
|
+
valueEnd = i
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Skip trailing comma and whitespace up to newline
|
|
124
|
+
let end = valueEnd
|
|
125
|
+
while (end < body.length && (body[end] === ' ' || body[end] === '\t')) end++
|
|
126
|
+
if (end < body.length && body[end] === ',') end++
|
|
127
|
+
while (end < body.length && (body[end] === ' ' || body[end] === '\t')) end++
|
|
128
|
+
if (end < body.length && body[end] === '\n') end++
|
|
129
|
+
|
|
130
|
+
return body.slice(0, propLineStart) + body.slice(end)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Prepend items into an existing array property (e.g. `integrations: [` or `plugins: [`).
|
|
135
|
+
* Mutates `lines` in place. Returns true if a merge happened.
|
|
136
|
+
*/
|
|
137
|
+
function prependToArrayProperty(lines: string[], property: string, items: string): boolean {
|
|
138
|
+
const pattern = new RegExp(`\\b${property}\\s*:\\s*\\[`)
|
|
139
|
+
for (let i = 0; i < lines.length; i++) {
|
|
140
|
+
if (pattern.test(lines[i]!)) {
|
|
141
|
+
lines[i] = lines[i]!.replace(
|
|
142
|
+
new RegExp(`(\\b${property}\\s*:\\s*\\[)`),
|
|
143
|
+
`$1${items}, `,
|
|
144
|
+
)
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function transformConfig(content: string, disabled: Set<FeatureKey>): string {
|
|
152
|
+
const userImports = content
|
|
153
|
+
.split('\n')
|
|
154
|
+
.filter(line => /^\s*import\s/.test(line))
|
|
155
|
+
.filter(line => !line.includes('@nuasite/'))
|
|
156
|
+
.filter(line => !line.includes('defineConfig'))
|
|
157
|
+
|
|
158
|
+
let body = extractConfigBody(content)
|
|
159
|
+
body = removeProperty(body, 'nua')
|
|
160
|
+
|
|
161
|
+
if (content.includes('@nuasite/nua/integration')) {
|
|
162
|
+
body = body.replace(/\bnua\s*\([^)]*\)\s*,?\s*/g, '')
|
|
163
|
+
body = body.replace(/\bintegrations\s*:\s*\[\s*,?\s*\]\s*,?/g, '')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const imports = [`import { defineConfig } from 'astro/config'`]
|
|
167
|
+
if (!disabled.has('tailwindcss')) imports.push(`import tailwindcss from '@tailwindcss/vite'`)
|
|
168
|
+
if (!disabled.has('mdx')) imports.push(`import mdx from '@astrojs/mdx'`)
|
|
169
|
+
if (!disabled.has('sitemap')) imports.push(`import sitemap from '@astrojs/sitemap'`)
|
|
170
|
+
imports.push(...userImports)
|
|
171
|
+
|
|
172
|
+
const integrationCalls: string[] = []
|
|
173
|
+
if (!disabled.has('mdx')) integrationCalls.push('mdx()')
|
|
174
|
+
if (!disabled.has('sitemap')) integrationCalls.push('sitemap()')
|
|
175
|
+
|
|
176
|
+
const bodyLines = body.split('\n').filter(line => line.trim() !== '')
|
|
177
|
+
|
|
178
|
+
const hasIntegrations = bodyLines.some(line => /^\s*integrations\s*:/.test(line))
|
|
179
|
+
const hasVite = bodyLines.some(line => /^\s*vite\s*:/.test(line))
|
|
180
|
+
|
|
181
|
+
if (hasIntegrations && integrationCalls.length > 0) {
|
|
182
|
+
prependToArrayProperty(bodyLines, 'integrations', integrationCalls.join(', '))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!disabled.has('tailwindcss') && hasVite) {
|
|
186
|
+
prependToArrayProperty(bodyLines, 'plugins', 'tailwindcss()')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const newPropLines: string[] = []
|
|
190
|
+
|
|
191
|
+
if (!disabled.has('tailwindcss') && !hasVite) {
|
|
192
|
+
newPropLines.push(
|
|
193
|
+
'\tvite: {',
|
|
194
|
+
'\t\tbuild: {',
|
|
195
|
+
'\t\t\tsourcemap: true,',
|
|
196
|
+
'\t\t},',
|
|
197
|
+
'\t\tplugins: [tailwindcss()],',
|
|
198
|
+
'\t},',
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!hasIntegrations && integrationCalls.length > 0) {
|
|
203
|
+
newPropLines.push(`\tintegrations: [${integrationCalls.join(', ')}],`)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const allLines = [...bodyLines, ...newPropLines]
|
|
207
|
+
|
|
208
|
+
let result = imports.join('\n') + '\n\n'
|
|
209
|
+
result += 'export default defineConfig({\n'
|
|
210
|
+
if (allLines.length > 0) {
|
|
211
|
+
result += allLines.join('\n') + '\n'
|
|
212
|
+
}
|
|
213
|
+
result += '})\n'
|
|
214
|
+
|
|
215
|
+
return result
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function transformPackageJson(
|
|
219
|
+
pkg: Record<string, any>,
|
|
220
|
+
disabled: Set<FeatureKey>,
|
|
221
|
+
usedRuntimePackages: string[] = [],
|
|
222
|
+
): Record<string, any> {
|
|
223
|
+
const result = structuredClone(pkg)
|
|
224
|
+
|
|
225
|
+
const nuaVersion: string | undefined = result.dependencies?.['@nuasite/nua']
|
|
226
|
+
?? result.devDependencies?.['@nuasite/nua']
|
|
227
|
+
|
|
228
|
+
if (result.scripts) {
|
|
229
|
+
for (const [key, value] of Object.entries(result.scripts)) {
|
|
230
|
+
if (typeof value === 'string') {
|
|
231
|
+
result.scripts[key] = value
|
|
232
|
+
.replace(/\bnua build\b/g, 'astro build')
|
|
233
|
+
.replace(/\bnua dev\b/g, 'astro dev')
|
|
234
|
+
.replace(/\bnua preview\b/g, 'astro preview')
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for (const field of ['dependencies', 'devDependencies', 'peerDependencies'] as const) {
|
|
240
|
+
if (!result[field]) continue
|
|
241
|
+
for (const name of NUASITE_TOOLING) {
|
|
242
|
+
delete result[field][name]
|
|
243
|
+
}
|
|
244
|
+
if (Object.keys(result[field]).length === 0) {
|
|
245
|
+
delete result[field]
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!result.dependencies) result.dependencies = {}
|
|
250
|
+
|
|
251
|
+
for (const [name, version] of Object.entries(PACKAGES_TO_ADD)) {
|
|
252
|
+
if (result.dependencies[name]) continue
|
|
253
|
+
if (name === '@astrojs/mdx' && disabled.has('mdx')) continue
|
|
254
|
+
if (name === '@astrojs/sitemap' && disabled.has('sitemap')) continue
|
|
255
|
+
if (name === '@tailwindcss/vite' && disabled.has('tailwindcss')) continue
|
|
256
|
+
if (name === 'tailwindcss' && disabled.has('tailwindcss')) continue
|
|
257
|
+
result.dependencies[name] = version
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Promote runtime packages (e.g. @nuasite/components) — version mirrors @nuasite/nua
|
|
261
|
+
for (const name of usedRuntimePackages) {
|
|
262
|
+
if (!result.dependencies[name]) {
|
|
263
|
+
result.dependencies[name] = nuaVersion ?? '^0.16.0'
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
result.dependencies = Object.fromEntries(
|
|
268
|
+
Object.entries(result.dependencies).sort(([a], [b]) => a.localeCompare(b)),
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return result
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function scanForNuasiteUsage(cwd: string): Array<{ file: string; packages: string[] }> {
|
|
275
|
+
const srcDir = join(cwd, 'src')
|
|
276
|
+
if (!existsSync(srcDir)) return []
|
|
277
|
+
|
|
278
|
+
const results: Array<{ file: string; packages: string[] }> = []
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
const files = readdirSync(srcDir, { recursive: true })
|
|
282
|
+
for (const entry of files) {
|
|
283
|
+
const fileName = String(entry)
|
|
284
|
+
if (!/\.(astro|ts|tsx|js|jsx)$/.test(fileName)) continue
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
const content = readFileSync(join(srcDir, fileName), 'utf-8')
|
|
288
|
+
const matches = content.match(/@nuasite\/[\w-]+/g)
|
|
289
|
+
if (matches) {
|
|
290
|
+
results.push({
|
|
291
|
+
file: join('src', fileName),
|
|
292
|
+
packages: [...new Set(matches)],
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// skip unreadable files
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
// src directory not readable
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return results
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export async function clean({ cwd = process.cwd(), dryRun = false, yes = false }: CleanOptions = {}) {
|
|
307
|
+
const configPath = findAstroConfig(cwd)
|
|
308
|
+
if (!configPath) {
|
|
309
|
+
console.error('No Astro config file found.')
|
|
310
|
+
process.exit(1)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const configContent = readFileSync(configPath, 'utf-8')
|
|
314
|
+
if (!configContent.includes('@nuasite/nua')) {
|
|
315
|
+
console.log('This project does not use @nuasite/nua. Nothing to clean.')
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const pkgPath = join(cwd, 'package.json')
|
|
320
|
+
if (!existsSync(pkgPath)) {
|
|
321
|
+
console.error('No package.json found.')
|
|
322
|
+
process.exit(1)
|
|
323
|
+
}
|
|
324
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
325
|
+
|
|
326
|
+
const disabled = detectDisabledFeatures(configContent)
|
|
327
|
+
const nuasiteUsage = scanForNuasiteUsage(cwd)
|
|
328
|
+
const configName = basename(configPath)
|
|
329
|
+
|
|
330
|
+
const usedRuntimePackages = new Set<string>()
|
|
331
|
+
const toolingUsage: Array<{ file: string; packages: string[] }> = []
|
|
332
|
+
|
|
333
|
+
for (const entry of nuasiteUsage) {
|
|
334
|
+
const runtime = entry.packages.filter(p => !NUASITE_TOOLING.includes(p))
|
|
335
|
+
const tooling = entry.packages.filter(p => NUASITE_TOOLING.includes(p))
|
|
336
|
+
for (const p of runtime) usedRuntimePackages.add(p)
|
|
337
|
+
if (tooling.length > 0) {
|
|
338
|
+
toolingUsage.push({ file: entry.file, packages: tooling })
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.log('')
|
|
343
|
+
console.log('nua clean — eject to standard Astro project')
|
|
344
|
+
console.log('')
|
|
345
|
+
console.log(` ${configName}`)
|
|
346
|
+
console.log(' - Replace @nuasite/nua with explicit Astro integrations')
|
|
347
|
+
console.log(' - Add mdx, sitemap, tailwindcss imports')
|
|
348
|
+
if (disabled.size > 0) {
|
|
349
|
+
console.log(` - Skipping disabled: ${[...disabled].join(', ')}`)
|
|
350
|
+
}
|
|
351
|
+
console.log('')
|
|
352
|
+
console.log(' package.json')
|
|
353
|
+
console.log(' - Remove @nuasite/* tooling dependencies')
|
|
354
|
+
if (usedRuntimePackages.size > 0) {
|
|
355
|
+
console.log(` - Keep as explicit deps: ${[...usedRuntimePackages].join(', ')}`)
|
|
356
|
+
}
|
|
357
|
+
console.log(' - Add standard Astro packages')
|
|
358
|
+
console.log(' - Update scripts: nua → astro')
|
|
359
|
+
|
|
360
|
+
if (toolingUsage.length > 0) {
|
|
361
|
+
console.log('')
|
|
362
|
+
console.log(' Warning: @nuasite tooling imports found in source files:')
|
|
363
|
+
for (const { file, packages } of toolingUsage) {
|
|
364
|
+
console.log(` ${file} (${packages.join(', ')})`)
|
|
365
|
+
}
|
|
366
|
+
console.log(' These will need manual removal.')
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (dryRun) {
|
|
370
|
+
console.log('')
|
|
371
|
+
console.log(' (--dry-run: no changes made)')
|
|
372
|
+
console.log('')
|
|
373
|
+
return
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!yes) {
|
|
377
|
+
console.log('')
|
|
378
|
+
const answer = prompt('Proceed? [y/N] ')
|
|
379
|
+
if (answer?.toLowerCase() !== 'y') {
|
|
380
|
+
console.log('Cancelled.')
|
|
381
|
+
return
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const newConfig = transformConfig(configContent, disabled)
|
|
386
|
+
writeFileSync(configPath, newConfig)
|
|
387
|
+
console.log(` Updated ${configName}`)
|
|
388
|
+
|
|
389
|
+
const newPkg = transformPackageJson(pkg, disabled, [...usedRuntimePackages])
|
|
390
|
+
writeFileSync(pkgPath, JSON.stringify(newPkg, null, '\t') + '\n')
|
|
391
|
+
console.log(' Updated package.json')
|
|
392
|
+
|
|
393
|
+
console.log('')
|
|
394
|
+
console.log('Next steps:')
|
|
395
|
+
console.log(' 1. bun install')
|
|
396
|
+
console.log(' 2. Review the updated config')
|
|
397
|
+
console.log(' 3. astro dev')
|
|
398
|
+
if (toolingUsage.length > 0) {
|
|
399
|
+
console.log(' 4. Remove @nuasite tooling imports from source files')
|
|
400
|
+
}
|
|
401
|
+
console.log('')
|
|
402
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { agentsSummary } from '@nuasite/agent-summary'
|
|
3
3
|
import { type AstroInlineConfig, build as astroBuild, dev, preview } from 'astro'
|
|
4
4
|
import { spawn } from 'node:child_process'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { readFileSync } from 'node:fs'
|
|
6
|
+
import { findAstroConfig } from './utils'
|
|
7
7
|
|
|
8
8
|
const [, , command, ...args] = process.argv
|
|
9
9
|
|
|
@@ -16,23 +16,6 @@ function hasNuaIntegration(configPath: string): boolean {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function findAstroConfig(): string | null {
|
|
20
|
-
const possibleConfigs = [
|
|
21
|
-
'astro.config.mjs',
|
|
22
|
-
'astro.config.js',
|
|
23
|
-
'astro.config.ts',
|
|
24
|
-
'astro.config.mts',
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
for (const config of possibleConfigs) {
|
|
28
|
-
const configPath = join(process.cwd(), config)
|
|
29
|
-
if (existsSync(configPath)) {
|
|
30
|
-
return configPath
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return null
|
|
34
|
-
}
|
|
35
|
-
|
|
36
19
|
function proxyToAstroCLI(command: string, args: string[]) {
|
|
37
20
|
const astro = spawn('npx', ['astro', command, ...args], {
|
|
38
21
|
stdio: 'inherit',
|
|
@@ -52,10 +35,11 @@ function proxyToAstroCLI(command: string, args: string[]) {
|
|
|
52
35
|
function printUsage() {
|
|
53
36
|
console.log('Usage: nua <command> [options]')
|
|
54
37
|
console.log('\nCommands:')
|
|
55
|
-
console.log(' build
|
|
56
|
-
console.log('
|
|
57
|
-
console.log('
|
|
58
|
-
console.log('
|
|
38
|
+
console.log(' build Run astro build with the Nua defaults')
|
|
39
|
+
console.log(' dev Run astro dev with the Nua defaults')
|
|
40
|
+
console.log(' preview Run astro preview with the Nua defaults')
|
|
41
|
+
console.log(' clean Eject to a standard Astro project (remove @nuasite/* deps)')
|
|
42
|
+
console.log(' help Show this message')
|
|
59
43
|
console.log('\nAll Astro CLI options are supported.\n')
|
|
60
44
|
}
|
|
61
45
|
|
|
@@ -102,6 +86,15 @@ if (canProxyDirectly && command && ['build', 'dev', 'preview'].includes(command)
|
|
|
102
86
|
})
|
|
103
87
|
break
|
|
104
88
|
}
|
|
89
|
+
case 'clean': {
|
|
90
|
+
const { clean } = await import('./clean')
|
|
91
|
+
await clean({
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
dryRun: args.includes('--dry-run'),
|
|
94
|
+
yes: args.includes('--yes') || args.includes('-y'),
|
|
95
|
+
})
|
|
96
|
+
break
|
|
97
|
+
}
|
|
105
98
|
case 'help':
|
|
106
99
|
case '--help':
|
|
107
100
|
case '-h':
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
const CONFIG_NAMES = [
|
|
5
|
+
'astro.config.ts',
|
|
6
|
+
'astro.config.mts',
|
|
7
|
+
'astro.config.mjs',
|
|
8
|
+
'astro.config.js',
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
export function findAstroConfig(cwd: string = process.cwd()): string | null {
|
|
12
|
+
for (const name of CONFIG_NAMES) {
|
|
13
|
+
const p = join(cwd, name)
|
|
14
|
+
if (existsSync(p)) return p
|
|
15
|
+
}
|
|
16
|
+
return null
|
|
17
|
+
}
|