@somewhatabstract/x 0.1.0 → 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.
Files changed (40) hide show
  1. package/README.md +9 -37
  2. package/dist/x.mjs +13 -20
  3. package/package.json +6 -3
  4. package/.changeset/README.md +0 -8
  5. package/.changeset/config.json +0 -11
  6. package/.github/codeql/codeql-config.yml +0 -5
  7. package/.github/dependabot.yml +0 -28
  8. package/.github/workflows/codeql-analysis.yml +0 -71
  9. package/.github/workflows/dependabot-pr-approval.yml +0 -36
  10. package/.github/workflows/nodejs.yml +0 -129
  11. package/.github/workflows/release.yml +0 -95
  12. package/.vscode/settings.json +0 -19
  13. package/CHANGELOG.md +0 -23
  14. package/CODE_OF_CONDUCT.md +0 -76
  15. package/CONTRIBUTING.md +0 -70
  16. package/biome.json +0 -39
  17. package/src/__tests__/build-environment.test.ts +0 -285
  18. package/src/__tests__/discover-packages.test.ts +0 -196
  19. package/src/__tests__/errors.test.ts +0 -59
  20. package/src/__tests__/execute-script.test.ts +0 -1042
  21. package/src/__tests__/find-matching-bins.test.ts +0 -506
  22. package/src/__tests__/find-workspace-root.test.ts +0 -73
  23. package/src/__tests__/is-node-executable.test.ts +0 -125
  24. package/src/__tests__/resolve-bin-path.test.ts +0 -344
  25. package/src/__tests__/x-impl.test.ts +0 -314
  26. package/src/__tests__/x.test.ts +0 -236
  27. package/src/bin/x.ts +0 -57
  28. package/src/build-environment.ts +0 -98
  29. package/src/discover-packages.ts +0 -35
  30. package/src/errors.ts +0 -10
  31. package/src/execute-script.ts +0 -56
  32. package/src/find-matching-bins.ts +0 -72
  33. package/src/find-workspace-root.ts +0 -24
  34. package/src/is-node-executable.ts +0 -16
  35. package/src/resolve-bin-path.ts +0 -48
  36. package/src/x-impl.ts +0 -96
  37. package/tsconfig-types.json +0 -5
  38. package/tsconfig.json +0 -21
  39. package/tsdown.config.ts +0 -24
  40. package/vitest.config.ts +0 -10
