Skip to content

Commit de0fff3

Browse files
Restore support for Bolt monorepos (#174)
* Restore support for Bolt monorepos * Update packages/get-packages/src/index.ts Co-authored-by: Mateusz Burzyński <[email protected]> * Move BoltTool down --------- Co-authored-by: Mateusz Burzyński <[email protected]>
1 parent bf7f69f commit de0fff3

File tree

13 files changed

+197
-9
lines changed

13 files changed

+197
-9
lines changed

.changeset/rude-squids-switch.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@manypkg/get-packages": minor
3+
"@manypkg/find-root": minor
4+
"@manypkg/tools": minor
5+
"@manypkg/cli": minor
6+
---
7+
8+
Restored support for Bolt monorepos.
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"private": true,
3+
"name": "bolt-workspaces",
4+
"description": "bolt-workspaces",
5+
"version": "1.0.0",
6+
"bolt": {
7+
"workspaces": [
8+
"packages/*"
9+
]
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "bolt-workspace-pkg-a",
3+
"version": "1.0.0",
4+
"dependencies": {
5+
"pkg-b": "1.0.0"
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "bolt-workspace-pkg-b",
3+
"version": "1.0.0"
4+
}

packages/cli/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Manypkg
22

3-
Manypkg is a linter for `package.json` files in Yarn, Lerna, pnpm or Rush monorepos.
3+
Manypkg is a linter for `package.json` files in Yarn, Bolt, Lerna, pnpm or Rush monorepos.
44

55
## Install
66

packages/cli/src/utils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function writePackage(pkg: Package) {
1616

1717
export async function install(toolType: string, cwd: string) {
1818
const cliRunners: Record<string, string> = {
19+
bolt: "bolt",
1920
lerna: "lerna",
2021
pnpm: "pnpm",
2122
root: "yarn",

packages/find-root/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# @manypkg/find-root
22

3-
> Find the root of a monorepo with Yarn workspaces, Lerna, pnpm or Rush
3+
> Find the root of a monorepo with Yarn workspaces, Bolt, Lerna, pnpm or Rush
44
55
## Install
66

packages/find-root/src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Tool,
77
RootTool,
88
MonorepoRoot,
9+
BoltTool,
910
LernaTool,
1011
PnpmTool,
1112
RushTool,
@@ -24,6 +25,7 @@ const DEFAULT_TOOLS: Tool[] = [
2425
PnpmTool,
2526
LernaTool,
2627
RushTool,
28+
BoltTool,
2729
RootTool,
2830
];
2931

@@ -32,6 +34,7 @@ const isNoEntryError = (err: unknown): boolean =>
3234

3335
export class NoPkgJsonFound extends Error {
3436
directory: string;
37+
3538
constructor(directory: string) {
3639
super(`No package.json could be found upwards from directory ${directory}`);
3740
this.directory = directory;
@@ -40,6 +43,7 @@ export class NoPkgJsonFound extends Error {
4043

4144
export class NoMatchingMonorepoFound extends Error {
4245
directory: string;
46+
4347
constructor(directory: string) {
4448
super(
4549
`No monorepo matching the list of supported monorepos could be found upwards from directory ${directory}`

packages/get-packages/README.md

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
# @manypkg/get-packages
22

3-
> A simple utility to get the packages from a monorepo, whether they're using Yarn, Lerna, pnpm or Rush
3+
> A simple utility to get the packages from a monorepo, whether they're using Yarn, Bolt, Lerna, pnpm or Rush
44
5-
This library exports `getPackages` and `getPackagesSync`. It is intended mostly for use of developers building tools that want to support different kinds of monorepos as an easy way to write tools without having to write tool-specific code. It supports Yarn, Lerna, pnpm, Rush and single-package repos(where the only package is the the same as the root package). This library uses `@manypkg/find-root` to search up from the directory that's passed to `getPackages` or `getPackagesSync` to find the project root.
5+
This library exports `getPackages` and `getPackagesSync`. It is intended mostly for use of developers building tools that want to support different kinds of monorepos as an easy way to write tools without having to write tool-specific code. It supports Yarn, Bolt, Lerna, pnpm, Rush and single-package repos(where the only package is the the same as the root package). This library uses `@manypkg/find-root` to search up from the directory that's passed to `getPackages` or `getPackagesSync` to find the project root.
66

77
```typescript
88
import { getPackages, getPackagesSync } from "@manypkg/get-packages";
99

10-
const { tool, root, packages } = await getPackages(process.cwd());
11-
const { tool, root, packages } = getPackagesSync(process.cwd());
10+
const { tool, packages, rootPackage, rootDir } = await getPackages(process.cwd());
11+
const { tool, packages, rootPackage, rootDir } = getPackagesSync(process.cwd());
1212

13-
type Package = { packageJson: PackageJSON; dir: string };
13+
// From @manypkg/tools
1414

15-
type Packages = {
15+
interface Tool {
16+
readonly type: string;
17+
isMonorepoRoot(directory: string): Promise<boolean>;
18+
isMonorepoRootSync(directory: string): boolean;
19+
getPackages(directory: string): Promise<Packages>;
20+
getPackagesSync(directory: string): Packages;
21+
}
22+
23+
interface Package {
24+
packageJson: PackageJSON;
25+
dir: string;
26+
relativeDir: string;
27+
}
28+
29+
interface Packages {
1630
tool: Tool;
1731
packages: Package[];
1832
rootPackage?: Package;
1933
rootDir: string;
20-
};
34+
}
2135
```

packages/get-packages/src/index.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ let runTests = (getPackages: GetPackages) => {
3737
expect(allPackages.tool.type).toEqual("yarn");
3838
});
3939

40+
it("should resolve workspaces for bolt", async () => {
41+
const allPackages = await getPackages(f.copy("bolt-workspace"));
42+
43+
if (allPackages.packages === null) {
44+
return expect(allPackages.packages).not.toBeNull();
45+
}
46+
47+
expect(allPackages.packages[0].packageJson.name).toEqual(
48+
"bolt-workspace-pkg-a"
49+
);
50+
expect(allPackages.packages[1].packageJson.name).toEqual(
51+
"bolt-workspace-pkg-b"
52+
);
53+
expect(allPackages.tool.type).toEqual("bolt");
54+
});
55+
4056
it("should resolve workspaces for pnpm", async () => {
4157
const allPackages = await getPackages(f.copy("pnpm-workspace-base"));
4258

packages/get-packages/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import path from "path";
23
import { findRoot, findRootSync, FindRootOptions } from "@manypkg/find-root";
34
import { Packages, MonorepoRoot, Tool } from "@manypkg/tools";
@@ -6,6 +7,7 @@ export type { Tool, Package, Packages } from "@manypkg/tools";
67

78
export class PackageJsonMissingNameError extends Error {
89
directories: string[];
10+
911
constructor(directories: string[]) {
1012
super(
1113
`The following package.jsons are missing the "name" field:\n${directories.join(

packages/tools/src/BoltTool.ts

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import path from "path";
2+
import fs from "fs-extra";
3+
4+
import { Tool, PackageJSON, Packages, InvalidMonorepoError } from "./Tool";
5+
import {
6+
expandPackageGlobs,
7+
expandPackageGlobsSync,
8+
} from "./expandPackageGlobs";
9+
10+
export interface BoltPackageJSON extends PackageJSON {
11+
bolt?: {
12+
workspaces?: string[];
13+
};
14+
}
15+
16+
export const BoltTool: Tool = {
17+
type: "bolt",
18+
19+
async isMonorepoRoot(directory: string): Promise<boolean> {
20+
try {
21+
const pkgJson = (await fs.readJson(
22+
path.join(directory, "package.json")
23+
)) as BoltPackageJSON;
24+
if (pkgJson.bolt && pkgJson.bolt.workspaces) {
25+
return true;
26+
}
27+
} catch (err) {
28+
if (err && (err as { code: string }).code === "ENOENT") {
29+
return false;
30+
}
31+
throw err;
32+
}
33+
return false;
34+
},
35+
36+
isMonorepoRootSync(directory: string): boolean {
37+
try {
38+
const pkgJson = fs.readJsonSync(
39+
path.join(directory, "package.json")
40+
) as BoltPackageJSON;
41+
if (pkgJson.bolt && pkgJson.bolt.workspaces) {
42+
return true;
43+
}
44+
} catch (err) {
45+
if (err && (err as { code: string }).code === "ENOENT") {
46+
return false;
47+
}
48+
throw err;
49+
}
50+
return false;
51+
},
52+
53+
async getPackages(directory: string): Promise<Packages> {
54+
const rootDir = path.resolve(directory);
55+
56+
try {
57+
const pkgJson = (await fs.readJson(
58+
path.join(rootDir, "package.json")
59+
)) as BoltPackageJSON;
60+
if (!pkgJson.bolt || !pkgJson.bolt.workspaces) {
61+
throw new InvalidMonorepoError(
62+
`Directory ${rootDir} is not a valid ${BoltTool.type} monorepo root: missing bolt.workspaces entry`
63+
);
64+
}
65+
const packageGlobs: string[] = pkgJson.bolt.workspaces;
66+
67+
return {
68+
tool: BoltTool,
69+
packages: await expandPackageGlobs(packageGlobs, rootDir),
70+
rootPackage: {
71+
dir: rootDir,
72+
relativeDir: ".",
73+
packageJson: pkgJson,
74+
},
75+
rootDir,
76+
};
77+
} catch (err) {
78+
if (err && (err as { code: string }).code === "ENOENT") {
79+
throw new InvalidMonorepoError(
80+
`Directory ${rootDir} is not a valid ${BoltTool.type} monorepo root: missing package.json`
81+
);
82+
}
83+
throw err;
84+
}
85+
},
86+
87+
getPackagesSync(directory: string): Packages {
88+
const rootDir = path.resolve(directory);
89+
90+
try {
91+
const pkgJson = fs.readJsonSync(
92+
path.join(rootDir, "package.json")
93+
) as BoltPackageJSON;
94+
if (!pkgJson.bolt || !pkgJson.bolt.workspaces) {
95+
throw new InvalidMonorepoError(
96+
`Directory ${directory} is not a valid ${BoltTool.type} monorepo root: missing bolt.workspaces entry`
97+
);
98+
}
99+
const packageGlobs: string[] = pkgJson.bolt.workspaces;
100+
101+
return {
102+
tool: BoltTool,
103+
packages: expandPackageGlobsSync(packageGlobs, rootDir),
104+
rootPackage: {
105+
dir: rootDir,
106+
relativeDir: ".",
107+
packageJson: pkgJson,
108+
},
109+
rootDir,
110+
};
111+
} catch (err) {
112+
if (err && (err as { code: string }).code === "ENOENT") {
113+
throw new InvalidMonorepoError(
114+
`Directory ${rootDir} is not a valid ${BoltTool.type} monorepo root: missing package.json`
115+
);
116+
}
117+
throw err;
118+
}
119+
},
120+
};

packages/tools/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./Tool";
2+
export { BoltTool } from "./BoltTool";
23
export { LernaTool } from "./LernaTool";
34
export { PnpmTool } from "./PnpmTool";
45
export { RootTool } from "./RootTool";

0 commit comments

Comments
 (0)