@pagopa/dx-cli 0.23.0 → 0.23.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.
Files changed (98) hide show
  1. package/package.json +5 -5
  2. package/templates/monorepo/nx.json +0 -1
  3. package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +0 -1
  4. package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +0 -95
  5. package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +0 -1
  6. package/dist/adapters/azure/__tests__/cloud-account-service.test.js +0 -378
  7. package/dist/adapters/codemods/__tests__/registry.test.d.ts +0 -1
  8. package/dist/adapters/codemods/__tests__/registry.test.js +0 -56
  9. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +0 -1
  10. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +0 -77
  11. package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +0 -1
  12. package/dist/adapters/codemods/__tests__/use-pnpm.test.js +0 -148
  13. package/dist/adapters/commander/__tests__/env.test.d.ts +0 -1
  14. package/dist/adapters/commander/__tests__/env.test.js +0 -45
  15. package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +0 -1
  16. package/dist/adapters/commander/__tests__/error-reporting.test.js +0 -63
  17. package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +0 -1
  18. package/dist/adapters/commander/__tests__/exit-with-error.test.js +0 -92
  19. package/dist/adapters/commander/__tests__/global-options.test.d.ts +0 -1
  20. package/dist/adapters/commander/__tests__/global-options.test.js +0 -33
  21. package/dist/adapters/commander/__tests__/spec.test.d.ts +0 -8
  22. package/dist/adapters/commander/__tests__/spec.test.js +0 -264
  23. package/dist/adapters/commander/commands/__tests__/add.test.d.ts +0 -4
  24. package/dist/adapters/commander/commands/__tests__/add.test.js +0 -167
  25. package/dist/adapters/commander/commands/__tests__/init-command.test.d.ts +0 -4
  26. package/dist/adapters/commander/commands/__tests__/init-command.test.js +0 -44
  27. package/dist/adapters/commander/commands/__tests__/init.test.d.ts +0 -4
  28. package/dist/adapters/commander/commands/__tests__/init.test.js +0 -48
  29. package/dist/adapters/commander/commands/__tests__/preconditions.test.d.ts +0 -1
  30. package/dist/adapters/commander/commands/__tests__/preconditions.test.js +0 -32
  31. package/dist/adapters/commander/commands/__tests__/savemoney.test.d.ts +0 -8
  32. package/dist/adapters/commander/commands/__tests__/savemoney.test.js +0 -60
  33. package/dist/adapters/commander/commands/__tests__/spec.test.d.ts +0 -7
  34. package/dist/adapters/commander/commands/__tests__/spec.test.js +0 -85
  35. package/dist/adapters/commander/presenters/__tests__/index.test.d.ts +0 -1
  36. package/dist/adapters/commander/presenters/__tests__/index.test.js +0 -23
  37. package/dist/adapters/commander/presenters/__tests__/json.test.d.ts +0 -1
  38. package/dist/adapters/commander/presenters/__tests__/json.test.js +0 -108
  39. package/dist/adapters/commander/presenters/__tests__/text.test.d.ts +0 -1
  40. package/dist/adapters/commander/presenters/__tests__/text.test.js +0 -60
  41. package/dist/adapters/github/__tests__/github-repo.spec.d.ts +0 -1
  42. package/dist/adapters/github/__tests__/github-repo.spec.js +0 -67
  43. package/dist/adapters/node/__tests__/data.d.ts +0 -18
  44. package/dist/adapters/node/__tests__/data.js +0 -22
  45. package/dist/adapters/node/__tests__/package-json.test.d.ts +0 -1
  46. package/dist/adapters/node/__tests__/package-json.test.js +0 -86
  47. package/dist/adapters/node/__tests__/repository.test.d.ts +0 -1
  48. package/dist/adapters/node/__tests__/repository.test.js +0 -77
  49. package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +0 -1
  50. package/dist/adapters/node/fs/__tests__/file-reader.test.js +0 -80
  51. package/dist/adapters/node/json/__tests__/index.test.d.ts +0 -1
  52. package/dist/adapters/node/json/__tests__/index.test.js +0 -14
  53. package/dist/adapters/octokit/__tests__/index.test.d.ts +0 -1
  54. package/dist/adapters/octokit/__tests__/index.test.js +0 -414
  55. package/dist/adapters/pagopa-technology/__tests__/authorization.test.d.ts +0 -4
  56. package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +0 -548
  57. package/dist/adapters/plop/__tests__/run-actions.test.d.ts +0 -1
  58. package/dist/adapters/plop/__tests__/run-actions.test.js +0 -68
  59. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +0 -1
  60. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +0 -171
  61. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +0 -1
  62. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +0 -134
  63. package/dist/adapters/plop/generators/__tests__/temp-dir.d.ts +0 -2
  64. package/dist/adapters/plop/generators/__tests__/temp-dir.js +0 -13
  65. package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +0 -2
  66. package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +0 -92
  67. package/dist/adapters/plop/generators/environment/__tests__/generation.test.d.ts +0 -1
  68. package/dist/adapters/plop/generators/environment/__tests__/generation.test.js +0 -213
  69. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.d.ts +0 -1
  70. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
  71. package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.d.ts +0 -1
  72. package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.js +0 -79
  73. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +0 -1
  74. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +0 -113
  75. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.d.ts +0 -1
  76. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.js +0 -35
  77. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.d.ts +0 -1
  78. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.js +0 -60
  79. package/dist/adapters/yaml/__tests__/index.test.d.ts +0 -1
  80. package/dist/adapters/yaml/__tests__/index.test.js +0 -53
  81. package/dist/domain/__tests__/data.d.ts +0 -15
  82. package/dist/domain/__tests__/data.js +0 -26
  83. package/dist/domain/__tests__/environment.test.d.ts +0 -1
  84. package/dist/domain/__tests__/environment.test.js +0 -332
  85. package/dist/domain/__tests__/info.test.d.ts +0 -1
  86. package/dist/domain/__tests__/info.test.js +0 -77
  87. package/dist/domain/__tests__/package-json.test.d.ts +0 -1
  88. package/dist/domain/__tests__/package-json.test.js +0 -39
  89. package/dist/domain/__tests__/repository.test.d.ts +0 -1
  90. package/dist/domain/__tests__/repository.test.js +0 -111
  91. package/dist/domain/__tests__/workspace.test.d.ts +0 -1
  92. package/dist/domain/__tests__/workspace.test.js +0 -57
  93. package/dist/use-cases/__tests__/apply-codemod.test.d.ts +0 -1
  94. package/dist/use-cases/__tests__/apply-codemod.test.js +0 -71
  95. package/dist/use-cases/__tests__/list-codemods.test.d.ts +0 -1
  96. package/dist/use-cases/__tests__/list-codemods.test.js +0 -37
  97. package/dist/use-cases/__tests__/request-authorization.test.d.ts +0 -4
  98. package/dist/use-cases/__tests__/request-authorization.test.js +0 -43
