@somewhatabstract/x 0.0.1 → 0.1.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/.github/dependabot.yml +28 -0
- package/.github/workflows/codeql-analysis.yml +29 -29
- package/.github/workflows/dependabot-pr-approval.yml +36 -0
- package/.github/workflows/nodejs.yml +84 -86
- package/.github/workflows/release.yml +4 -7
- package/.vscode/settings.json +19 -0
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +3 -3
- package/README.md +132 -1
- package/biome.json +39 -0
- package/dist/x.mjs +278 -3
- package/package.json +14 -4
- package/src/__tests__/build-environment.test.ts +285 -0
- package/src/__tests__/discover-packages.test.ts +196 -0
- package/src/__tests__/errors.test.ts +59 -0
- package/src/__tests__/execute-script.test.ts +1042 -0
- package/src/__tests__/find-matching-bins.test.ts +506 -0
- package/src/__tests__/find-workspace-root.test.ts +73 -0
- package/src/__tests__/is-node-executable.test.ts +125 -0
- package/src/__tests__/resolve-bin-path.test.ts +344 -0
- package/src/__tests__/x-impl.test.ts +306 -7
- package/src/__tests__/x.test.ts +236 -0
- package/src/bin/x.ts +55 -1
- package/src/build-environment.ts +98 -0
- package/src/discover-packages.ts +35 -0
- package/src/errors.ts +10 -0
- package/src/execute-script.ts +56 -0
- package/src/find-matching-bins.ts +72 -0
- package/src/find-workspace-root.ts +24 -0
- package/src/is-node-executable.ts +16 -0
- package/src/resolve-bin-path.ts +48 -0
- package/src/x-impl.ts +95 -4
- package/tsconfig-types.json +2 -4
- package/tsconfig.json +5 -13
- package/tsdown.config.ts +1 -1
- package/vitest.config.ts +1 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import * as manypkg from "@manypkg/get-packages";
|
|
2
|
+
import {beforeEach, describe, expect, it, vi} from "vitest";
|
|
3
|
+
import {discoverPackages} from "../discover-packages";
|
|
4
|
+
import {HandledError} from "../errors";
|
|
5
|
+
|
|
6
|
+
// Mock @manypkg/get-packages
|
|
7
|
+
vi.mock("@manypkg/get-packages", () => ({
|
|
8
|
+
getPackages: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe("discoverPackages", () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should return packages from @manypkg", async () => {
|
|
17
|
+
// Arrange
|
|
18
|
+
const workspaceRoot = "/test/workspace";
|
|
19
|
+
const mockPackages = {
|
|
20
|
+
packages: [
|
|
21
|
+
{
|
|
22
|
+
packageJson: {name: "pkg1", version: "1.0.0"},
|
|
23
|
+
dir: "/test/workspace/pkg1",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
packageJson: {name: "pkg2", version: "2.0.0"},
|
|
27
|
+
dir: "/test/workspace/pkg2",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
const result = await discoverPackages(workspaceRoot);
|
|
36
|
+
|
|
37
|
+
// Assert
|
|
38
|
+
expect(result).toHaveLength(2);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should map package names correctly", async () => {
|
|
42
|
+
// Arrange
|
|
43
|
+
const workspaceRoot = "/test/workspace";
|
|
44
|
+
const mockPackages = {
|
|
45
|
+
packages: [
|
|
46
|
+
{
|
|
47
|
+
packageJson: {name: "test-package", version: "1.0.0"},
|
|
48
|
+
dir: "/test/workspace/pkg",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
54
|
+
|
|
55
|
+
// Act
|
|
56
|
+
const result = await discoverPackages(workspaceRoot);
|
|
57
|
+
|
|
58
|
+
// Assert
|
|
59
|
+
expect(result[0].name).toBe("test-package");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should map package paths correctly", async () => {
|
|
63
|
+
// Arrange
|
|
64
|
+
const workspaceRoot = "/test/workspace";
|
|
65
|
+
const mockPackages = {
|
|
66
|
+
packages: [
|
|
67
|
+
{
|
|
68
|
+
packageJson: {name: "test-package", version: "1.0.0"},
|
|
69
|
+
dir: "/test/workspace/packages/test",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
75
|
+
|
|
76
|
+
// Act
|
|
77
|
+
const result = await discoverPackages(workspaceRoot);
|
|
78
|
+
|
|
79
|
+
// Assert
|
|
80
|
+
expect(result[0].path).toBe("/test/workspace/packages/test");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should map package versions correctly", async () => {
|
|
84
|
+
// Arrange
|
|
85
|
+
const workspaceRoot = "/test/workspace";
|
|
86
|
+
const mockPackages = {
|
|
87
|
+
packages: [
|
|
88
|
+
{
|
|
89
|
+
packageJson: {name: "test-package", version: "3.2.1"},
|
|
90
|
+
dir: "/test/workspace/pkg",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
96
|
+
|
|
97
|
+
// Act
|
|
98
|
+
const result = await discoverPackages(workspaceRoot);
|
|
99
|
+
|
|
100
|
+
// Assert
|
|
101
|
+
expect(result[0].version).toBe("3.2.1");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should use 'unknown' for missing version", async () => {
|
|
105
|
+
// Arrange
|
|
106
|
+
const workspaceRoot = "/test/workspace";
|
|
107
|
+
const mockPackages = {
|
|
108
|
+
packages: [
|
|
109
|
+
{
|
|
110
|
+
packageJson: {name: "test-package"},
|
|
111
|
+
dir: "/test/workspace/pkg",
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
117
|
+
|
|
118
|
+
// Act
|
|
119
|
+
const result = await discoverPackages(workspaceRoot);
|
|
120
|
+
|
|
121
|
+
// Assert
|
|
122
|
+
expect(result[0].version).toBe("unknown");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should call getPackages with workspace root", async () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
const workspaceRoot = "/test/workspace";
|
|
128
|
+
const mockPackages = {
|
|
129
|
+
packages: [],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
vi.mocked(manypkg.getPackages).mockResolvedValue(mockPackages as any);
|
|
133
|
+
|
|
134
|
+
// Act
|
|
135
|
+
await discoverPackages(workspaceRoot);
|
|
136
|
+
|
|
137
|
+
// Assert
|
|
138
|
+
expect(manypkg.getPackages).toHaveBeenCalledWith(workspaceRoot);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should rethrow HandledError type as is", async () => {
|
|
142
|
+
// Arrange
|
|
143
|
+
const workspaceRoot = "/test/workspace";
|
|
144
|
+
const handledError = new HandledError("Test handled error");
|
|
145
|
+
|
|
146
|
+
vi.mocked(manypkg.getPackages).mockRejectedValue(handledError);
|
|
147
|
+
|
|
148
|
+
// Act
|
|
149
|
+
const underTest = () => discoverPackages(workspaceRoot);
|
|
150
|
+
|
|
151
|
+
// Assert
|
|
152
|
+
await expect(underTest).rejects.toThrow(HandledError);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should rethrow HandledError message as is", async () => {
|
|
156
|
+
// Arrange
|
|
157
|
+
const workspaceRoot = "/test/workspace";
|
|
158
|
+
const handledError = new HandledError("Test handled error");
|
|
159
|
+
|
|
160
|
+
vi.mocked(manypkg.getPackages).mockRejectedValue(handledError);
|
|
161
|
+
|
|
162
|
+
// Act
|
|
163
|
+
const underTest = () => discoverPackages(workspaceRoot);
|
|
164
|
+
|
|
165
|
+
// Assert
|
|
166
|
+
await expect(underTest).rejects.toThrow("Test handled error");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should wrap non-HandledError in HandledError type", async () => {
|
|
170
|
+
// Arrange
|
|
171
|
+
const workspaceRoot = "/test/workspace";
|
|
172
|
+
const error = new Error("Original error");
|
|
173
|
+
|
|
174
|
+
vi.mocked(manypkg.getPackages).mockRejectedValue(error);
|
|
175
|
+
|
|
176
|
+
// Act
|
|
177
|
+
const underTest = () => discoverPackages(workspaceRoot);
|
|
178
|
+
|
|
179
|
+
// Assert
|
|
180
|
+
await expect(underTest).rejects.toThrow(HandledError);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should use expected message when wrapping non-HandledError", async () => {
|
|
184
|
+
// Arrange
|
|
185
|
+
const workspaceRoot = "/test/workspace";
|
|
186
|
+
const error = new Error("Original error");
|
|
187
|
+
|
|
188
|
+
vi.mocked(manypkg.getPackages).mockRejectedValue(error);
|
|
189
|
+
|
|
190
|
+
// Act
|
|
191
|
+
const underTest = () => discoverPackages(workspaceRoot);
|
|
192
|
+
|
|
193
|
+
// Assert
|
|
194
|
+
await expect(underTest).rejects.toThrow("Failed to discover packages");
|
|
195
|
+
});
|
|
196
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {describe, expect, it} from "vitest";
|
|
2
|
+
import {HandledError} from "../errors";
|
|
3
|
+
|
|
4
|
+
describe("HandledError", () => {
|
|
5
|
+
it("should be an instance of Error", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
const error = new HandledError("Test error message");
|
|
8
|
+
|
|
9
|
+
// Act
|
|
10
|
+
const isError = error instanceof Error;
|
|
11
|
+
|
|
12
|
+
// Assert
|
|
13
|
+
expect(isError).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should have name 'HandledError'", () => {
|
|
17
|
+
// Arrange
|
|
18
|
+
const error = new HandledError("Test error message");
|
|
19
|
+
|
|
20
|
+
// Act
|
|
21
|
+
const name = error.name;
|
|
22
|
+
|
|
23
|
+
// Assert
|
|
24
|
+
expect(name).toBe("HandledError");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should preserve the error message", () => {
|
|
28
|
+
// Arrange
|
|
29
|
+
const message = "Test error message";
|
|
30
|
+
|
|
31
|
+
// Act
|
|
32
|
+
const error = new HandledError(message);
|
|
33
|
+
|
|
34
|
+
// Assert
|
|
35
|
+
expect(error.message).toBe(message);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should be distinguishable from HandledError type", () => {
|
|
39
|
+
// Arrange
|
|
40
|
+
const handledError = new HandledError("Handled");
|
|
41
|
+
|
|
42
|
+
// Act
|
|
43
|
+
const isHandledError = handledError instanceof HandledError;
|
|
44
|
+
|
|
45
|
+
// Assert
|
|
46
|
+
expect(isHandledError).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should distinguish regular errors from HandledError type", () => {
|
|
50
|
+
// Arrange
|
|
51
|
+
const regularError = new Error("Regular");
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
const isHandledError = regularError instanceof HandledError;
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(isHandledError).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
});
|