@pagopa/dx-cli 0.21.6 → 0.22.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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tests for the CLI environment schema.
3
+ * Validates that `cliEnvSchema` correctly parses `process.env`.
4
+ */
5
+ import { afterEach, describe, expect, it, vi } from "vitest";
6
+ import { cliEnvSchema } from "../env.js";
7
+ describe("cliEnvSchema", () => {
8
+ afterEach(() => {
9
+ vi.unstubAllEnvs();
10
+ });
11
+ describe("CI field", () => {
12
+ it("is undefined when CI is not set", () => {
13
+ vi.stubEnv("CI", undefined);
14
+ const result = cliEnvSchema.safeParse(process.env);
15
+ expect(result.success).toBe(true);
16
+ expect(result.success && result.data.CI).toBeUndefined();
17
+ });
18
+ it("captures any non-empty CI value", () => {
19
+ vi.stubEnv("CI", "true");
20
+ const result = cliEnvSchema.safeParse(process.env);
21
+ expect(result.success).toBe(true);
22
+ expect(result.success && result.data.CI).toBe("true");
23
+ });
24
+ it("captures CI=false as a string (presence is the signal, not the value)", () => {
25
+ vi.stubEnv("CI", "false");
26
+ const result = cliEnvSchema.safeParse(process.env);
27
+ expect(result.success).toBe(true);
28
+ expect(result.success && result.data.CI).toBe("false");
29
+ });
30
+ it("captures CI=1 for numeric-style env vars", () => {
31
+ vi.stubEnv("CI", "1");
32
+ const result = cliEnvSchema.safeParse(process.env);
33
+ expect(result.success).toBe(true);
34
+ expect(result.success && result.data.CI).toBe("1");
35
+ });
36
+ });
37
+ it("passes through an object with unrelated env keys without failing", () => {
38
+ vi.stubEnv("CI", "true");
39
+ const result = cliEnvSchema.safeParse(process.env);
40
+ expect(result.success).toBe(true);
41
+ expect(result.success && result.data.CI).toBe("true");
42
+ });
43
+ });
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { mock } from "vitest-mock-extended";
3
+ import { makeCli } from "../index.js";
4
+ const makeProgram = (argv) => {
5
+ const program = makeCli(mock(), mock(), mock(), "0.0.0");
6
+ program.exitOverride().configureOutput({
7
+ writeErr: () => {
8
+ /* silence stderr in tests */
9
+ },
10
+ writeOut: () => {
11
+ /* silence stdout in tests */
12
+ },
13
+ });
14
+ program.parseOptions(argv);
15
+ return program;
16
+ };
17
+ describe("--output option", () => {
18
+ it("defaults to 'text' when not provided", () => {
19
+ const program = makeProgram([]);
20
+ expect(program.opts().output).toBe("text");
21
+ });
22
+ it("accepts 'text' explicitly", () => {
23
+ const program = makeProgram(["--output", "text"]);
24
+ expect(program.opts().output).toBe("text");
25
+ });
26
+ it("accepts 'json'", () => {
27
+ const program = makeProgram(["--output", "json"]);
28
+ expect(program.opts().output).toBe("json");
29
+ });
30
+ it("rejects invalid values", () => {
31
+ expect(() => makeProgram(["--output", "xml"])).toThrow();
32
+ });
33
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Zod schema for the CLI environment variables.
3
+ *
4
+ * Intended to centralize env parsing at the entrypoint (`src/index.ts`),
5
+ * which will parse the raw environment once and pass the validated result as
6
+ * `CliEnv` to every command. This keeps env-var reads out of use-cases and
7
+ * adapters and makes them fully testable.
8
+ */
9
+ import { z } from "zod";
10
+ export declare const cliEnvSchema: z.ZodObject<{
11
+ CI: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$loose>;
13
+ export type CliEnv = z.infer<typeof cliEnvSchema>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Zod schema for the CLI environment variables.
3
+ *
4
+ * Intended to centralize env parsing at the entrypoint (`src/index.ts`),
5
+ * which will parse the raw environment once and pass the validated result as
6
+ * `CliEnv` to every command. This keeps env-var reads out of use-cases and
7
+ * adapters and makes them fully testable.
8
+ */
9
+ import { z } from "zod";
10
+ export const cliEnvSchema = z
11
+ .object({
12
+ // Standard CI marker. Presence (any string value) signals an automated
13
+ // pipeline where interactive prompts must not block. Follows the same
14
+ // convention used by `is-interactive` and `ora`.
15
+ CI: z.string().optional(),
16
+ })
17
+ .loose();
@@ -4,6 +4,7 @@ import { Dependencies } from "../../domain/dependencies.js";
4
4
  import { CodemodCommandDependencies } from "./commands/codemod.js";
5
5
  export type CliDependencies = CodemodCommandDependencies;
6
6
  export type GlobalOptions = {
7
+ output: "json" | "text";
7
8
  verbose?: boolean;
8
9
  };
9
10
  /**
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import { Command, Option } from "commander";
2
2
  import { makeAddCommand } from "./commands/add.js";
3
3
  import { makeCodemodCommand, } from "./commands/codemod.js";
4
4
  import { makeDoctorCommand } from "./commands/doctor.js";
@@ -17,7 +17,10 @@ export const makeCli = (deps, config, cliDeps, version) => {
17
17
  .name("dx")
18
18
  .description("The CLI for DX-Platform")
19
19
  .version(version)
20
- .option("-v, --verbose", "Enable verbose output: debug-level logs and full error chain (with stack traces) when a command fails", false);
20
+ .option("-v, --verbose", "Enable verbose output: debug-level logs and full error chain (with stack traces) when a command fails", false)
21
+ .addOption(new Option("--output <mode>", "Output mode: 'text' (human-readable, default) or 'json' (structured JSON envelope on stdout, NDJSON progress events on stderr)")
22
+ .choices(["text", "json"])
23
+ .default("text"));
21
24
  program.addCommand(makeDoctorCommand(deps, config));
22
25
  program.addCommand(makeCodemodCommand(cliDeps));
23
26
  program.addCommand(makeInitCommand(deps));
@@ -0,0 +1,26 @@
1
+ /**
2
+ * CommandPresenter — domain port for all CLI output.
3
+ *
4
+ * Use-cases depend on this interface, not on any concrete output mechanism.
5
+ * Concrete implementations are injected at the entry point.
6
+ *
7
+ * The interface deliberately does NOT handle process exit: callers report the
8
+ * error through `reportError`, then let the host terminate the process with
9
+ * the appropriate exit code.
10
+ */
11
+ export interface CommandPresenter {
12
+ /**
13
+ * Formats and emits the error.
14
+ * Does NOT exit the process — that responsibility belongs to the host
15
+ * after this returns.
16
+ */
17
+ reportError(error: unknown): void;
18
+ /**
19
+ * Emits the final successful result.
20
+ */
21
+ reportResult<T>(data: T): void;
22
+ /**
23
+ * Tracks `task` while emitting start/end lifecycle events for the named step.
24
+ */
25
+ trackStep<T>(name: string, task: () => Promise<T>): Promise<T>;
26
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CommandPresenter — domain port for all CLI output.
3
+ *
4
+ * Use-cases depend on this interface, not on any concrete output mechanism.
5
+ * Concrete implementations are injected at the entry point.
6
+ *
7
+ * The interface deliberately does NOT handle process exit: callers report the
8
+ * error through `reportError`, then let the host terminate the process with
9
+ * the appropriate exit code.
10
+ */
11
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.21.6",
3
+ "version": "0.22.1",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "semver": "^7.7.4",
49
49
  "yaml": "^2.8.4",
50
50
  "zod": "^4.4.2",
51
- "@pagopa/dx-savemoney": "^0.2.5"
51
+ "@pagopa/dx-savemoney": "^0.2.6"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@tsconfig/node24": "24.0.4",