@@ -1,148 +0,0 @@
1
- import { beforeEach, describe, expect, test, vi } from "vitest";
2
- import YAML from "yaml";
3
- import { extractPackageExtensions, NPM, preparePackageJsonForPnpm, usePnpm, writePnpmWorkspaceFile, Yarn, } from "../use-pnpm.js";
4
- const { readFile, stdout, writeFile } = vi.hoisted(() => ({
5
- readFile: vi.fn(async () => ""),
6
- stdout: vi.fn(),
7
- writeFile: vi.fn(),
8
- }));
9
- vi.mock("execa", () => ({
10
- $: vi.fn((opts) => {
11
- const hasOptions = typeof opts === "object" && Object.hasOwn(opts, "lines");
12
- if (hasOptions) {
13
- return () => stdout().then((output) => ({
14
- stdout: output.split("\n"),
15
- }));
16
- }
17
- return stdout().then((output) => ({
18
- stdout: output,
19
- }));
20
- }),
21
- }));
22
- vi.mock("node:fs/promises", () => ({
23
- default: {
24
- appendFile: () => Promise.resolve(),
25
- readFile,
26
- rm: () => Promise.resolve(),
27
- stat: () => Promise.resolve({
28
- isFile: () => true,
29
- }),
30
- writeFile,
31
- },
32
- }));
33
- vi.mock("../git.js", async () => ({
34
- getLatestCommitShaOrRef: async () => "dummy-sha",
35
- }));
36
- describe("pm", () => {
37
- test("yarn workspaces are parsed correctly", async () => {
38
- const yarn = new Yarn();
39
- stdout.mockResolvedValueOnce(`{"location":".","name":"io-messages"}\n{"location":"apps/citizen-func","name":"citizen-func"}`);
40
- const workspaces = await yarn.listWorkspaces();
41
- expect(workspaces).toEqual(["io-messages", "citizen-func"]);
42
- });
43
- test("npm workspaces are parsed correctly", async () => {
44
- const npm = new NPM();
45
- stdout.mockResolvedValueOnce(`[{ "name": "io-messages", "location": "." },{ "name": "citizen-func", "location": "apps/citizen-func" }]`);
46
- const workspaces = await npm.listWorkspaces();
47
- expect(workspaces).toEqual(["io-messages", "citizen-func"]);
48
- });
49
- });
50
- describe("extractPackageExtensions", () => {
51
- beforeEach(() => {
52
- vi.clearAllMocks();
53
- });
54
- test("returns packageExtensions only if present", async () => {
55
- const yarnrc = {
56
- packageExtensions: {
57
- "some-package@*": {
58
- peerDependencies: {
59
- react: "*",
60
- },
61
- },
62
- },
63
- };
64
- readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
65
- await expect(extractPackageExtensions()).resolves.toEqual(yarnrc.packageExtensions);
66
- expect(readFile).toHaveBeenCalledOnce();
67
- });
68
- test("returns undefined if packageExtensions is not present", async () => {
69
- const yarnrc = {
70
- someOtherField: {},
71
- };
72
- readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
73
- await expect(extractPackageExtensions()).resolves.toBeUndefined();
74
- expect(readFile).toHaveBeenCalledOnce();
75
- });
76
- });
77
- describe("preparePackageJsonForPnpm", () => {
78
- beforeEach(() => {
79
- vi.clearAllMocks();
80
- });
81
- test("removes packageManager field and keeps workspaces", async () => {
82
- const packageJson = {
83
- name: "test-monorepo",
84
- packageManager: "yarn@1.22.10",
85
- version: "1.0.0",
86
- workspaces: ["packages/*"],
87
- };
88
- readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
89
- const workspaces = await preparePackageJsonForPnpm();
90
- expect(workspaces).toEqual(["packages/*"]);
91
- expect(readFile).toHaveBeenCalledOnce();
92
- expect(writeFile).toHaveBeenCalledWith("package.json", JSON.stringify({
93
- name: packageJson.name,
94
- version: packageJson.version,
95
- }, null, 2));
96
- });
97
- });
98
- describe("writePnpmWorkspaceFile", () => {
99
- beforeEach(() => {
100
- vi.clearAllMocks();
101
- });
102
- test("writes pnpm-workspace.yaml with given workspaces", async () => {
103
- const workspaces = ["packages/*", "apps/*"];
104
- const packageExtensions = {
105
- "express@*": {
106
- peerDependencies: {
107
- typescript: "*",
108
- },
109
- },
110
- };
111
- await writePnpmWorkspaceFile(workspaces, packageExtensions);
112
- expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packages: workspaces })), "utf-8");
113
- expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packageExtensions })), "utf-8");
114
- });
115
- });
116
- describe("usePnpm", () => {
117
- beforeEach(() => {
118
- vi.resetAllMocks();
119
- });
120
- test("rejects if the project is already using pnpm", async () => {
121
- await expect(usePnpm("pnpm", "10.20")).rejects.toThrow();
122
- });
123
- test.each([
124
- { expected: false, version: "18.0.0" },
125
- { expected: false, version: "20.10.0" },
126
- { expected: false, version: "20.19.4" },
127
- { expected: true, version: "22.0.0" },
128
- { expected: true, version: "20.19.5" },
129
- ])("rejects if Node.js version is less than required ($version)", async ({ expected, version }) => {
130
- stdout.mockResolvedValue("[]");
131
- readFile.mockResolvedValueOnce(JSON.stringify({ name: "test-monorepo", workspaces: [] }));
132
- await expect(usePnpm("npm", version).then(() => true, () => false)).resolves.toBe(expected);
133
- });
134
- test("moves workspaces from package.json to pnpm-workspace.yaml", async () => {
135
- const packageJson = {
136
- name: "test-monorepo",
137
- packageManager: "yarn@1.22.10",
138
- version: "1.0.0",
139
- workspaces: ["packages/*"],
140
- };
141
- readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
142
- stdout.mockResolvedValue(`[]`); // npm list workspaces
143
- await usePnpm("npm", "22.0.0");
144
- expect(writeFile).toHaveBeenNthCalledWith(2, "pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({
145
- packages: packageJson.workspaces,
146
- })), "utf-8");
147
- });
148
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,45 +0,0 @@
1
- import fc from "fast-check";
2
- /**
3
- * Tests for the CLI environment schema.
4
- * Validates that `cliEnvSchema` correctly parses `process.env`.
5
- */
6
- import { afterEach, describe, expect, it, vi } from "vitest";
7
- import { z } from "zod";
8
- import { cliEnvSchema } from "../env.js";
9
- // The accepted stringbool values mirror those recognised by z.stringbool().
10
- const CI_TRUTHY = ["true", "1", "yes", "y", "on"];
11
- const CI_FALSEY = ["false", "0", "no", "n", "off"];
12
- const CI_ACCEPTED = [...CI_TRUTHY, ...CI_FALSEY];
13
- describe("cliEnvSchema", () => {
14
- afterEach(() => {
15
- vi.unstubAllEnvs();
16
- });
17
- describe("CI field", () => {
18
- it("should be true for truthy string-bool values", () => {
19
- fc.assert(fc.property(fc.constantFrom(...CI_TRUTHY), (value) => {
20
- vi.stubEnv("CI", value);
21
- const result = cliEnvSchema.safeParse(process.env);
22
- expect(result.success).toBe(true);
23
- expect(result.success && result.data.CI).toBe(true);
24
- }));
25
- });
26
- it("should be false for falsey string-bool values or when unset", () => {
27
- fc.assert(fc.property(fc.constantFrom(...CI_FALSEY, undefined), (value) => {
28
- vi.stubEnv("CI", value);
29
- const result = cliEnvSchema.safeParse(process.env);
30
- expect(result.success).toBe(true);
31
- expect(result.success && result.data.CI).toBe(false);
32
- }));
33
- });
34
- it("should not parse unrecognised values", () => {
35
- fc.assert(fc.property(
36
- // Every string not in the accepted list
37
- fc.string().filter((s) => !CI_ACCEPTED.includes(s.toLowerCase())), (value) => {
38
- vi.stubEnv("CI", value);
39
- const result = cliEnvSchema.safeParse(process.env);
40
- expect(result.success).toBe(false);
41
- expect(result.error).toBeInstanceOf(z.ZodError);
42
- }));
43
- });
44
- });
45
- });
@@ -1,63 +0,0 @@
1
- import { ExecaError } from "execa";
2
- import { describe, expect, it } from "vitest";
3
- import { formatErrorDetailed, toErrorMessage } from "../error-reporting.js";
4
- describe("toErrorMessage", () => {
5
- it("returns the string as-is when given a string", () => {
6
- expect(toErrorMessage("oops")).toBe("oops");
7
- });
8
- it("returns 'Unknown error' for null/undefined", () => {
9
- expect(toErrorMessage(null)).toBe("Unknown error");
10
- expect(toErrorMessage(undefined)).toBe("Unknown error");
11
- });
12
- it("returns Error.message when given a plain Error", () => {
13
- expect(toErrorMessage(new Error("boom"))).toBe("boom");
14
- });
15
- it("prefers ExecaError.shortMessage over message", () => {
16
- const execaError = Object.assign(Object.create(ExecaError.prototype), {
17
- message: "long noisy message with stderr",
18
- shortMessage: "Command failed: terraform init",
19
- });
20
- expect(toErrorMessage(execaError)).toBe("Command failed: terraform init");
21
- });
22
- it("flattens AggregateError into a bulleted message", () => {
23
- const aggregate = new AggregateError([new Error("first"), new Error("second")], "parent");
24
- expect(toErrorMessage(aggregate)).toBe("parent\n - first\n - second");
25
- });
26
- it("extracts `message` property from plain objects when present", () => {
27
- expect(toErrorMessage({ message: "from object" })).toBe("from object");
28
- });
29
- it("falls back to JSON.stringify for objects without message", () => {
30
- expect(toErrorMessage({ code: 42 })).toBe('{"code":42}');
31
- });
32
- });
33
- describe("formatErrorDetailed", () => {
34
- it("renders name, message and stack for a single error", () => {
35
- const err = new Error("top");
36
- const formatted = formatErrorDetailed(err);
37
- expect(formatted).toContain("Error: top");
38
- expect(formatted).toContain("at ");
39
- });
40
- it("walks the cause chain", () => {
41
- const root = new Error("root failure");
42
- const middle = new Error("middle", { cause: root });
43
- const top = new Error("top", { cause: middle });
44
- const formatted = formatErrorDetailed(top);
45
- expect(formatted).toContain("Error: top");
46
- expect(formatted).toContain("Caused by: Error: middle");
47
- expect(formatted).toContain("Caused by: Error: root failure");
48
- });
49
- it("terminates when encountering a cycle in the cause chain", () => {
50
- const a = new Error("a");
51
- const b = new Error("b", { cause: a });
52
- a.cause = b;
53
- const formatted = formatErrorDetailed(a);
54
- expect(formatted).toContain("Error: a");
55
- expect(formatted).toContain("Caused by: Error: b");
56
- });
57
- it("handles non-Error causes gracefully", () => {
58
- const err = new Error("wrapped", { cause: "raw string cause" });
59
- const formatted = formatErrorDetailed(err);
60
- expect(formatted).toContain("Error: wrapped");
61
- expect(formatted).toContain("Caused by: raw string cause");
62
- });
63
- });
@@ -1,92 +0,0 @@
1
- import { Command } from "commander";
2
- import { describe, expect, it } from "vitest";
3
- import { exitWithError, isVerbose } from "../index.js";
4
- /**
5
- * Builds a parent command that exposes the global `--verbose` flag so that
6
- * `optsWithGlobals()` behaves the same way it does on the real CLI.
7
- */
8
- const makeProgramWith = (child, argv) => {
9
- const program = new Command()
10
- .name("dx")
11
- .option("-v, --verbose", "verbose output", false)
12
- .exitOverride()
13
- .configureOutput({
14
- writeErr: () => {
15
- /* silence stderr in tests */
16
- },
17
- writeOut: () => {
18
- /* silence stdout in tests */
19
- },
20
- });
21
- child.exitOverride().configureOutput({
22
- writeErr: () => {
23
- /* silence */
24
- },
25
- writeOut: () => {
26
- /* silence */
27
- },
28
- });
29
- program.addCommand(child);
30
- program.parse(argv, { from: "user" });
31
- return program;
32
- };
33
- /**
34
- * `exitWithError` always throws (Commander's `exitOverride()` converts the
35
- * process.exit call into a CommanderError throw). This helper captures that
36
- * throw so tests can assert on the thrown payload without putting `expect`
37
- * inside a `catch` block (which vitest/no-conditional-expect disallows).
38
- */
39
- const captureThrown = (fn) => {
40
- try {
41
- fn();
42
- }
43
- catch (error) {
44
- return error;
45
- }
46
- throw new Error("expected the callback to throw");
47
- };
48
- describe("isVerbose", () => {
49
- it("is false when --verbose is not provided", () => {
50
- const cmd = new Command("run").action(() => undefined);
51
- makeProgramWith(cmd, ["run"]);
52
- expect(isVerbose(cmd)).toBe(false);
53
- });
54
- it("is true when -v is provided at the root", () => {
55
- const cmd = new Command("run").action(() => undefined);
56
- makeProgramWith(cmd, ["-v", "run"]);
57
- expect(isVerbose(cmd)).toBe(true);
58
- });
59
- it("is true when --verbose is provided at the root", () => {
60
- const cmd = new Command("run").action(() => undefined);
61
- makeProgramWith(cmd, ["--verbose", "run"]);
62
- expect(isVerbose(cmd)).toBe(true);
63
- });
64
- });
65
- describe("exitWithError", () => {
66
- it("reports only the message in normal mode", () => {
67
- const cmd = new Command("run").action(() => undefined);
68
- makeProgramWith(cmd, ["run"]);
69
- const err = new Error("outer", { cause: new Error("inner secret") });
70
- expect(() => exitWithError(cmd)(err)).toThrow(/outer/);
71
- const thrown = captureThrown(() => exitWithError(cmd)(err));
72
- const message = String(thrown?.message ?? thrown);
73
- expect(message).not.toContain("Caused by");
74
- expect(message).not.toContain("inner secret");
75
- });
76
- it("includes the cause chain and stack trace in verbose mode", () => {
77
- const cmd = new Command("run").action(() => undefined);
78
- makeProgramWith(cmd, ["--verbose", "run"]);
79
- const root = new Error("root cause");
80
- const err = new Error("surface", { cause: root });
81
- const thrown = captureThrown(() => exitWithError(cmd)(err));
82
- const message = String(thrown?.message ?? thrown);
83
- expect(message).toContain("Error: surface");
84
- expect(message).toContain("Caused by: Error: root cause");
85
- expect(message).toContain("at ");
86
- });
87
- it("works with non-Error values", () => {
88
- const cmd = new Command("run").action(() => undefined);
89
- makeProgramWith(cmd, ["run"]);
90
- expect(() => exitWithError(cmd)("plain string failure")).toThrow(/plain string failure/);
91
- });
92
- });
@@ -1,33 +0,0 @@
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
- });
@@ -1,8 +0,0 @@
1
- /**
2
- * Tests for the Commander spec adapter.
3
- *
4
- * Verifies that `extractCliSpec` correctly maps Commander's internal command
5
- * tree to the `CliSpec` domain type, covering options, arguments, and nested
6
- * subcommands.
7
- */
8
- export {};
@@ -1,264 +0,0 @@
1
- /**
2
- * Tests for the Commander spec adapter.
3
- *
4
- * Verifies that `extractCliSpec` correctly maps Commander's internal command
5
- * tree to the `CliSpec` domain type, covering options, arguments, and nested
6
- * subcommands.
7
- */
8
- import { Argument, Command, Option } from "commander";
9
- import { describe, expect, it } from "vitest";
10
- import { extractCliSpec } from "../spec.js";
11
- const buildRoot = () => new Command("dx")
12
- .description("The CLI for DX-Platform")
13
- .version("1.2.3")
14
- .addOption(new Option("-v, --verbose", "Enable verbose output").default(false))
15
- .addOption(new Option("--output <mode>", "Output mode")
16
- .choices(["text", "json"])
17
- .default("text"));
18
- const registerRootMetadataAndGlobalOptionTests = () => {
19
- describe("root metadata and global options", () => {
20
- it("maps the root command name, description and version", () => {
21
- const root = buildRoot();
22
- const spec = extractCliSpec(root, "1.2.3");
23
- expect(spec).toMatchObject({
24
- description: "The CLI for DX-Platform",
25
- name: "dx",
26
- specVersion: "1",
27
- version: "1.2.3",
28
- });
29
- });
30
- it("maps global options from the root command", () => {
31
- const root = buildRoot();
32
- const spec = extractCliSpec(root, "1.2.3");
33
- expect(spec.globalOptions.find((o) => o.long === "--verbose")).toStrictEqual({
34
- choices: [],
35
- defaultValue: false,
36
- description: "Enable verbose output",
37
- flags: "-v, --verbose",
38
- long: "--verbose",
39
- optional: false,
40
- required: false,
41
- short: "-v",
42
- });
43
- expect(spec.globalOptions.find((o) => o.long === "--output")).toStrictEqual({
44
- choices: ["text", "json"],
45
- defaultValue: "text",
46
- description: "Output mode",
47
- flags: "--output <mode>",
48
- long: "--output",
49
- optional: false,
50
- required: true,
51
- short: undefined,
52
- });
53
- });
54
- it("excludes help and version options from globalOptions", () => {
55
- const root = buildRoot();
56
- const spec = extractCliSpec(root, "1.2.3");
57
- const flags = spec.globalOptions.map((o) => o.long);
58
- expect(flags).not.toContain("--help");
59
- expect(flags).not.toContain("--version");
60
- });
61
- });
62
- };
63
- const registerCommandListTests = () => {
64
- describe("command lists", () => {
65
- it("maps a flat subcommand with options and no arguments", () => {
66
- const root = buildRoot();
67
- root.addCommand(new Command("doctor")
68
- .description("Run health checks")
69
- .addOption(new Option("--fix", "Auto-fix issues").default(false)));
70
- const spec = extractCliSpec(root, "1.2.3");
71
- expect(spec.commands).toStrictEqual([
72
- {
73
- arguments: [],
74
- commands: [],
75
- description: "Run health checks",
76
- name: "doctor",
77
- options: [
78
- {
79
- choices: [],
80
- defaultValue: false,
81
- description: "Auto-fix issues",
82
- flags: "--fix",
83
- long: "--fix",
84
- optional: false,
85
- required: false,
86
- short: undefined,
87
- },
88
- ],
89
- },
90
- ]);
91
- });
92
- it("maps a subcommand argument (required)", () => {
93
- const root = buildRoot();
94
- root.addCommand(new Command("apply")
95
- .description("Apply something")
96
- .addArgument(new Argument("<id>", "The id of the item to apply")));
97
- const spec = extractCliSpec(root, "1.2.3");
98
- expect(spec.commands).toStrictEqual([
99
- {
100
- arguments: [
101
- {
102
- choices: [],
103
- defaultValue: undefined,
104
- description: "The id of the item to apply",
105
- name: "id",
106
- required: true,
107
- variadic: false,
108
- },
109
- ],
110
- commands: [],
111
- description: "Apply something",
112
- name: "apply",
113
- options: [],
114
- },
115
- ]);
116
- });
117
- it("maps a variadic optional argument", () => {
118
- const root = buildRoot();
119
- root.addCommand(new Command("run")
120
- .description("Run scripts")
121
- .addArgument(new Argument("[scripts...]", "Scripts to run")));
122
- const spec = extractCliSpec(root, "1.2.3");
123
- expect(spec.commands).toStrictEqual([
124
- {
125
- arguments: [
126
- {
127
- choices: [],
128
- defaultValue: undefined,
129
- description: "Scripts to run",
130
- name: "scripts",
131
- required: false,
132
- variadic: true,
133
- },
134
- ],
135
- commands: [],
136
- description: "Run scripts",
137
- name: "run",
138
- options: [],
139
- },
140
- ]);
141
- });
142
- it("includes commands registered with { hidden: true }", () => {
143
- const root = buildRoot();
144
- const visible = new Command("visible").description("Visible");
145
- const hidden = new Command("internal").description("Internal");
146
- root.addCommand(visible);
147
- root.addCommand(hidden, { hidden: true });
148
- const spec = extractCliSpec(root, "1.2.3");
149
- expect(spec.commands).toStrictEqual([
150
- {
151
- arguments: [],
152
- commands: [],
153
- description: "Visible",
154
- name: "visible",
155
- options: [],
156
- },
157
- {
158
- arguments: [],
159
- commands: [],
160
- description: "Internal",
161
- name: "internal",
162
- options: [],
163
- },
164
- ]);
165
- });
166
- it("excludes the spec command from the extracted command list", () => {
167
- const root = buildRoot();
168
- root.addCommand(new Command("doctor").description("Run health checks"));
169
- root.addCommand(new Command("spec").description("Print the CLI spec"));
170
- const spec = extractCliSpec(root, "1.2.3");
171
- expect(spec.commands).toStrictEqual([
172
- {
173
- arguments: [],
174
- commands: [],
175
- description: "Run health checks",
176
- name: "doctor",
177
- options: [],
178
- },
179
- ]);
180
- });
181
- it("returns empty commands array when root has no subcommands", () => {
182
- const root = buildRoot();
183
- const spec = extractCliSpec(root, "1.2.3");
184
- expect(spec.commands).toEqual([]);
185
- });
186
- it("maps an argument with choices", () => {
187
- const root = buildRoot();
188
- root.addCommand(new Command("format")
189
- .description("Format output")
190
- .addArgument(new Argument("<style>", "Output style").choices(["json", "table"])));
191
- const spec = extractCliSpec(root, "1.2.3");
192
- expect(spec.commands).toStrictEqual([
193
- {
194
- arguments: [
195
- {
196
- choices: ["json", "table"],
197
- defaultValue: undefined,
198
- description: "Output style",
199
- name: "style",
200
- required: true,
201
- variadic: false,
202
- },
203
- ],
204
- commands: [],
205
- description: "Format output",
206
- name: "format",
207
- options: [],
208
- },
209
- ]);
210
- });
211
- });
212
- };
213
- const registerNestedCommandTests = () => {
214
- describe("nested commands", () => {
215
- it("recursively maps nested subcommands", () => {
216
- const root = buildRoot();
217
- const codemod = new Command("codemod").description("Manage codemods");
218
- codemod.addCommand(new Command("list").description("List available codemods"));
219
- codemod.addCommand(new Command("apply")
220
- .description("Apply a codemod")
221
- .addArgument(new Argument("<id>", "Codemod id")));
222
- root.addCommand(codemod);
223
- const spec = extractCliSpec(root, "1.2.3");
224
- expect(spec.commands).toStrictEqual([
225
- {
226
- arguments: [],
227
- commands: [
228
- {
229
- arguments: [],
230
- commands: [],
231
- description: "List available codemods",
232
- name: "list",
233
- options: [],
234
- },
235
- {
236
- arguments: [
237
- {
238
- choices: [],
239
- defaultValue: undefined,
240
- description: "Codemod id",
241
- name: "id",
242
- required: true,
243
- variadic: false,
244
- },
245
- ],
246
- commands: [],
247
- description: "Apply a codemod",
248
- name: "apply",
249
- options: [],
250
- },
251
- ],
252
- description: "Manage codemods",
253
- name: "codemod",
254
- options: [],
255
- },
256
- ]);
257
- });
258
- });
259
- };
260
- describe("extractCliSpec", () => {
261
- registerRootMetadataAndGlobalOptionTests();
262
- registerCommandListTests();
263
- registerNestedCommandTests();
264
- });
@@ -1,4 +0,0 @@
1
- /**
2
- * Tests for authorizeCloudAccounts in the init command.
3
- */
4
- export {};