Skip to content

Commit 206be26

Browse files
committed
Adopt catalogs.yml
1 parent 7e33539 commit 206be26

File tree

11 files changed

+202
-94
lines changed

11 files changed

+202
-94
lines changed

README.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,20 @@ yarn plugin import https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/m
2727

2828
## Features
2929

30-
This plugin adds the `catalogsOptions` configuration to `.yarnrc.yml`:
30+
This plugin reads extended options from `catalogs.yml` in your project root:
3131

3232
### Default Alias Groups
3333

3434
Automatically applies catalog protocols when adding dependencies.
3535

3636
```yaml
37-
# in .yarnrc.yml
38-
catalogsOptions:
37+
# in catalogs.yml
38+
options:
3939
default: [beta, legacy] # Priority order
40+
```
4041
42+
```yaml
43+
# in .yarnrc.yml
4144
catalogs:
4245
beta:
4346
react: npm:19.0.0
@@ -54,9 +57,13 @@ yarn add typescript # Automatically becomes: yarn add typescript@catalog:legacy
5457
#### Using `root` as Default
5558

5659
```yaml
57-
catalogsOptions:
60+
# in catalogs.yml
61+
options:
5862
default: [root] # Use root catalog as default
63+
```
5964
65+
```yaml
66+
# in .yarnrc.yml
6067
catalog:
6168
react: npm:19.0.0
6269
react-dom: npm:19.0.0
@@ -71,9 +78,13 @@ yarn add react # Same as: yarn add react@catalog:
7178
The `max` option selects the most frequently used catalog in your package.json.
7279

7380
```yaml
74-
catalogsOptions:
81+
# in catalogs.yml
82+
options:
7583
default: max
84+
```
7685
86+
```yaml
87+
# in .yarnrc.yml
7788
catalogs:
7889
beta:
7990
react: npm:19.0.0
@@ -102,9 +113,13 @@ yarn add next # Will use "catalog:beta" (most frequent)
102113
Disable catalog features for specific workspaces using glob patterns.
103114

104115
```yaml
105-
catalogsOptions:
116+
# in catalogs.yml
117+
options:
106118
ignoredWorkspaces: [package, test-*]
119+
```
107120
121+
```yaml
122+
# in .yarnrc.yml
108123
catalog:
109124
react: npm:19.0.0
110125
```
@@ -119,9 +134,13 @@ Ignored workspaces:
119134
Enforce catalog usage when dependencies listed in catalogs are added with actual versions.
120135

121136
```yaml
122-
catalogsOptions:
137+
# in catalogs.yml
138+
options:
123139
validation: warn # "warn" | "strict" | "off"
140+
```
124141

142+
```yaml
143+
# in .yarnrc.yml
125144
catalog:
126145
react: npm:19.0.0
127146
lodash: npm:4.17.21
@@ -136,12 +155,16 @@ catalog:
136155
Configure different validation levels for different catalog groups:
137156

138157
```yaml
139-
catalogsOptions:
158+
# in catalogs.yml
159+
options:
140160
validation:
141161
beta: warn
142162
stable: strict
143163
legacy: off
164+
```
144165

