@pagopa/dx-cli 0.22.4 → 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 (104) hide show
  1. package/README.md +18 -0
  2. package/dist/adapters/commander/commands/add.d.ts +2 -6
  3. package/dist/adapters/commander/commands/add.js +4 -8
  4. package/dist/adapters/commander/commands/init.d.ts +2 -6
  5. package/dist/adapters/commander/commands/init.js +6 -5
  6. package/dist/adapters/commander/commands/savemoney.d.ts +11 -0
  7. package/dist/adapters/commander/commands/savemoney.js +30 -5
  8. package/dist/adapters/commander/commands/spec.d.ts +10 -0
  9. package/dist/adapters/commander/commands/spec.js +13 -0
  10. package/dist/adapters/commander/index.js +6 -2
  11. package/dist/adapters/commander/spec.d.ts +16 -0
  12. package/dist/adapters/commander/spec.js +54 -0
  13. package/dist/adapters/plop/generators/environment/actions.js +3 -3
  14. package/dist/adapters/plop/index.js +3 -5
  15. package/dist/adapters/plop/templates-path.d.ts +5 -0
  16. package/dist/adapters/plop/templates-path.js +6 -0
  17. package/dist/domain/dependencies.d.ts +15 -2
  18. package/dist/domain/spec.d.ts +50 -0
  19. package/dist/domain/spec.js +8 -0
  20. package/dist/index.js +15 -12
  21. package/package.json +5 -5
  22. package/templates/monorepo/nx.json +0 -1
  23. package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +0 -1
  24. package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +0 -95
  25. package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +0 -1
  26. package/dist/adapters/azure/__tests__/cloud-account-service.test.js +0 -378
  27. package/dist/adapters/codemods/__tests__/registry.test.d.ts +0 -1
  28. package/dist/adapters/codemods/__tests__/registry.test.js +0 -56
  29. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +0 -1
  30. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +0 -77
  31. package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +0 -1
  32. package/dist/adapters/codemods/__tests__/use-pnpm.test.js +0 -148
  33. package/dist/adapters/commander/__tests__/env.test.d.ts +0 -1
  34. package/dist/adapters/commander/__tests__/env.test.js +0 -45
  35. package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +0 -1
  36. package/dist/adapters/commander/__tests__/error-reporting.test.js +0 -63
  37. package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +0 -1
  38. package/dist/adapters/commander/__tests__/exit-with-error.test.js +0 -92
  39. package/dist/adapters/commander/__tests__/global-options.test.d.ts +0 -1
  40. package/dist/adapters/commander/__tests__/global-options.test.js +0 -33
  41. package/dist/adapters/commander/commands/__tests__/add.test.d.ts +0 -4
  42. package/dist/adapters/commander/commands/__tests__/add.test.js +0 -167
  43. package/dist/adapters/commander/commands/__tests__/init.test.d.ts +0 -4
  44. package/dist/adapters/commander/commands/__tests__/init.test.js +0 -48
  45. package/dist/adapters/commander/commands/__tests__/preconditions.test.d.ts +0 -1
  46. package/dist/adapters/commander/commands/__tests__/preconditions.test.js +0 -32
  47. package/dist/adapters/commander/presenters/__tests__/index.test.d.ts +0 -1
  48. package/dist/adapters/commander/presenters/__tests__/index.test.js +0 -23
  49. package/dist/adapters/commander/presenters/__tests__/json.test.d.ts +0 -1
  50. package/dist/adapters/commander/presenters/__tests__/json.test.js +0 -108
  51. package/dist/adapters/commander/presenters/__tests__/text.test.d.ts +0 -1
  52. package/dist/adapters/commander/presenters/__tests__/text.test.js +0 -60
  53. package/dist/adapters/github/__tests__/github-repo.spec.d.ts +0 -1
  54. package/dist/adapters/github/__tests__/github-repo.spec.js +0 -67
  55. package/dist/adapters/node/__tests__/data.d.ts +0 -18
  56. package/dist/adapters/node/__tests__/data.js +0 -22
  57. package/dist/adapters/node/__tests__/package-json.test.d.ts +0 -1
  58. package/dist/adapters/node/__tests__/package-json.test.js +0 -86
  59. package/dist/adapters/node/__tests__/repository.test.d.ts +0 -1
  60. package/dist/adapters/node/__tests__/repository.test.js +0 -77
  61. package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +0 -1
  62. package/dist/adapters/node/fs/__tests__/file-reader.test.js +0 -80
  63. package/dist/adapters/node/json/__tests__/index.test.d.ts +0 -1
  64. package/dist/adapters/node/json/__tests__/index.test.js +0 -14
  65. package/dist/adapters/octokit/__tests__/index.test.d.ts +0 -1
  66. package/dist/adapters/octokit/__tests__/index.test.js +0 -414
  67. package/dist/adapters/pagopa-technology/__tests__/authorization.test.d.ts +0 -4
  68. package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +0 -548
  69. package/dist/adapters/plop/__tests__/run-actions.test.d.ts +0 -1
  70. package/dist/adapters/plop/__tests__/run-actions.test.js +0 -68
  71. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +0 -1
  72. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +0 -171
  73. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +0 -1
  74. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +0 -134
  75. package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +0 -2
  76. package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +0 -92
  77. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.d.ts +0 -1
  78. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
  79. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +0 -1
  80. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +0 -113
  81. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.d.ts +0 -1
  82. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.js +0 -35
  83. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.d.ts +0 -1
  84. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.js +0 -60
  85. package/dist/adapters/yaml/__tests__/index.test.d.ts +0 -1
  86. package/dist/adapters/yaml/__tests__/index.test.js +0 -53
  87. package/dist/domain/__tests__/data.d.ts +0 -19
  88. package/dist/domain/__tests__/data.js +0 -28
  89. package/dist/domain/__tests__/environment.test.d.ts +0 -1
  90. package/dist/domain/__tests__/environment.test.js +0 -332
  91. package/dist/domain/__tests__/info.test.d.ts +0 -1
  92. package/dist/domain/__tests__/info.test.js +0 -77
  93. package/dist/domain/__tests__/package-json.test.d.ts +0 -1
  94. package/dist/domain/__tests__/package-json.test.js +0 -39
  95. package/dist/domain/__tests__/repository.test.d.ts +0 -1
  96. package/dist/domain/__tests__/repository.test.js +0 -111
  97. package/dist/domain/__tests__/workspace.test.d.ts +0 -1
  98. package/dist/domain/__tests__/workspace.test.js +0 -57
  99. package/dist/use-cases/__tests__/apply-codemod.test.d.ts +0 -1
  100. package/dist/use-cases/__tests__/apply-codemod.test.js +0 -71
  101. package/dist/use-cases/__tests__/list-codemods.test.d.ts +0 -1
  102. package/dist/use-cases/__tests__/list-codemods.test.js +0 -37
  103. package/dist/use-cases/__tests__/request-authorization.test.d.ts +0 -4
  104. package/dist/use-cases/__tests__/request-authorization.test.js +0 -43
