@kcconfigs/commitlint 0.0.1 → 0.1.0-beta.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/CHANGELOG.md +35 -0
- package/dist/index.cjs +216 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +210 -0
- package/dist/index.js.map +1 -0
- package/dist/lib-26NWB_Cl.cjs +142 -0
- package/dist/lib-26NWB_Cl.cjs.map +1 -0
- package/dist/lib-CzUh7oEE.cjs +31 -0
- package/dist/lib-CzUh7oEE.cjs.map +1 -0
- package/dist/lib-D5qzG1z4.js +25 -0
- package/dist/lib-D5qzG1z4.js.map +1 -0
- package/dist/lib-DPex9ONF.js +142 -0
- package/dist/lib-DPex9ONF.js.map +1 -0
- package/package.json +58 -1
- package/src/apis/projects.test.ts +344 -0
- package/src/apis/projects.ts +52 -0
- package/src/apis/scopes.test.ts +126 -0
- package/src/apis/scopes.ts +56 -0
- package/src/apis/types.test.ts +88 -0
- package/src/apis/types.ts +103 -0
- package/src/index.test.ts +497 -0
- package/src/index.ts +82 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { cwd } from "node:process";
|
|
2
|
+
import { vol } from "@kcconfigs/vitest/mocks";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
4
|
+
import { findBunPackages, findNpmPackages, findPnpmPackages } from "./projects";
|
|
5
|
+
|
|
6
|
+
describe("Project APIs", () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vol.reset();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe(findNpmPackages.name, () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.mocked(cwd).mockReturnValue("/mock/npm-workspace");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("should find empty packages when no workspaces defined", async () => {
|
|
17
|
+
vol.fromJSON(
|
|
18
|
+
{
|
|
19
|
+
"./package.json": JSON.stringify({
|
|
20
|
+
name: "npm-workspace",
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
cwd(),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const packages = await findNpmPackages(false);
|
|
27
|
+
|
|
28
|
+
expect(cwd()).toEqual("/mock/npm-workspace");
|
|
29
|
+
expect(packages).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("should return workspace packages without root", async () => {
|
|
33
|
+
vol.fromJSON(
|
|
34
|
+
{
|
|
35
|
+
"./package.json": JSON.stringify({
|
|
36
|
+
name: "npm-workspace",
|
|
37
|
+
workspaces: ["packages/*"],
|
|
38
|
+
}),
|
|
39
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
40
|
+
name: "@scope/pkg-a",
|
|
41
|
+
}),
|
|
42
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
43
|
+
name: "@scope/pkg-b",
|
|
44
|
+
}),
|
|
45
|
+
},
|
|
46
|
+
cwd(),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const packages = await findNpmPackages(false);
|
|
50
|
+
|
|
51
|
+
expect(cwd()).toEqual("/mock/npm-workspace");
|
|
52
|
+
expect(packages.sort()).toEqual(["scope/pkg-a", "scope/pkg-b"].sort());
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("should return workspace packages with root", async () => {
|
|
56
|
+
vol.fromJSON(
|
|
57
|
+
{
|
|
58
|
+
"./package.json": JSON.stringify({
|
|
59
|
+
name: "npm-workspace",
|
|
60
|
+
workspaces: ["**"],
|
|
61
|
+
}),
|
|
62
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
63
|
+
name: "@scope/pkg-a",
|
|
64
|
+
}),
|
|
65
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
66
|
+
name: "@scope/pkg-b",
|
|
67
|
+
}),
|
|
68
|
+
},
|
|
69
|
+
cwd(),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const packages = await findNpmPackages(true);
|
|
73
|
+
|
|
74
|
+
expect(cwd()).toEqual("/mock/npm-workspace");
|
|
75
|
+
expect(packages.sort()).toEqual(
|
|
76
|
+
["npm-workspace", "scope/pkg-a", "scope/pkg-b"].sort(),
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("should fallback to directory name when manifest name missing", async () => {
|
|
81
|
+
vol.fromJSON(
|
|
82
|
+
{
|
|
83
|
+
"./package.json": JSON.stringify({
|
|
84
|
+
name: "npm-workspace",
|
|
85
|
+
workspaces: ["packages/*"],
|
|
86
|
+
}),
|
|
87
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
88
|
+
version: "1.0.0",
|
|
89
|
+
}),
|
|
90
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
91
|
+
version: "1.0.0",
|
|
92
|
+
}),
|
|
93
|
+
},
|
|
94
|
+
cwd(),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const packages = await findNpmPackages(false);
|
|
98
|
+
|
|
99
|
+
expect(cwd()).toEqual("/mock/npm-workspace");
|
|
100
|
+
expect(packages.sort()).toEqual(["pkg-a", "pkg-b"].sort());
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("should handle packages without scope prefix", async () => {
|
|
104
|
+
vol.fromJSON(
|
|
105
|
+
{
|
|
106
|
+
"./package.json": JSON.stringify({
|
|
107
|
+
name: "npm-workspace",
|
|
108
|
+
workspaces: ["packages/*"],
|
|
109
|
+
}),
|
|
110
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
111
|
+
name: "pkg-a",
|
|
112
|
+
}),
|
|
113
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
114
|
+
name: "pkg-b",
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
cwd(),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const packages = await findNpmPackages(false);
|
|
121
|
+
|
|
122
|
+
expect(cwd()).toEqual("/mock/npm-workspace");
|
|
123
|
+
expect(packages.sort()).toEqual(["pkg-a", "pkg-b"].sort());
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe(findPnpmPackages.name, () => {
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
vi.mocked(cwd).mockReturnValue("/mock/pnpm-workspace");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("should find empty packages when no packages defined", async () => {
|
|
133
|
+
vol.fromJSON(
|
|
134
|
+
{
|
|
135
|
+
"./pnpm-workspace.yaml": "",
|
|
136
|
+
},
|
|
137
|
+
cwd(),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const packages = await findPnpmPackages(false);
|
|
141
|
+
|
|
142
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
143
|
+
expect(packages).toEqual([]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("should return workspace packages without root", async () => {
|
|
147
|
+
vol.fromJSON(
|
|
148
|
+
{
|
|
149
|
+
"./pnpm-workspace.yaml": "packages:\n - 'packages/*'",
|
|
150
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
151
|
+
name: "@scope/pkg-a",
|
|
152
|
+
}),
|
|
153
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
154
|
+
name: "@scope/pkg-b",
|
|
155
|
+
}),
|
|
156
|
+
},
|
|
157
|
+
cwd(),
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const packages = await findPnpmPackages(false);
|
|
161
|
+
|
|
162
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
163
|
+
expect(packages.sort()).toEqual(["scope/pkg-a", "scope/pkg-b"].sort());
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("should return workspace packages with root", async () => {
|
|
167
|
+
vol.fromJSON(
|
|
168
|
+
{
|
|
169
|
+
"./pnpm-workspace.yaml": "packages:\n - '**'",
|
|
170
|
+
"./package.json": JSON.stringify({
|
|
171
|
+
name: "pnpm-workspace",
|
|
172
|
+
}),
|
|
173
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
174
|
+
name: "@scope/pkg-a",
|
|
175
|
+
}),
|
|
176
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
177
|
+
name: "@scope/pkg-b",
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
cwd(),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const packages = await findPnpmPackages(true);
|
|
184
|
+
|
|
185
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
186
|
+
expect(packages.sort()).toEqual(
|
|
187
|
+
["pnpm-workspace", "scope/pkg-a", "scope/pkg-b"].sort(),
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("should fallback to directory name when manifest name missing", async () => {
|
|
192
|
+
vol.fromJSON(
|
|
193
|
+
{
|
|
194
|
+
"./pnpm-workspace.yaml": "packages:\n - 'packages/*'",
|
|
195
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
196
|
+
version: "1.0.0",
|
|
197
|
+
}),
|
|
198
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
199
|
+
version: "1.0.0",
|
|
200
|
+
}),
|
|
201
|
+
},
|
|
202
|
+
cwd(),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const packages = await findPnpmPackages(false);
|
|
206
|
+
|
|
207
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
208
|
+
expect(packages.sort()).toEqual(["pkg-a", "pkg-b"].sort());
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("should handle multiple package patterns", async () => {
|
|
212
|
+
vol.fromJSON(
|
|
213
|
+
{
|
|
214
|
+
"./pnpm-workspace.yaml": "packages:\n - 'packages/*'\n - 'apps/*'",
|
|
215
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
216
|
+
name: "@scope/pkg-a",
|
|
217
|
+
}),
|
|
218
|
+
"./apps/app-a/package.json": JSON.stringify({
|
|
219
|
+
name: "@scope/app-a",
|
|
220
|
+
}),
|
|
221
|
+
},
|
|
222
|
+
cwd(),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const packages = await findPnpmPackages(false);
|
|
226
|
+
|
|
227
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
228
|
+
expect(packages.sort()).toEqual(["scope/pkg-a", "scope/app-a"].sort());
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("should default to false when includeRoot is undefined", async () => {
|
|
232
|
+
vol.fromJSON(
|
|
233
|
+
{
|
|
234
|
+
"./pnpm-workspace.yaml": "packages:\n - '**'",
|
|
235
|
+
"./package.json": JSON.stringify({
|
|
236
|
+
name: "pnpm-workspace",
|
|
237
|
+
}),
|
|
238
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
239
|
+
name: "@scope/pkg-a",
|
|
240
|
+
}),
|
|
241
|
+
},
|
|
242
|
+
cwd(),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const packages = await findPnpmPackages();
|
|
246
|
+
|
|
247
|
+
expect(cwd()).toEqual("/mock/pnpm-workspace");
|
|
248
|
+
expect(packages.sort()).toEqual(["scope/pkg-a"].sort());
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe(findBunPackages.name, () => {
|
|
253
|
+
beforeEach(() => {
|
|
254
|
+
vi.mocked(cwd).mockReturnValue("/mock/bun-workspace");
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test("should find empty packages when no workspaces defined", async () => {
|
|
258
|
+
vol.fromJSON(
|
|
259
|
+
{
|
|
260
|
+
"./package.json": JSON.stringify({
|
|
261
|
+
name: "bun-workspace",
|
|
262
|
+
}),
|
|
263
|
+
},
|
|
264
|
+
cwd(),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const packages = await findBunPackages(false);
|
|
268
|
+
|
|
269
|
+
expect(cwd()).toEqual("/mock/bun-workspace");
|
|
270
|
+
expect(packages).toEqual([]);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("should return workspace packages without root", async () => {
|
|
274
|
+
vol.fromJSON(
|
|
275
|
+
{
|
|
276
|
+
"./package.json": JSON.stringify({
|
|
277
|
+
name: "bun-workspace",
|
|
278
|
+
workspaces: ["packages/*"],
|
|
279
|
+
}),
|
|
280
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
281
|
+
name: "@scope/pkg-a",
|
|
282
|
+
}),
|
|
283
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
284
|
+
name: "@scope/pkg-b",
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
cwd(),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const packages = await findBunPackages(false);
|
|
291
|
+
|
|
292
|
+
expect(cwd()).toEqual("/mock/bun-workspace");
|
|
293
|
+
expect(packages.sort()).toEqual(["scope/pkg-a", "scope/pkg-b"].sort());
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("should return workspace packages with root", async () => {
|
|
297
|
+
vol.fromJSON(
|
|
298
|
+
{
|
|
299
|
+
"./package.json": JSON.stringify({
|
|
300
|
+
name: "bun-workspace",
|
|
301
|
+
workspaces: ["**"],
|
|
302
|
+
}),
|
|
303
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
304
|
+
name: "@scope/pkg-a",
|
|
305
|
+
}),
|
|
306
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
307
|
+
name: "@scope/pkg-b",
|
|
308
|
+
}),
|
|
309
|
+
},
|
|
310
|
+
cwd(),
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const packages = await findBunPackages(true);
|
|
314
|
+
|
|
315
|
+
expect(cwd()).toEqual("/mock/bun-workspace");
|
|
316
|
+
expect(packages.sort()).toEqual(
|
|
317
|
+
["bun-workspace", "scope/pkg-a", "scope/pkg-b"].sort(),
|
|
318
|
+
);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("should fallback to directory name when manifest name missing", async () => {
|
|
322
|
+
vol.fromJSON(
|
|
323
|
+
{
|
|
324
|
+
"./package.json": JSON.stringify({
|
|
325
|
+
name: "bun-workspace",
|
|
326
|
+
workspaces: ["packages/*"],
|
|
327
|
+
}),
|
|
328
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
329
|
+
version: "1.0.0",
|
|
330
|
+
}),
|
|
331
|
+
"./packages/pkg-b/package.json": JSON.stringify({
|
|
332
|
+
version: "1.0.0",
|
|
333
|
+
}),
|
|
334
|
+
},
|
|
335
|
+
cwd(),
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const packages = await findBunPackages(false);
|
|
339
|
+
|
|
340
|
+
expect(cwd()).toEqual("/mock/bun-workspace");
|
|
341
|
+
expect(packages.sort()).toEqual(["pkg-a", "pkg-b"].sort());
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import { cwd as wd } from "node:process";
|
|
4
|
+
import { findWorkspacePackagesNoCheck } from "@pnpm/workspace.find-packages";
|
|
5
|
+
import { parse } from "yaml";
|
|
6
|
+
|
|
7
|
+
const findPackages = async (
|
|
8
|
+
cwd: string,
|
|
9
|
+
patterns: WithUndefined<string[]>,
|
|
10
|
+
includeRoot: WithUndefined<boolean>,
|
|
11
|
+
) => {
|
|
12
|
+
const packages = await findWorkspacePackagesNoCheck(cwd, {
|
|
13
|
+
patterns: patterns ?? ["**"],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return packages
|
|
17
|
+
.filter((pkg) => (includeRoot ?? false) || pkg.rootDir !== cwd)
|
|
18
|
+
.map((pkg) => pkg.manifest.name ?? basename(pkg.rootDirRealPath))
|
|
19
|
+
.map((name) => (name.startsWith("@") ? name.slice(1) : name));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const findPnpmPackages = async (
|
|
23
|
+
includeRoot?: boolean,
|
|
24
|
+
): Promise<string[]> => {
|
|
25
|
+
const cwd = wd();
|
|
26
|
+
|
|
27
|
+
const pnpmWorkspace = await readFile(join(cwd, "pnpm-workspace.yaml"), {
|
|
28
|
+
encoding: "utf8",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const workspace = parse(pnpmWorkspace);
|
|
32
|
+
return findPackages(cwd, workspace?.packages, includeRoot);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const findNpmPackages = async (
|
|
36
|
+
includeRoot?: boolean,
|
|
37
|
+
): Promise<string[]> => {
|
|
38
|
+
const cwd = wd();
|
|
39
|
+
|
|
40
|
+
const { workspaces } = JSON.parse(
|
|
41
|
+
await readFile(join(cwd, "package.json"), {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
return findPackages(cwd, workspaces, includeRoot);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const findBunPackages = async (
|
|
49
|
+
includeRoot?: boolean,
|
|
50
|
+
): Promise<string[]> => {
|
|
51
|
+
return findNpmPackages(includeRoot);
|
|
52
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { cwd } from "node:process";
|
|
2
|
+
import { vol } from "@kcconfigs/vitest/mocks";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
4
|
+
import { getScopes } from "./scopes";
|
|
5
|
+
|
|
6
|
+
describe("Scopes APIs", () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vol.reset();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe(getScopes.name, () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.mocked(cwd).mockReturnValue("/mock/workspace");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("should return default scopes when auto is false and no scopes provided", async () => {
|
|
17
|
+
const scopes = await getScopes(false);
|
|
18
|
+
|
|
19
|
+
expect(scopes.sort()).toEqual(
|
|
20
|
+
["core", "config", "script", "deps", "deps-dev"].sort(),
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("should return user-provided scopes when auto is false", async () => {
|
|
25
|
+
const scopes = await getScopes(false, ["custom1", "custom2"]);
|
|
26
|
+
|
|
27
|
+
expect(scopes.sort()).toEqual(["custom1", "custom2"].sort());
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("should detect pnpm workspace and return package scopes", async () => {
|
|
31
|
+
vol.fromJSON(
|
|
32
|
+
{
|
|
33
|
+
"./pnpm-workspace.yaml": "packages:\n - 'packages/*'",
|
|
34
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
35
|
+
name: "@scope/pkg-a",
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
cwd(),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const scopes = await getScopes(true);
|
|
42
|
+
|
|
43
|
+
expect(scopes.sort()).toEqual(["scope/pkg-a"].sort());
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("should detect bun workspace with bun.lock", async () => {
|
|
47
|
+
vol.fromJSON(
|
|
48
|
+
{
|
|
49
|
+
"./bun.lock": "",
|
|
50
|
+
"./package.json": JSON.stringify({
|
|
51
|
+
name: "bun-workspace",
|
|
52
|
+
workspaces: ["packages/*"],
|
|
53
|
+
}),
|
|
54
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
55
|
+
name: "@scope/pkg-a",
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
cwd(),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const scopes = await getScopes(true);
|
|
62
|
+
|
|
63
|
+
expect(scopes.sort()).toEqual(["scope/pkg-a"].sort());
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("should detect bun workspace with bun.lockb", async () => {
|
|
67
|
+
vol.fromJSON(
|
|
68
|
+
{
|
|
69
|
+
"./bun.lockb": "",
|
|
70
|
+
"./package.json": JSON.stringify({
|
|
71
|
+
name: "bun-workspace",
|
|
72
|
+
workspaces: ["packages/*"],
|
|
73
|
+
}),
|
|
74
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
75
|
+
name: "@scope/pkg-a",
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
cwd(),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const scopes = await getScopes(true);
|
|
82
|
+
|
|
83
|
+
expect(scopes.sort()).toEqual(["scope/pkg-a"].sort());
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("should fallback to npm when no specific workspace file found", async () => {
|
|
87
|
+
vol.fromJSON(
|
|
88
|
+
{
|
|
89
|
+
"./package.json": JSON.stringify({
|
|
90
|
+
name: "npm-workspace",
|
|
91
|
+
workspaces: ["packages/*"],
|
|
92
|
+
}),
|
|
93
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
94
|
+
name: "@scope/pkg-a",
|
|
95
|
+
}),
|
|
96
|
+
},
|
|
97
|
+
cwd(),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const scopes = await getScopes(true);
|
|
101
|
+
|
|
102
|
+
expect(scopes.sort()).toEqual(["scope/pkg-a"].sort());
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("should merge user scopes with auto-detected scopes", async () => {
|
|
106
|
+
vol.fromJSON(
|
|
107
|
+
{
|
|
108
|
+
"./package.json": JSON.stringify({
|
|
109
|
+
name: "npm-workspace",
|
|
110
|
+
workspaces: ["packages/*"],
|
|
111
|
+
}),
|
|
112
|
+
"./packages/pkg-a/package.json": JSON.stringify({
|
|
113
|
+
name: "@scope/pkg-a",
|
|
114
|
+
}),
|
|
115
|
+
},
|
|
116
|
+
cwd(),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const scopes = await getScopes(true, ["custom1", "custom2"]);
|
|
120
|
+
|
|
121
|
+
expect(scopes.sort()).toEqual(
|
|
122
|
+
["custom1", "custom2", "scope/pkg-a"].sort(),
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { cwd as wd } from "node:process";
|
|
4
|
+
import { findBunPackages, findNpmPackages, findPnpmPackages } from "./projects";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Automatically detects and retrieves project scopes based on the package manager in use.
|
|
8
|
+
*
|
|
9
|
+
* Determines the package manager by checking for workspace configuration files:
|
|
10
|
+
* - pnpm: Checks for pnpm-workspace.yaml
|
|
11
|
+
* - bun: Checks for bun.lock or bun.lockb
|
|
12
|
+
* - npm: Falls back to npm package detection
|
|
13
|
+
*
|
|
14
|
+
* @param includeRoot - Whether to include the root package in the results
|
|
15
|
+
* @returns Array of detected project scope names
|
|
16
|
+
*/
|
|
17
|
+
const getAutoScope = (includeRoot: boolean) => {
|
|
18
|
+
const cwd = wd();
|
|
19
|
+
|
|
20
|
+
if (existsSync(join(cwd, "pnpm-workspace.yaml"))) {
|
|
21
|
+
return findPnpmPackages(includeRoot);
|
|
22
|
+
} else if (
|
|
23
|
+
existsSync(join(cwd, "bun.lock")) ||
|
|
24
|
+
existsSync(join(cwd, "bun.lockb"))
|
|
25
|
+
) {
|
|
26
|
+
return findBunPackages(includeRoot);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return findNpmPackages(includeRoot);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Retrieves a merged list of commit scopes based on automatic detection and user input.
|
|
34
|
+
*
|
|
35
|
+
* Combines user-provided scopes with automatically detected project scopes.
|
|
36
|
+
* If no scopes are provided, returns a default set of common scope categories.
|
|
37
|
+
*
|
|
38
|
+
* @param auto - Whether to automatically detect scopes from workspace packages
|
|
39
|
+
* @param scopes - Optional user-provided scopes to include
|
|
40
|
+
* @returns Merged array of all available scopes
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
export const getScopes = async (
|
|
44
|
+
auto: boolean,
|
|
45
|
+
scopes?: string[],
|
|
46
|
+
): Promise<string[]> => {
|
|
47
|
+
const _scopes: string[] = [];
|
|
48
|
+
|
|
49
|
+
if (scopes) _scopes.push(...scopes);
|
|
50
|
+
if (auto) _scopes.push(...(await getAutoScope(false)));
|
|
51
|
+
|
|
52
|
+
if (_scopes.length === 0) {
|
|
53
|
+
_scopes.push("core", "config", "script", "deps", "deps-dev");
|
|
54
|
+
}
|
|
55
|
+
return _scopes;
|
|
56
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** biome-ignore-all lint/complexity/useLiteralKeys: Conflict with ts(4111) */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from "vitest";
|
|
4
|
+
import { getTypes } from "./types";
|
|
5
|
+
|
|
6
|
+
describe("Types APIs", () => {
|
|
7
|
+
describe(getTypes.name, () => {
|
|
8
|
+
test("should return standard types when mode is 'standard'", () => {
|
|
9
|
+
const types = getTypes("standard");
|
|
10
|
+
|
|
11
|
+
expect(Object.keys(types).sort()).toEqual(
|
|
12
|
+
[
|
|
13
|
+
"feat",
|
|
14
|
+
"perf",
|
|
15
|
+
"fix",
|
|
16
|
+
"docs",
|
|
17
|
+
"test",
|
|
18
|
+
"style",
|
|
19
|
+
"build",
|
|
20
|
+
"refactor",
|
|
21
|
+
"ci",
|
|
22
|
+
"chore",
|
|
23
|
+
"revert",
|
|
24
|
+
].sort(),
|
|
25
|
+
);
|
|
26
|
+
expect(types["feat"]).toEqual({
|
|
27
|
+
description: "A new feature",
|
|
28
|
+
title: "Features",
|
|
29
|
+
emoji: "✨",
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should return minimal types when mode is 'minimal'", () => {
|
|
34
|
+
const types = getTypes("minimal");
|
|
35
|
+
|
|
36
|
+
expect(Object.keys(types).sort()).toEqual(
|
|
37
|
+
["feat", "perf", "fix", "chore"].sort(),
|
|
38
|
+
);
|
|
39
|
+
expect(types["feat"]).toEqual({
|
|
40
|
+
description: "A new feature",
|
|
41
|
+
title: "Features",
|
|
42
|
+
emoji: "✨",
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("should return custom types when mode is an array", () => {
|
|
47
|
+
const types = getTypes(["custom1", "custom2", "custom3"]);
|
|
48
|
+
|
|
49
|
+
expect(Object.keys(types).sort()).toEqual(
|
|
50
|
+
["custom1", "custom2", "custom3"].sort(),
|
|
51
|
+
);
|
|
52
|
+
expect(types["custom1"]).toEqual({});
|
|
53
|
+
expect(types["custom2"]).toEqual({});
|
|
54
|
+
expect(types["custom3"]).toEqual({});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("should return custom types when mode is an object", () => {
|
|
58
|
+
const customTypes = {
|
|
59
|
+
type1: {
|
|
60
|
+
description: "Custom type 1",
|
|
61
|
+
title: "Type 1",
|
|
62
|
+
emoji: "🎨",
|
|
63
|
+
},
|
|
64
|
+
type2: {
|
|
65
|
+
description: "Custom type 2",
|
|
66
|
+
title: "Type 2",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const types = getTypes(customTypes);
|
|
71
|
+
|
|
72
|
+
expect(types).toEqual(customTypes);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("should handle empty array", () => {
|
|
76
|
+
const types = getTypes([]);
|
|
77
|
+
|
|
78
|
+
expect(types).toEqual({});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("should handle single type in array", () => {
|
|
82
|
+
const types = getTypes(["single"]);
|
|
83
|
+
|
|
84
|
+
expect(Object.keys(types)).toEqual(["single"]);
|
|
85
|
+
expect(types["single"]).toEqual({});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|