@znight/cli 0.1.3 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@znight/cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Znight CLI: scaffold projects, generate code, run dev server and builds",
5
5
  "license": "MIT",
6
6
  "author": "Ugho STEPHAN",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@clack/prompts": "^1.8.1",
44
- "@znight/core": "0.1.3",
44
+ "@znight/core": "0.2.0",
45
45
  "citty": "^0.2.2",
46
46
  "picocolors": "^1.1.1"
47
47
  },
@@ -50,14 +50,14 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "vite": "8.3.5",
53
- "@znight/compiler": "0.1.3",
54
- "@znight/openapi": "0.1.3",
55
- "@znight/schedule": "0.1.3"
53
+ "@znight/compiler": "0.2.0",
54
+ "@znight/openapi": "0.2.0",
55
+ "@znight/schedule": "0.2.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "@znight/compiler": "^0.1.3",
58
+ "@znight/compiler": "^0.2.0",
59
59
  "vite": "^8.0.0",
60
- "@znight/openapi": "^0.1.3"
60
+ "@znight/openapi": "^0.2.0"
61
61
  },
62
62
  "peerDependenciesMeta": {
63
63
  "@znight/compiler": {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * `znight generate`: writes the DI container module (`src/.znight/container.generated.ts`) with the
3
- * compiler, checks that it is up to date (`--check`, for CI) or keeps it up to date (`--watch`, for
4
- * `tsc --watch` and editors).
2
+ * `znight generate`: writes the DI container module (`src/.znight/container.generated.ts`), and the
3
+ * files compiler extensions emit with it, with the compiler, checks that they are up to date
4
+ * (`--check`, for CI) or keeps them up to date (`--watch`, for `tsc --watch` and editors).
5
5
  */
6
6
  import type { Command } from '../command.ts'
7
7
  import type { CliContext } from '../context.ts'
@@ -200,6 +200,16 @@ function staleFilesOf(result: CheckResultLike): string[] {
200
200
  return [...stale].sort((a, b) => Number(b === result.outFile) - Number(a === result.outFile))
201
201
  }
202
202
 
203
+ /**
204
+ * The hint of a missing generated file: the module, an extra file of the compiler extensions (an SDL
205
+ * schema...) or the library manifest (`dist/znight.providers.json`).
206
+ */
207
+ function missingHint(path: string, outFile: string, extraFiles: ReadonlySet<string>): string {
208
+ if (path === outFile) return 'run "znight generate" (it is git-ignored: generate it before tsc and tests)'
209
+ if (extraFiles.has(path)) return 'run "znight generate" (a compiler extension generates it from the sources)'
210
+ return 'run "znight generate" after the build: a build cleaning dist/ (tsdown, tsc --build --clean...) deletes it'
211
+ }
212
+
203
213
  async function check(cli: CliContext, compiler: CompilerApi, options: ZnightOptions): Promise<number> {
204
214
  const root = options.root ?? cli.cwd
205
215
  const started = performance.now()
@@ -211,15 +221,11 @@ async function check(cli: CliContext, compiler: CompilerApi, options: ZnightOpti
211
221
  }
212
222
  const file = displayPath(result.outFile, cli.cwd)
213
223
  const stale = staleFilesOf(result)
224
+ const extraFiles = new Set(result.extraFiles?.map(extra => extra.file))
214
225
  for (const path of stale) {
215
226
  const shown = displayPath(path, cli.cwd)
216
- // the other generated file is the library manifest (`dist/znight.providers.json`)
217
- const hint =
218
- path === result.outFile
219
- ? 'run "znight generate" (it is git-ignored: generate it before tsc and tests)'
220
- : 'run "znight generate" after the build: a build cleaning dist/ (tsdown, tsc --build --clean...) deletes it'
221
227
  if (existsSync(path)) cli.reporter.error(`${shown} is out of date`, ['run "znight generate"'])
222
- else cli.reporter.error(`${shown} is missing`, [hint])
228
+ else cli.reporter.error(`${shown} is missing`, [missingHint(path, result.outFile, extraFiles)])
223
229
  }
224
230
  if (stale.length > 0) return 1
225
231
  cli.reporter.success(
@@ -48,6 +48,13 @@ export interface ZnightOptions {
48
48
  readonly [option: string]: unknown
49
49
  }
50
50
 
51
+ /** A file emitted by a compiler extension next to the generated module (`CompileResult.extraFiles`, §6.2). */
52
+ export interface ExtraFileLike {
53
+ /** Absolute path. */
54
+ readonly file: string
55
+ readonly content: string
56
+ }
57
+
51
58
  /** What the CLI reads from a compile result (`CompileResult`, §6.2). */
52
59
  export interface CompileResultLike {
53
60
  /** Content of the generated module (with errors: a module throwing them, or empty). */
@@ -58,6 +65,8 @@ export interface CompileResultLike {
58
65
  readonly stats?: { readonly files?: number; readonly providers?: number; readonly durationMs?: number } | undefined
59
66
  /** Files the result depends on (`createCompiler()` results). */
60
67
  readonly watchFiles?: readonly string[] | undefined
68
+ /** Files emitted by compiler extensions (an SDL schema...), absent from compilers without them. */
69
+ readonly extraFiles?: readonly ExtraFileLike[] | undefined
61
70
  }
62
71
 
63
72
  /** Result of {@link CompilerApi.generate}. */
@@ -71,9 +80,9 @@ export interface CheckResultLike extends CompileResultLike {
71
80
  /** The generated files on disk are missing or differ from what would be generated. */
72
81
  readonly stale: boolean
73
82
  /**
74
- * The generated files that are missing or out of date (the module, and `znight.providers.json` in
75
- * library mode). Empty when `stale` is `false`; empty or absent with `stale` when the compiler
76
- * does not say which file is stale.
83
+ * The generated files that are missing or out of date (the module, the extra files of the
84
+ * extensions, and `znight.providers.json` in library mode). Empty when `stale` is `false`; empty or
85
+ * absent with `stale` when the compiler does not say which file is stale.
77
86
  */
78
87
  readonly staleFiles?: readonly string[] | undefined
79
88
  }
@@ -240,7 +249,10 @@ export function adaptCompilerModule(module: CompilerModule): CompilerApi {
240
249
  return written(await generate(options), before)
241
250
  }
242
251
  const result = await compileOnly(options)
243
- const changed = !hasErrors(result.diagnostics) && writeIfChanged(result.outFile, result.diskCode ?? result.code)
252
+ let changed = false
253
+ if (!hasErrors(result.diagnostics)) {
254
+ for (const output of outputsOf(result, false)) changed = writeIfChanged(output.file, output.content) || changed
255
+ }
244
256
  return { ...result, written: changed }
245
257
  }
246
258
 
@@ -285,17 +297,30 @@ export function adaptCompilerModule(module: CompilerModule): CompilerApi {
285
297
  }
286
298
 
287
299
  /**
288
- * The generated files of a compile result that differ from the disk: the module, and
289
- * `znight.providers.json` in library mode. None with errors (nothing would be written).
300
+ * The generated files of a compile result: the module, the extra files of the extensions and, with
301
+ * `library`, `znight.providers.json` in library mode (`generate()` of the compiler writes the module
302
+ * and the extra files; library mode is a compiler feature).
290
303
  */
291
- function staleOutputs(result: ModuleResult): string[] {
292
- if (hasErrors(result.diagnostics)) return []
304
+ function outputsOf(result: ModuleResult, library: boolean): { file: string; content: string }[] {
293
305
  const outputs: { file: string; content: string }[] = [
294
306
  { file: result.outFile, content: result.diskCode ?? result.code },
295
307
  ]
308
+ for (const extra of result.extraFiles ?? []) outputs.push({ file: extra.file, content: extra.content })
296
309
  const { file, content } = result.library ?? {}
297
- if (typeof file === 'string' && typeof content === 'string') outputs.push({ file, content })
298
- return outputs.filter(output => readText(output.file) !== output.content).map(output => output.file)
310
+ if (library && typeof file === 'string' && typeof content === 'string') outputs.push({ file, content })
311
+ return outputs
312
+ }
313
+
314
+ /**
315
+ * The generated files of a compile result that differ from the disk: the module, the extra files of
316
+ * the extensions and `znight.providers.json` in library mode. None with errors (nothing would be
317
+ * written).
318
+ */
319
+ function staleOutputs(result: ModuleResult): string[] {
320
+ if (hasErrors(result.diagnostics)) return []
321
+ return outputsOf(result, true)
322
+ .filter(output => readText(output.file) !== output.content)
323
+ .map(output => output.file)
299
324
  }
300
325
 
301
326
  /** Default `outFile` of the compiler (§6.2). */