@@ -1,76 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, sex characteristics, gender identity and expression,
9
- level of experience, education, socio-economic status, nationality, personal
10
- appearance, race, religion, or sexual identity and orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at jeff[at]somewhatabstract[dot]com. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
-
73
- [homepage]: https://www.contributor-covenant.org
74
-
75
- For answers to common questions about this code of conduct, see
76
- https://www.contributor-covenant.org/faq
package/CONTRIBUTING.md DELETED
@@ -1,70 +0,0 @@
1
- # Contributing to `x`
2
-
3
- 🙇Thank you for your interest in contributing to this 📦.
4
-
5
- Whether raising an issue, reviewing a pull request, or implementing a change, the participation of others is a wonderful 🎁. Read on to find out how you can get involved.
6
-
7
- 📖 Be sure to read our [Code of Conduct](CODE_OF_CONDUCT.md).
8
-
9
- ## 🛑 Bugs And Feature Requests
10
-
11
- If you find a bug or want to make enhancements to the project, head on over to the [🔗Issues](https://github.com/somewhatabstract/x/issues) section and raise an issue. The issue templates will guide you in providing details that will help others help you.
12
-
13
- ## 💻 Code Changes
14
-
15
- ### ⓵ Making your first change
16
-
17
- Look for bugs or feature requests with the [good first issue](https://github.com/somewhatabstract/x/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) or [help wanted](https://github.com/somewhatabstract/x/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+) labels and have a go at implementing a change. Once your change is ready, you can submit a pull request.
18
-
19
- ### 🎬 Getting Started
20
-
21
- To work in the `x` repository, follow these steps:
22
-
23
- 1. Clone the repository
24
- - `gh repo clone somewhatabstract/x`
25
- - -or-
26
- - `git clone git@github.com:somewhatabstract/x.git`
27
- 2. Install `pnpm`
28
- - `corepack enable pnpm`
29
- - `corepack prepare pnpm --activate`
30
- 3. Run `pnpm install` (or `pnpm i`) to install the dependencies
31
-
32
- You can now work on `x`. We prefer [🔗Visual Studio Code](https://code.visualstudio.com/) as our development environment (it's cross-platform and awesome), but please use what you feel comfortable with (we'll even forgive you for using vim).
33
-
34
- ### 🧪 Code Quality
35
-
36
- #### Manual
37
-
38
- We love code reviews. If there are open pull requests, please feel free to review them and provide feedback. Feedback is a gift and code reviews are often a bottleneck in getting new things released. Jump in, even if you don't know anything; you probably know more than you think.
39
-
40
- 💭**REMEMBER** Be kind and considerate. Folks are volunteering their time and code reviews are a moment of vulnerability where a criticism of the code can easily become a criticism of the individual that wrote it.
41
-
42
- 1. Take your time
43
- 2. Consider how you might receive the feedback you are giving if it were attached to code you wrote
44
- 3. Favor asking questions over prescribing solutions.
45
-
46
- #### Automated
47
-
48
- To ensure code quality, we use TypeScript, biome, and vitest. These are all executed when you submit a pull request to ensure contributions meet our code quality standards.
49
-
50
- To execute these operations outside of a pull request, you can use `pnpm`.
51
-
52
- - `pnpm typecheck`
53
- - `pnpm lint`
54
- - `pnpm test`
55
-
56
- If you make changes that change snapshots, you may need to run tests with the `-u` vitest option and commit the updated snapshot files along with the rest of your contribution.
57
-
58
- 💭**REMEMBER** If you would like to contribute code changes to the project, first make sure there's a corresponding issue for the change you wish to make.
59
-
60
- ## 📦 Build And Publish
61
-
62
- Anyone can create a local build of the distributed code by running `pnpm build`.
63
-
64
- Running the build will execute tests first.
65
-
66
- ### Publishing
67
-
68
- Publishing is automated through our use of [changesets][1]. When a PR is merged to `main`, a release PR is created that bundles all the changes since the last release. When we are ready to release, this bundled PR is merged to `main` which triggers changesets to publish to npm via trusted publishing.
69
-
70
- [1]:https://github.com/changesets/changesets/blob/main/README.md#documentation
package/biome.json DELETED
@@ -1,39 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/2.4.3/schema.json",
3
- "formatter": {
4
- "enabled": true,
5
- "indentStyle": "space",
6
- "indentWidth": 4,
7
- "bracketSpacing": false,
8
- "includes": ["**", "!dist/**", "!coverage/**"]
9
- },
10
- "linter": {
11
- "enabled": true,
12
- "includes": ["**", "!dist/**", "!coverage/**"]
13
- },
14
- "assist": {
15
- "enabled": true,
16
- "includes": ["**", "!dist/**", "!coverage/**"]
17
- },
18
- "overrides": [
19
- {
20
- "includes": ["**/*.test.*"],
21
- "linter": {
22
- "rules": {
23
- "suspicious": {
24
- "noExplicitAny": "off"
25
- }
26
- }
27
- }
28
- },
29
- {
30
- "includes": ["*.json", "*.jsonc"],
31
- "json": {
32
- "parser": {
33
- "allowComments": true,
34
- "allowTrailingCommas": true
35
- }
36
- }
37
- }
38
- ]
39
- }
@@ -1,285 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import {beforeEach, describe, expect, it, vi} from "vitest";
4
- import {buildEnvironment} from "../build-environment";
5
-
6
- // Mock the fs module
7
- vi.mock("node:fs/promises", () => ({
8
- readFile: vi.fn(),
9
- }));
10
-
11
- describe("buildEnvironment", () => {
12
- beforeEach(() => {
13
- vi.clearAllMocks();
14
- });
15
-
16
- it("should preserve existing environment variables", async () => {
17
- // Arrange
18
- const workspaceRoot = "/test/workspace";
19
- const currentEnv = {
20
- EXISTING_VAR: "existing-value",
21
- PATH: "/usr/bin:/bin",
22
- };
23
-
24
- vi.mocked(fs.readFile).mockResolvedValue(
25
- JSON.stringify({
26
- name: "test-workspace",
27
- version: "1.0.0",
28
- }),
29
- );
30
-
31
- // Act
32
- const env = await buildEnvironment(workspaceRoot, currentEnv);
33
-
34
- // Assert
35
- expect(env.EXISTING_VAR).toBe("existing-value");
36
- });
37
-
38
- it("should prepend workspace node_modules/.bin to PATH", async () => {
39
- // Arrange
40
- const workspaceRoot = "/test/workspace";
41
- const currentEnv = {
42
- PATH: "/usr/bin:/bin",
43
- };
44
-
45
- vi.mocked(fs.readFile).mockResolvedValue(
46
- JSON.stringify({
47
- name: "test-workspace",
48
- }),
49
- );
50
-
51
- // Act
52
- const env = await buildEnvironment(workspaceRoot, currentEnv);
53
-
54
- // Assert
55
- const expectedPath = path.join(workspaceRoot, "node_modules", ".bin");
56
- expect(env.PATH).toContain(expectedPath);
57
- });
58
-
59
- it("should set npm_command to exec", async () => {
60
- // Arrange
61
- const workspaceRoot = "/test/workspace";
62
- const currentEnv = {PATH: "/usr/bin"};
63
-
64
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
65
-
66
- // Act
67
- const env = await buildEnvironment(workspaceRoot, currentEnv);
68
-
69
- // Assert
70
- expect(env.npm_command).toBe("exec");
71
- });
72
-
73
- it("should set INIT_CWD to current working directory", async () => {
74
- // Arrange
75
- const workspaceRoot = "/test/workspace";
76
- const currentEnv = {PATH: "/usr/bin"};
77
- const expectedCwd = process.cwd();
78
-
79
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
80
-
81
- // Act
82
- const env = await buildEnvironment(workspaceRoot, currentEnv);
83
-
84
- // Assert
85
- expect(env.INIT_CWD).toBe(expectedCwd);
86
- });
87
-
88
- it("should set npm_package_name from workspace package.json", async () => {
89
- // Arrange
90
- const workspaceRoot = "/test/workspace";
91
- const currentEnv = {PATH: "/usr/bin"};
92
-
93
- vi.mocked(fs.readFile).mockResolvedValue(
94
- JSON.stringify({
95
- name: "my-workspace",
96
- version: "2.5.0",
97
- }),
98
- );
99
-
100
- // Act
101
- const env = await buildEnvironment(workspaceRoot, currentEnv);
102
-
103
- // Assert
104
- expect(env.npm_package_name).toBe("my-workspace");
105
- });
106
-
107
- it("should set npm_package_version from workspace package.json", async () => {
108
- // Arrange
109
- const workspaceRoot = "/test/workspace";
110
- const currentEnv = {PATH: "/usr/bin"};
111
-
112
- vi.mocked(fs.readFile).mockResolvedValue(
113
- JSON.stringify({
114
- name: "my-workspace",
115
- version: "2.5.0",
116
- }),
117
- );
118
-
119
- // Act
120
- const env = await buildEnvironment(workspaceRoot, currentEnv);
121
-
122
- // Assert
123
- expect(env.npm_package_version).toBe("2.5.0");
124
- });
125
-
126
- it("should set npm_execpath to node executable path", async () => {
127
- // Arrange
128
- const workspaceRoot = "/test/workspace";
129
- const currentEnv = {PATH: "/usr/bin"};
130
-
131
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
132
-
133
- // Act
134
- const env = await buildEnvironment(workspaceRoot, currentEnv);
135
-
136
- // Assert
137
- expect(env.npm_execpath).toBe(process.execPath);
138
- });
139
-
140
- it("should include package name in npm_config_user_agent", async () => {
141
- // Arrange
142
- const workspaceRoot = "/test/workspace";
143
- const currentEnv = {PATH: "/usr/bin"};
144
-
145
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
146
-
147
- // Act
148
- const env = await buildEnvironment(workspaceRoot, currentEnv);
149
-
150
- // Assert
151
- expect(env.npm_config_user_agent).toContain("x/");
152
- });
153
-
154
- it("should include node version in npm_config_user_agent", async () => {
155
- // Arrange
156
- const workspaceRoot = "/test/workspace";
157
- const currentEnv = {PATH: "/usr/bin"};
158
-
159
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
160
-
161
- // Act
162
- const env = await buildEnvironment(workspaceRoot, currentEnv);
163
-
164
- // Assert
165
- expect(env.npm_config_user_agent).toContain("node/");
166
- });
167
-
168
- it("should set npm_command to exec when package.json is missing", async () => {
169
- // Arrange
170
- const workspaceRoot = "/test/workspace";
171
- const currentEnv = {PATH: "/usr/bin"};
172
-
173
- vi.mocked(fs.readFile).mockRejectedValue(
174
- new Error("ENOENT: no such file"),
175
- );
176
-
177
- // Act
178
- const env = await buildEnvironment(workspaceRoot, currentEnv);
179
-
180
- // Assert
181
- expect(env.npm_command).toBe("exec");
182
- });
183
-
184
- it("should set INIT_CWD when package.json is missing", async () => {
185
- // Arrange
186
- const workspaceRoot = "/test/workspace";
187
- const currentEnv = {PATH: "/usr/bin"};
188
-
189
- vi.mocked(fs.readFile).mockRejectedValue(
190
- new Error("ENOENT: no such file"),
191
- );
192
-
193
- // Act
194
- const env = await buildEnvironment(workspaceRoot, currentEnv);
195
-
196
- // Assert
197
- expect(env.INIT_CWD).toBe(process.cwd());
198
- });
199
-
200
- it("should include npm_package_description if present", async () => {
201
- // Arrange
202
- const workspaceRoot = "/test/workspace";
203
- const currentEnv = {PATH: "/usr/bin"};
204
-
205
- vi.mocked(fs.readFile).mockResolvedValue(
206
- JSON.stringify({
207
- name: "my-workspace",
208
- description: "A test workspace",
209
- }),
210
- );
211
-
212
- // Act
213
- const env = await buildEnvironment(workspaceRoot, currentEnv);
214
-
215
- // Assert
216
- expect(env.npm_package_description).toBe("A test workspace");
217
- });
218
-
219
- it("should convert object fields to JSON strings", async () => {
220
- // Arrange
221
- const workspaceRoot = "/test/workspace";
222
- const currentEnv = {PATH: "/usr/bin"};
223
-
224
- vi.mocked(fs.readFile).mockResolvedValue(
225
- JSON.stringify({
226
- name: "my-workspace",
227
- repository: {
228
- type: "git",
229
- url: "https://github.com/test/repo",
230
- },
231
- }),
232
- );
233
-
234
- // Act
235
- const env = await buildEnvironment(workspaceRoot, currentEnv);
236
-
237
- // Assert
238
- expect(env.npm_package_repository).toBe(
239
- JSON.stringify({
240
- type: "git",
241
- url: "https://github.com/test/repo",
242
- }),
243
- );
244
- });
245
-
246
- it("should set npm_package_license from workspace package.json", async () => {
247
- // Arrange
248
- const workspaceRoot = "/test/workspace";
249
- const currentEnv = {PATH: "/usr/bin"};
250
-
251
- vi.mocked(fs.readFile).mockResolvedValue(
252
- JSON.stringify({
253
- name: "my-workspace",
254
- license: "MIT",
255
- author: "John Doe",
256
- }),
257
- );
258
-
259
- // Act
260
- const env = await buildEnvironment(workspaceRoot, currentEnv);
261
-
262
- // Assert
263
- expect(env.npm_package_license).toBe("MIT");
264
- });
265
-
266
- it("should set npm_package_author from workspace package.json", async () => {
267
- // Arrange
268
- const workspaceRoot = "/test/workspace";
269
- const currentEnv = {PATH: "/usr/bin"};
270
-
271
- vi.mocked(fs.readFile).mockResolvedValue(
272
- JSON.stringify({
273
- name: "my-workspace",
274
- license: "MIT",
275
- author: "John Doe",
276
- }),
277
- );
278
-
279
- // Act
280
- const env = await buildEnvironment(workspaceRoot, currentEnv);
281
-
282
- // Assert
283
- expect(env.npm_package_author).toBe("John Doe");
284
- });
285
- });
@@ -1,196 +0,0 @@
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
- });