166+
```yaml
167+
# in .yarnrc.yml
145168
catalogs:
146169
beta:
147170
react: npm:18.0.0

biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
2+
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
33
"files": {
44
"includes": ["sources/**/*.ts"]
55
},

bundles/@yarnpkg/plugin-catalogs.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"dependencies": {
66
"@yarnpkg/cli": "^4.8.0",
77
"@yarnpkg/core": "^4.3.0",
8+
"@yarnpkg/fslib": "^3.1.3",
9+
"@yarnpkg/parsers": "^3.0.3",
810
"@yarnpkg/plugin-essentials": "^4.3.2",
911
"@yarnpkg/plugin-git": "^3.1.1",
1012
"@yarnpkg/plugin-pack": "^4.0.1",

sources/__tests__/default-groups.test.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ describe("default alias groups", () => {
1717
it("should use the default alias group if no group is provided", async () => {
1818
workspace = await createTestWorkspace();
1919

20-
await workspace.writeYarnrc({
21-
catalogsOptions: {
20+
await workspace.writeCatalogsYml({
21+
options: {
2222
default: ["groupA"],
2323
},
24+
});
25+
26+
await workspace.writeYarnrc({
2427
catalogs: {
2528
groupA: {
2629
react: "npm:18.0.0",
@@ -40,10 +43,13 @@ describe("default alias groups", () => {
4043
it("should fail when the default alias group is not found in the list", async () => {
4144
workspace = await createTestWorkspace();
4245

43-
await workspace.writeYarnrc({
44-
catalogsOptions: {
46+
await workspace.writeCatalogsYml({
47+
options: {
4548
default: ["unknown"],
4649
},
50+
});
51+
52+
await workspace.writeYarnrc({
4753
catalogs: {
4854
stable: {
4955
react: "npm:18.0.0",
@@ -64,10 +70,13 @@ describe("default alias groups", () => {
6470
it("should use the root alias group if it is specified", async () => {
6571
workspace = await createTestWorkspace();
6672

67-
await workspace.writeYarnrc({
68-
catalogsOptions: {
73+
await workspace.writeCatalogsYml({
74+
options: {
6975
default: ["root"],
7076
},
77+
});
78+
79+
await workspace.writeYarnrc({
7180
catalog: {
7281
react: "npm:18.0.0",
7382
},
@@ -82,10 +91,13 @@ describe("default alias groups", () => {
8291
it("should follow the priority based on the order of default alias groups", async () => {
8392
workspace = await createTestWorkspace();
8493

85-
await workspace.writeYarnrc({
86-
catalogsOptions: {
94+
await workspace.writeCatalogsYml({
95+
options: {
8796
default: ["stable", "root"],
8897
},
98+
});
99+
100+
await workspace.writeYarnrc({
89101
catalog: {
90102
next: "npm:12.0.0",
91103
lodash: "npm:4.0.0",
@@ -110,10 +122,13 @@ describe("default alias groups", () => {
110122
it("should use the most frequently used alias group if 'max' is specified", async () => {
111123
workspace = await createTestWorkspace();
112124

113-
await workspace.writeYarnrc({
114-
catalogsOptions: {
125+
await workspace.writeCatalogsYml({
126+
options: {
115127
default: "max",
116128
},
129+
});
130+
131+
await workspace.writeYarnrc({
117132
catalogs: {
118133
beta: {
119134
react: "npm:18.0.0",

sources/__tests__/ignored-workspaces.test.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ describe("ignored workspaces", () => {
1717
it("should not use default alias group if workspace is ignored", async () => {
1818
workspace = await createTestWorkspace();
1919

20-
await workspace.writeYarnrc({
21-
catalogsOptions: {
20+
await workspace.writeCatalogsYml({
21+
options: {
2222
default: ["root"],
2323
ignoredWorkspaces: ["workspace-ignored"],
2424
},
25+
});
26+
27+
await workspace.writeYarnrc({
2528
catalogs: {
2629
root: {
2730
react: "npm:18.0.0",
@@ -45,11 +48,14 @@ describe("ignored workspaces", () => {
4548
it("should ignore workspaces matched by glob pattern", async () => {
4649
workspace = await createTestWorkspace();
4750

48-
await workspace.writeYarnrc({
49-
catalogsOptions: {
51+
await workspace.writeCatalogsYml({
52+
options: {
5053
default: ["root"],
5154
ignoredWorkspaces: ["@ignored/*"],
5255
},
56+
});
57+
58+
await workspace.writeYarnrc({
5359
catalogs: {
5460
root: {
5561
react: "npm:18.0.0",
@@ -73,10 +79,13 @@ describe("ignored workspaces", () => {
7379
it("should fail validation if workspace is ignored, but using the catalog protocol", async () => {
7480
workspace = await createTestWorkspace();
7581

76-
await workspace.writeYarnrc({
77-
catalogsOptions: {
82+
await workspace.writeCatalogsYml({
83+
options: {
7884
ignoredWorkspaces: ["workspace-ignored"],
7985
},
86+
});
87+
88+
await workspace.writeYarnrc({
8089
catalogs: {
8190
root: {
8291
react: "npm:18.0.0",
@@ -99,10 +108,13 @@ describe("ignored workspaces", () => {
99108
it("should fail when adding dependency to ignored workspace", async () => {
100109
workspace = await createTestWorkspace();
101110

102-
await workspace.writeYarnrc({
103-
catalogsOptions: {
111+
await workspace.writeCatalogsYml({
112+
options: {
104113
ignoredWorkspaces: ["workspace-ignored"],
105114
},
115+
});
116+
117+
await workspace.writeYarnrc({
106118
catalogs: {
107119
stable: {
108120
lodash: "npm:2.0.0",
@@ -127,10 +139,13 @@ describe("ignored workspaces", () => {
127139
it("should success dlx with ignored workspace", async () => {
128140
workspace = await createTestWorkspace();
129141

130-
await workspace.writeYarnrc({
131-
catalogsOptions: {
142+
await workspace.writeCatalogsYml({
143+
options: {
132144
ignoredWorkspaces: ["workspace-ignored"],
133145
},
146+
});
147+
148+
await workspace.writeYarnrc({
134149
catalogs: {
135150
stable: {
136151
"@jwoo0122/echo": "npm:1.0.0",

sources/__tests__/utils.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { dir as tmpDir } from "tmp-promise";
2-
import { writeFile } from "fs/promises";
3-
import { join } from "path";
4-
import { execFile } from "child_process";
5-
import { promisify } from "util";
2+
import { writeFile } from "node:fs/promises";
3+
import { join } from "node:path";
4+
import { execFile } from "node:child_process";
5+
import { promisify } from "node:util";
66
import { dump as yamlDump } from "js-yaml";
7-
import * as fs from "fs/promises";
7+
import * as fs from "node:fs/promises";
88

99
const execFileAsync = promisify(execFile);
1010

@@ -13,6 +13,7 @@ export interface TestWorkspace {
1313
cleanup: () => Promise<void>;
1414
writeJson: (path: string, content: unknown) => Promise<void>;
1515
writeYarnrc: (content: unknown) => Promise<void>;
16+
writeCatalogsYml: (content: unknown) => Promise<void>;
1617
yarn: {
1718
(args: string[]): Promise<{ stdout: string; stderr: string }>;
1819
install(): Promise<{ stdout: string; stderr: string }>;
@@ -58,14 +59,20 @@ export async function createTestWorkspace(): Promise<TestWorkspace> {
5859
const existingContent = await fs
5960
.readFile(yarnrcPath, "utf8")
6061
.catch(() => "");
61-
await writeFile(yarnrcPath, existingContent + "\n" + yamlDump(content));
62+
await writeFile(yarnrcPath, `${existingContent}\n${yamlDump(content)}`);
63+
};
64+
65+
const writeCatalogsYml = async (content: unknown) => {
66+
const catalogsYmlPath = join(path, "catalogs.yml");
67+
await writeFile(catalogsYmlPath, yamlDump(content));
6268
};
6369

6470
return {
6571
path,
6672
cleanup,
6773
writeJson,
6874
writeYarnrc: writeYaml,
75+
writeCatalogsYml,
6976
yarn,
7077
};
7178
}
@@ -98,7 +105,7 @@ module.exports = {
98105
// Create a new descriptor with the resolved version
99106
return structUtils.makeDescriptor(
100107
structUtils.makeIdent(dependency.scope, dependency.name),
101-
\`npm:\$\{version\}\`
108+
'npm:' + version
102109
);
103110
}
104111
}
@@ -124,7 +131,10 @@ export function extractDependencies(log: string): string[] {
124131
(depsString) =>
125132
JSON.parse(depsString) as { value: string; children: object },
126133
)
127-
.reduce((result, item) => [...result, item.value], [] as string[]);
134+
.reduce((result, item) => {
135+
result.push(item.value);
136+
return result;
137+
}, [] as string[]);
128138
}
129139

130140
export async function hasDependency(

0 commit comments

Comments
 (0)