@nuasite/cli 0.53.0 → 0.55.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 +51 -1
- package/dist/index.js +1263 -228
- package/dist/types/check.d.ts +9 -0
- package/dist/types/check.d.ts.map +1 -1
- package/dist/types/live-schema.d.ts +20 -0
- package/dist/types/live-schema.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/check.ts +49 -3
- package/src/index.ts +3 -10
- package/src/live-schema.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuasite/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@astrojs/compiler": "^3.0.1",
|
|
27
27
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
28
|
-
"@nuasite/cms": "0.
|
|
29
|
-
"@nuasite/cms-core": "0.
|
|
28
|
+
"@nuasite/cms": "0.55.0",
|
|
29
|
+
"@nuasite/cms-core": "0.55.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/bun": "1.3.11"
|
package/src/check.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { checkContent, type CheckReport, createNodeFs, formatCheckReport } from '@nuasite/cms-core'
|
|
1
|
+
import { checkContent, type CheckReport, createNodeFs, formatCheckReport, type LiveSchemas } from '@nuasite/cms-core'
|
|
2
2
|
import { existsSync, readdirSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { checkCode } from './check-code'
|
|
5
|
+
import { loadLiveSchemas } from './live-schema'
|
|
5
6
|
|
|
6
7
|
export interface CheckOptions {
|
|
7
8
|
cwd: string
|
|
@@ -10,6 +11,26 @@ export interface CheckOptions {
|
|
|
10
11
|
strict: boolean
|
|
11
12
|
/** Skip the code syntax pass — content only. */
|
|
12
13
|
contentOnly: boolean
|
|
14
|
+
/** Validate against the project's real schemas, which means importing and running its content config. */
|
|
15
|
+
live: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `nua check`'s argv, as options.
|
|
20
|
+
*
|
|
21
|
+
* Pure and exported so the flag combinations are testable: `index.ts` is a top-level-await
|
|
22
|
+
* script that reads `process.argv` and calls `process.exit`, so a test cannot import it.
|
|
23
|
+
*/
|
|
24
|
+
export function parseCheckArgs(args: string[], cwd: string): CheckOptions {
|
|
25
|
+
const contentOnly = args.includes('--content-only')
|
|
26
|
+
return {
|
|
27
|
+
cwd,
|
|
28
|
+
json: args.includes('--json'),
|
|
29
|
+
strict: args.includes('--strict'),
|
|
30
|
+
contentOnly,
|
|
31
|
+
// Loading the real schemas executes the project's content config — the least content-only thing this command does.
|
|
32
|
+
live: !contentOnly && !args.includes('--no-live'),
|
|
33
|
+
}
|
|
13
34
|
}
|
|
14
35
|
|
|
15
36
|
const ASTRO_CONFIG_NAMES = ['astro.config.ts', 'astro.config.mts', 'astro.config.mjs', 'astro.config.js']
|
|
@@ -47,6 +68,25 @@ function prefixed(report: CheckReport, root: string): CheckReport {
|
|
|
47
68
|
}
|
|
48
69
|
}
|
|
49
70
|
|
|
71
|
+
/** The project's real schemas, or the sentence saying why the rules needing them did not run. */
|
|
72
|
+
type LiveResult = { schemas: LiveSchemas } | { skipped: string }
|
|
73
|
+
|
|
74
|
+
async function liveSchemasFor(options: CheckOptions, roots: string[]): Promise<LiveResult> {
|
|
75
|
+
if (options.contentOnly) {
|
|
76
|
+
return { skipped: "--content-only was passed, and reading the real schemas means executing the project's content config." }
|
|
77
|
+
}
|
|
78
|
+
if (!options.live) return { skipped: '--no-live was passed.' }
|
|
79
|
+
|
|
80
|
+
const first = roots[0]
|
|
81
|
+
// The `astro:content` stub is process-global and re-exports one project's zod, so a second
|
|
82
|
+
// project would be judged by the first project's schemas — quietly wrong is worse than skipped.
|
|
83
|
+
if (roots.length !== 1 || first === undefined) {
|
|
84
|
+
const where = roots.join(', ')
|
|
85
|
+
return { skipped: `They need exactly one Astro project; this run covers ${roots.length} (${where}). Check each one from its own directory.` }
|
|
86
|
+
}
|
|
87
|
+
return loadLiveSchemas(path.join(options.cwd, first))
|
|
88
|
+
}
|
|
89
|
+
|
|
50
90
|
/** Validate the content collections and return the process exit code. */
|
|
51
91
|
export async function check(options: CheckOptions): Promise<number> {
|
|
52
92
|
const roots = astroRoots(options.cwd)
|
|
@@ -56,9 +96,12 @@ export async function check(options: CheckOptions): Promise<number> {
|
|
|
56
96
|
return 1
|
|
57
97
|
}
|
|
58
98
|
|
|
99
|
+
const live = await liveSchemasFor(options, roots)
|
|
100
|
+
const schemas = 'schemas' in live ? live.schemas : undefined
|
|
101
|
+
|
|
59
102
|
const reports = await Promise.all(roots.map(async root => {
|
|
60
103
|
const absolute = path.join(options.cwd, root)
|
|
61
|
-
const content = prefixed(await checkContent(createNodeFs(absolute)), root)
|
|
104
|
+
const content = prefixed(await checkContent(createNodeFs(absolute), schemas ? { schemas } : {}), root)
|
|
62
105
|
if (options.contentOnly) return { ...content, files: 0 }
|
|
63
106
|
const code = await checkCode(absolute)
|
|
64
107
|
return {
|
|
@@ -79,7 +122,8 @@ export async function check(options: CheckOptions): Promise<number> {
|
|
|
79
122
|
const warnings = report.findings.length - errors
|
|
80
123
|
|
|
81
124
|
if (options.json) {
|
|
82
|
-
|
|
125
|
+
// The reason belongs inside the payload: a stray line would break anything parsing this.
|
|
126
|
+
console.log(JSON.stringify({ ...report, roots, liveSchemas: 'schemas' in live ? 'ran' : live.skipped }, null, 2))
|
|
83
127
|
} else {
|
|
84
128
|
const formatted = formatCheckReport(report)
|
|
85
129
|
if (formatted) console.log(formatted + '\n')
|
|
@@ -87,6 +131,8 @@ export async function check(options: CheckOptions): Promise<number> {
|
|
|
87
131
|
const code = options.contentOnly ? '' : `, ${sourceFiles} source file(s)`
|
|
88
132
|
const counts = `${report.collections} collection(s), ${report.entries} entries${code}${where}`
|
|
89
133
|
console.log(errors === 0 && warnings === 0 ? `${counts} — no problems found` : `${counts} — ${errors} error(s), ${warnings} warning(s)`)
|
|
134
|
+
// A check that did not run must not read as a pass.
|
|
135
|
+
if ('skipped' in live) console.log(`Live schema rules did not run: ${live.skipped}`)
|
|
90
136
|
}
|
|
91
137
|
|
|
92
138
|
return errors > 0 || (options.strict && warnings > 0) ? 1 : 0
|
package/src/index.ts
CHANGED
|
@@ -25,7 +25,7 @@ function printUsage() {
|
|
|
25
25
|
console.log(' build Run astro build with the Nua defaults')
|
|
26
26
|
console.log(' dev Run astro dev with the Nua defaults')
|
|
27
27
|
console.log(' preview Run astro preview with the Nua defaults')
|
|
28
|
-
console.log(' check Validate collections and parse the source (no build). --json, --strict, --content-only')
|
|
28
|
+
console.log(' check Validate collections and parse the source (no build). --json, --strict, --content-only, --no-live')
|
|
29
29
|
console.log(' init Convert a standard Astro project to use Nua')
|
|
30
30
|
console.log(' clean Eject to a standard Astro project (remove @nuasite/* deps)')
|
|
31
31
|
console.log(' migrate <target> Run a content migration. Targets: astro-image')
|
|
@@ -38,15 +38,8 @@ if (command && ['build', 'dev', 'preview'].includes(command)) {
|
|
|
38
38
|
} else {
|
|
39
39
|
switch (command) {
|
|
40
40
|
case 'check': {
|
|
41
|
-
const { check } = await import('./check')
|
|
42
|
-
process.exit(
|
|
43
|
-
await check({
|
|
44
|
-
cwd: process.cwd(),
|
|
45
|
-
json: args.includes('--json'),
|
|
46
|
-
strict: args.includes('--strict'),
|
|
47
|
-
contentOnly: args.includes('--content-only'),
|
|
48
|
-
}),
|
|
49
|
-
)
|
|
41
|
+
const { check, parseCheckArgs } = await import('./check')
|
|
42
|
+
process.exit(await check(parseCheckArgs(args, process.cwd())))
|
|
50
43
|
break
|
|
51
44
|
}
|
|
52
45
|
case 'init': {
|
|
Binary file
|