@@ -1,23 +0,0 @@
1
- /**
2
- * Tests for isNonInteractive and createCommandPresenter factory.
3
- */
4
- import { describe, expect, it } from "vitest";
5
- import { createCommandPresenter, isNonInteractive } from "../index.js";
6
- import { JsonCommandPresenter } from "../json-command-presenter.js";
7
- import { TextCommandPresenter } from "../text-command-presenter.js";
8
- describe("isNonInteractive", () => {
9
- it("returns true when CI is true", () => {
10
- expect(isNonInteractive({ CI: true })).toBe(true);
11
- });
12
- it("returns false when CI is false", () => {
13
- expect(isNonInteractive({ CI: false })).toBe(false);
14
- });
15
- });
16
- describe("createCommandPresenter", () => {
17
- it("returns a TextCommandPresenter when output is 'text'", () => {
18
- expect(createCommandPresenter("text")).toBeInstanceOf(TextCommandPresenter);
19
- });
20
- it("returns a JsonCommandPresenter when output is 'json'", () => {
21
- expect(createCommandPresenter("json")).toBeInstanceOf(JsonCommandPresenter);
22
- });
23
- });
@@ -1,108 +0,0 @@
1
- /**
2
- * Tests for JsonCommandPresenter.
3
- *
4
- * JsonCommandPresenter uses a split-stream convention:
5
- * - stdout for the final result/error envelope
6
- * - stderr for step lifecycle (progress) events
7
- *
8
- * Tests verify the wire format, correct stream usage, and that values
9
- * flow through correctly.
10
- */
11
- import { afterEach, describe, expect, it, vi } from "vitest";
12
- import { JsonCommandPresenter } from "../json-command-presenter.js";
13
- const captureStdout = () => {
14
- const written = [];
15
- vi.spyOn(process.stdout, "write").mockImplementation((data) => {
16
- written.push(String(data));
17
- return true;
18
- });
19
- return { written };
20
- };
21
- const captureStderr = () => {
22
- const written = [];
23
- vi.spyOn(process.stderr, "write").mockImplementation((data) => {
24
- written.push(String(data));
25
- return true;
26
- });
27
- return { written };
28
- };
29
- describe("JsonCommandPresenter", () => {
30
- afterEach(() => {
31
- vi.restoreAllMocks();
32
- });
33
- describe("trackStep", () => {
34
- it("executes the task and returns its resolved value", async () => {
35
- captureStderr();
36
- const logger = new JsonCommandPresenter();
37
- const result = await logger.trackStep("check terraform", () => Promise.resolve(42));
38
- expect(result).toBe(42);
39
- });
40
- it("emits start then success events to stderr", async () => {
41
- const stderr = captureStderr();
42
- const logger = new JsonCommandPresenter();
43
- await logger.trackStep("check terraform", () => Promise.resolve("done"));
44
- expect(stderr.written).toHaveLength(2);
45
- expect(JSON.parse(stderr.written[0])).toMatchObject({
46
- name: "check terraform",
47
- status: "start",
48
- type: "step",
49
- });
50
- expect(JSON.parse(stderr.written[1])).toMatchObject({
51
- name: "check terraform",
52
- status: "success",
53
- type: "step",
54
- });
55
- });
56
- it("emits error event to stderr and rethrows on task failure", async () => {
57
- const stderr = captureStderr();
58
- const logger = new JsonCommandPresenter();
59
- const error = new Error("terraform not found");
60
- await expect(logger.trackStep("check terraform", () => Promise.reject(error))).rejects.toThrow("terraform not found");
61
- expect(JSON.parse(stderr.written[1])).toMatchObject({
62
- error: "terraform not found",
63
- name: "check terraform",
64
- status: "error",
65
- type: "step",
66
- });
67
- });
68
- it("can run multiple sequential steps", async () => {
69
- captureStderr();
70
- const logger = new JsonCommandPresenter();
71
- const order = [];
72
- await logger.trackStep("step A", async () => {
73
- order.push("A");
74
- });
75
- await logger.trackStep("step B", async () => {
76
- order.push("B");
77
- });
78
- expect(order).toEqual(["A", "B"]);
79
- });
80
- });
81
- describe("reportResult", () => {
82
- it("emits an ok:true JSON envelope to stdout", () => {
83
- const stdout = captureStdout();
84
- const logger = new JsonCommandPresenter();
85
- logger.reportResult({ repository: { name: "my-repo" } });
86
- expect(JSON.parse(stdout.written[0])).toEqual({
87
- data: { repository: { name: "my-repo" } },
88
- ok: true,
89
- });
90
- });
91
- });
92
- describe("reportError", () => {
93
- it("emits an ok:false JSON envelope to stdout", () => {
94
- const stdout = captureStdout();
95
- const logger = new JsonCommandPresenter();
96
- logger.reportError(new Error("something failed"));
97
- expect(JSON.parse(stdout.written[0])).toMatchObject({
98
- error: "something failed",
99
- ok: false,
100
- });
101
- });
102
- it("handles non-Error values without throwing", () => {
103
- captureStdout();
104
- const logger = new JsonCommandPresenter();
105
- expect(() => logger.reportError("plain string error")).not.toThrow();
106
- });
107
- });
108
- });
@@ -1,60 +0,0 @@
1
- /**
2
- * Tests for TextCommandPresenter.
3
- *
4
- * The TextCommandPresenter wraps oraPromise for step feedback and chalk for
5
- * final output. Tests verify the observable behavior: tasks are executed,
6
- * values flow through, and errors surface correctly.
7
- */
8
- import { afterEach, describe, expect, it, vi } from "vitest";
9
- // Mock oraPromise so tests don't spin up a real TTY spinner
10
- vi.mock("ora", () => ({
11
- oraPromise: (_promise) => _promise,
12
- }));
13
- import { TextCommandPresenter } from "../text-command-presenter.js";
14
- describe("TextCommandPresenter", () => {
15
- afterEach(() => {
16
- vi.restoreAllMocks();
17
- });
18
- describe("trackStep", () => {
19
- it("executes the task and returns its resolved value", async () => {
20
- const logger = new TextCommandPresenter();
21
- const result = await logger.trackStep("check terraform", () => Promise.resolve(42));
22
- expect(result).toBe(42);
23
- });
24
- it("propagates task rejection as a thrown error", async () => {
25
- const logger = new TextCommandPresenter();
26
- const error = new Error("terraform not found");
27
- await expect(logger.trackStep("check terraform", () => Promise.reject(error))).rejects.toThrow("terraform not found");
28
- });
29
- it("can run multiple sequential steps", async () => {
30
- const logger = new TextCommandPresenter();
31
- const order = [];
32
- await logger.trackStep("step A", async () => {
33
- order.push("A");
34
- });
35
- await logger.trackStep("step B", async () => {
36
- order.push("B");
37
- });
38
- expect(order).toEqual(["A", "B"]);
39
- });
40
- });
41
- describe("reportResult", () => {
42
- it("calls console.log without throwing", () => {
43
- vi.spyOn(console, "log").mockImplementation(() => undefined);
44
- const logger = new TextCommandPresenter();
45
- expect(() => logger.reportResult({ repository: { name: "my-repo" } })).not.toThrow();
46
- });
47
- });
48
- describe("reportError", () => {
49
- it("calls console.error without throwing", () => {
50
- vi.spyOn(console, "error").mockImplementation(() => undefined);
51
- const logger = new TextCommandPresenter();
52
- expect(() => logger.reportError(new Error("something failed"))).not.toThrow();
53
- });
54
- it("handles non-Error values without throwing", () => {
55
- vi.spyOn(console, "error").mockImplementation(() => undefined);
56
- const logger = new TextCommandPresenter();
57
- expect(() => logger.reportError("plain string error")).not.toThrow();
58
- });
59
- });
60
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,67 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
- vi.mock("execa", () => ({
3
- $: vi.fn(),
4
- }));
5
- import { $ } from "execa";
6
- import { getGithubRepo } from "../github-repo.js";
7
- const mock$ = $;
8
- describe("getGithubRepo", () => {
9
- beforeEach(() => {
10
- vi.clearAllMocks();
11
- });
12
- it("should return undefined if no remote URL is set", async () => {
13
- mock$.mockResolvedValue({ stdout: "" });
14
- const result = await getGithubRepo();
15
- expect(result).toBeUndefined();
16
- });
17
- it("should parse GitHub repository URL and return owner and repo", async () => {
18
- mock$.mockResolvedValue({ stdout: "https://github.com/pagopa/dx" });
19
- const result = await getGithubRepo();
20
- expect(result).toEqual({
21
- owner: "pagopa",
22
- repo: "dx",
23
- });
24
- });
25
- it("should handle repository URLs with .git suffix", async () => {
26
- mock$.mockResolvedValue({ stdout: "https://github.com/pagopa/dx.git" });
27
- const result = await getGithubRepo();
28
- expect(result).toEqual({
29
- owner: "pagopa",
30
- repo: "dx",
31
- });
32
- });
33
- it("should throw an error for non-GitHub repositories", async () => {
34
- mock$.mockResolvedValue({ stdout: "https://gitlab.com/owner/repo" });
35
- await expect(getGithubRepo()).rejects.toThrow("Only GitHub repositories are supported");
36
- });
37
- it("should handle repository names with hyphens", async () => {
38
- mock$.mockResolvedValue({
39
- stdout: "https://github.com/my-org/my-repo-name",
40
- });
41
- const result = await getGithubRepo();
42
- expect(result).toEqual({
43
- owner: "my-org",
44
- repo: "my-repo-name",
45
- });
46
- });
47
- it("should handle repository names with underscores", async () => {
48
- mock$.mockResolvedValue({
49
- stdout: "https://github.com/my_org/my_repo_name",
50
- });
51
- const result = await getGithubRepo();
52
- expect(result).toEqual({
53
- owner: "my_org",
54
- repo: "my_repo_name",
55
- });
56
- });
57
- it("should handle ssh repository URLs", async () => {
58
- mock$.mockResolvedValue({
59
- stdout: "git@github.com:my-org/my-repo-name.git",
60
- });
61
- const result = await getGithubRepo();
62
- expect(result).toEqual({
63
- owner: "my-org",
64
- repo: "my-repo-name",
65
- });
66
- });
67
- });
@@ -1,18 +0,0 @@
1
- import { PackageJson } from "../../../domain/package-json.js";
2
- export declare const makeMockPackageJson: (overrides?: Partial<PackageJson>) => {
3
- dependencies: Map<string, string> | {
4
- aDependency: string;
5
- anotherDependency: string;
6
- };
7
- devDependencies: Map<string, string> | {
8
- turbo: string;
9
- typescript: string;
10
- };
11
- name: string;
12
- scripts: Map<string & import("zod").$brand<"ScriptName">, string> | {
13
- build: string;
14
- "code-review": string;
15
- };
16
- packageManager?: "npm" | "pnpm" | "yarn" | undefined;
17
- };
18
- export declare const makeMockPnpmWorkspaceYaml: () => string;
@@ -1,22 +0,0 @@
1
- export const makeMockPackageJson = (overrides = {}) => {
2
- const basePackageJson = {
3
- dependencies: {
4
- aDependency: "^4.17.21",
5
- anotherDependency: "^8.0.0",
6
- },
7
- devDependencies: {
8
- turbo: "^2.5.2",
9
- typescript: "^5.0.0",
10
- },
11
- name: "aPackageName",
12
- scripts: {
13
- build: "tsc",
14
- "code-review": "eslint .",
15
- },
16
- };
17
- return { ...basePackageJson, ...overrides };
18
- };
19
- export const makeMockPnpmWorkspaceYaml = () => `
20
- packages:
21
- - packages/*
22
- `;
@@ -1 +0,0 @@
1
- export {};
@@ -1,86 +0,0 @@
1
- import { vol } from "memfs";
2
- import { err, ok } from "neverthrow";
3
- import fs from "node:fs/promises";
4
- import { beforeEach, describe, expect, it, vi } from "vitest";
5
- import { makePackageJsonReader } from "../package-json.js";
6
- import { makeMockPackageJson } from "./data.js";
7
- vi.mock("node:fs/promises");
8
- describe("makePackageJsonReader", () => {
9
- const mockPackageJson = makeMockPackageJson();
10
- const rootDir = "/some/dir";
11
- beforeEach(() => {
12
- vol.reset();
13
- vol.fromJSON({
14
- "./package.json": JSON.stringify(mockPackageJson),
15
- }, rootDir);
16
- });
17
- describe("getScripts", () => {
18
- it("should parse scripts from package.json", async () => {
19
- const spy = vi.spyOn(fs, "readFile");
20
- const packageJsonReader = makePackageJsonReader();
21
- const result = await packageJsonReader.getScripts(rootDir);
22
- expect(result).toStrictEqual(ok(new Map().set("build", "tsc").set("code-review", "eslint .")));
23
- expect(spy).toHaveBeenCalledWith(`${rootDir}/package.json`, "utf-8");
24
- });
25
- it("should return an empty array when no scripts exist", async () => {
26
- vol.fromJSON({
27
- "./package.json": JSON.stringify(makeMockPackageJson({ scripts: undefined })),
28
- }, rootDir);
29
- const spy = vi.spyOn(fs, "readFile");
30
- const packageJsonReader = makePackageJsonReader();
31
- const result = await packageJsonReader.getScripts(rootDir);
32
- expect(result).toStrictEqual(ok(new Map()));
33
- expect(spy).toHaveBeenCalledWith(`${rootDir}/package.json`, "utf-8");
34
- });
35
- it("should return an error when package.json does not exist", async () => {
36
- vol.reset();
37
- const packageJsonReader = makePackageJsonReader();
38
- const result = await packageJsonReader.getScripts(rootDir);
39
- expect(result).toStrictEqual(err(new Error("Failed to read file: /some/dir/package.json")));
40
- });
41
- it("should return an error when package.json is invalid JSON", async () => {
42
- vol.fromJSON({
43
- "./package.json": "invalid json content",
44
- }, rootDir);
45
- const packageJsonReader = makePackageJsonReader();
46
- const result = await packageJsonReader.getScripts(rootDir);
47
- expect(result).toStrictEqual(err(new Error("Failed to parse JSON")));
48
- });
49
- });
50
- describe("getDependencies", () => {
51
- it("should parse devDependencies from package.json", async () => {
52
- const spy = vi.spyOn(fs, "readFile");
53
- const packageJsonReader = makePackageJsonReader();
54
- const result = await packageJsonReader.getDependencies(rootDir, "dev");
55
- expect(result).toStrictEqual(ok(new Map().set("turbo", "^2.5.2").set("typescript", "^5.0.0")));
56
- expect(spy).toHaveBeenCalledWith(`${rootDir}/package.json`, "utf-8");
57
- });
58
- it("should parse dependencies from package.json", async () => {
59
- const spy = vi.spyOn(fs, "readFile");
60
- const packageJsonReader = makePackageJsonReader();
61
- const result = await packageJsonReader.getDependencies(rootDir, "prod");
62
- expect(result).toStrictEqual(ok(new Map()
63
- .set("aDependency", "^4.17.21")
64
- .set("anotherDependency", "^8.0.0")));
65
- expect(spy).toHaveBeenCalledWith(`${rootDir}/package.json`, "utf-8");
66
- });
67
- it("should return an empty array when no dependencies exist", async () => {
68
- vol.reset();
69
- vol.fromJSON({
70
- "./package.json": JSON.stringify(makeMockPackageJson({
71
- dependencies: undefined,
72
- devDependencies: undefined,
73
- })),
74
- }, rootDir);
75
- const packageJsonReader = makePackageJsonReader();
76
- const result = await packageJsonReader.getDependencies(rootDir, "dev");
77
- expect(result).toStrictEqual(ok(new Map()));
78
- });
79
- it("should return an error when package.json does not exist for dependencies", async () => {
80
- vol.reset();
81
- const packageJsonReader = makePackageJsonReader();
82
- const result = await packageJsonReader.getDependencies(rootDir, "dev");
83
- expect(result).toStrictEqual(err(new Error("Failed to read file: /some/dir/package.json")));
84
- });
85
- });
86
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,77 +0,0 @@
1
- import * as glob from "glob";
2
- import { fs, vol } from "memfs";
3
- import { err, ok } from "neverthrow";
4
- import { beforeEach, describe, expect, it, vi } from "vitest";
5
- import { makeRepositoryReader } from "../repository.js";
6
- import { makeMockPackageJson, makeMockPnpmWorkspaceYaml } from "./data.js";
7
- vi.mock("node:fs/promises");
8
- const mockFileSystem = {
9
- "./packages/bar/package.json": JSON.stringify(makeMockPackageJson({ name: "bar" })),
10
- "./packages/foo/package.json": JSON.stringify(makeMockPackageJson({ name: "foo" })),
11
- "./pnpm-workspace.yaml": makeMockPnpmWorkspaceYaml(),
12
- };
13
- describe("makeRepositoryReader", () => {
14
- const repoRoot = "/some/repo/root";
15
- vi.mock("glob", { spy: true });
16
- beforeEach(() => {
17
- vi.clearAllMocks();
18
- vol.reset();
19
- vol.fromJSON(mockFileSystem, repoRoot);
20
- });
21
- describe("getWorkspaces", () => {
22
- it("should return an error when pnpm-workspace.yaml does not exist", async () => {
23
- vol.reset();
24
- const repositoryReader = makeRepositoryReader();
25
- const result = await repositoryReader.getWorkspaces(repoRoot);
26
- expect(result).toStrictEqual(err(new Error("Failed to read file: /some/repo/root/pnpm-workspace.yaml")));
27
- });
28
- it("should return no workspaces if the packages entry is not in the pnpm-workspace.yaml file", async () => {
29
- vol.reset();
30
- vol.fromJSON({ ...mockFileSystem, "./pnpm-workspace.yaml": "a yaml" }, repoRoot);
31
- const readFileSpy = vi.spyOn(fs.promises, "readFile");
32
- const globSpy = vi.spyOn(glob, "glob");
33
- const repositoryReader = makeRepositoryReader();
34
- const result = await repositoryReader.getWorkspaces(repoRoot);
35
- expect(result).toStrictEqual(ok([]));
36
- expect(readFileSpy).nthCalledWith(1, "/some/repo/root/pnpm-workspace.yaml", "utf-8");
37
- expect(globSpy).not.toHaveBeenCalled();
38
- });
39
- });
40
- it("should return the workspaces", async () => {
41
- const spyReadFile = vi.spyOn(fs.promises, "readFile");
42
- const globSpy = vi.spyOn(glob, "glob");
43
- globSpy.mockResolvedValueOnce(["packages/foo", "packages/bar"]);
44
- const repositoryReader = makeRepositoryReader();
45
- const result = await repositoryReader.getWorkspaces(repoRoot);
46
- expect(result).toStrictEqual(ok([
47
- {
48
- name: "foo",
49
- path: "/some/repo/root/packages/foo",
50
- },
51
- {
52
- name: "bar",
53
- path: "/some/repo/root/packages/bar",
54
- },
55
- ]));
56
- expect(spyReadFile).nthCalledWith(1, "/some/repo/root/pnpm-workspace.yaml", "utf-8");
57
- expect(globSpy).toHaveBeenCalledTimes(1);
58
- expect(globSpy).toHaveBeenCalledWith("packages/*", {
59
- cwd: repoRoot,
60
- });
61
- expect(spyReadFile).nthCalledWith(2, "/some/repo/root/packages/foo/package.json", "utf-8");
62
- expect(spyReadFile).nthCalledWith(3, "/some/repo/root/packages/bar/package.json", "utf-8");
63
- });
64
- it("should return an error when the glob function fails", async () => {
65
- const readFileSpy = vi.spyOn(fs.promises, "readFile");
66
- const globSpy = vi.spyOn(glob, "glob");
67
- // First read the pnpm-workspace.yaml file
68
- globSpy.mockImplementationOnce(() => Promise.reject(new Error("glob failed")));
69
- const repositoryReader = makeRepositoryReader();
70
- const result = await repositoryReader.getWorkspaces(repoRoot);
71
- expect(result).toStrictEqual(err(new Error("Failed to resolve workspace glob: packages/*")));
72
- expect(readFileSpy).toBeCalledWith("/some/repo/root/pnpm-workspace.yaml", "utf-8");
73
- expect(globSpy).toBeCalledWith("packages/*", {
74
- cwd: repoRoot,
75
- });
76
- });
77
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,80 +0,0 @@
1
- import { fs, vol } from "memfs";
2
- import { err, ok } from "neverthrow";
3
- import { beforeEach, describe, expect, it, vi } from "vitest";
4
- import { z } from "zod/v4";
5
- import { fileExists, readFile, readFileAndDecode } from "../file-reader.js";
6
- vi.mock("node:fs/promises");
7
- describe("readFileAndDecode", () => {
8
- const testSchema = z.object({
9
- name: z.string(),
10
- version: z.string(),
11
- });
12
- const validData = {
13
- name: "test-package",
14
- version: "1.0.0",
15
- };
16
- beforeEach(() => {
17
- vol.reset();
18
- vol.fromJSON({
19
- "./file.json": JSON.stringify(validData),
20
- "./file.yaml": "name: test-package\nversion: 1.0.0",
21
- "./invalid.json": JSON.stringify({ invalidKey: "anInvalidKey" }),
22
- }, ".");
23
- });
24
- it("should read and parse a file", async () => {
25
- const spy = vi.spyOn(fs.promises, "readFile");
26
- const result = await readFileAndDecode("file.json", testSchema);
27
- expect(result).toStrictEqual(ok(validData));
28
- expect(spy).toHaveBeenCalledWith("file.json", "utf-8");
29
- });
30
- it("should return error when file does not exist", async () => {
31
- const result = await readFileAndDecode("nonexistent.json", testSchema);
32
- expect(result).toStrictEqual(err(new Error("Failed to read file: nonexistent.json")));
33
- });
34
- it("should return error when JSON parsing fails", async () => {
35
- const result = await readFileAndDecode("file.yaml", testSchema);
36
- expect(result).toStrictEqual(err(new Error("Failed to parse JSON")));
37
- });
38
- it("should return error when schema decoding fails", async () => {
39
- const spy = vi.spyOn(fs.promises, "readFile");
40
- const result = await readFileAndDecode("invalid.json", testSchema);
41
- expect(result).toStrictEqual(err(new Error("Input is not valid for the given schema")));
42
- expect(spy).toHaveBeenCalledWith("invalid.json", "utf-8");
43
- });
44
- });
45
- describe("readFile", () => {
46
- beforeEach(() => {
47
- vol.reset();
48
- vol.fromJSON({
49
- "./existing.txt": "hello world",
50
- }, ".");
51
- });
52
- it("should read a file when it exists", async () => {
53
- const spy = vi.spyOn(fs.promises, "readFile");
54
- const result = await readFile("existing.txt");
55
- expect(result).toStrictEqual(ok("hello world"));
56
- expect(spy).toHaveBeenCalledWith("existing.txt", "utf-8");
57
- });
58
- it("should return error when file does not exist", async () => {
59
- const result = await readFile("/missing.txt");
60
- expect(result).toStrictEqual(err(new Error("Failed to read file: /missing.txt")));
61
- });
62
- });
63
- describe("fileExists", () => {
64
- beforeEach(() => {
65
- vol.reset();
66
- vol.fromJSON({
67
- "./file.txt": "content",
68
- }, ".");
69
- });
70
- it("should return true when the path exists", async () => {
71
- const spy = vi.spyOn(fs.promises, "stat");
72
- const result = await fileExists("file.txt");
73
- expect(result).toStrictEqual(ok(true));
74
- expect(spy).toHaveBeenCalledWith("file.txt");
75
- });
76
- it("should return the error when the path does not exist", async () => {
77
- const result = await fileExists("missing.txt");
78
- expect(result).toStrictEqual(err(new Error("missing.txt not found.")));
79
- });
80
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,14 +0,0 @@
1
- import { err, ok } from "neverthrow";
2
- import { describe, expect, it } from "vitest";
3
- import { parseJson } from "../index.js";
4
- describe("parseJson", () => {
5
- const validJSONString = '{"name": "test"}';
6
- it("should return JS object when valid JSON is provided", () => {
7
- const result = parseJson(validJSONString);
8
- expect(result).toStrictEqual(ok({ name: "test" }));
9
- });
10
- it("should return error when invalid JSON is provided", () => {
11
- const result = parseJson("invalid JSON");
12
- expect(result).toStrictEqual(err(new Error("Failed to parse JSON")));
13
- });
14
- });
@@ -1 +0,0 @@
1
- export {};