Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/large-plants-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@manypkg/get-packages": major
"@manypkg/find-root": major
"@manypkg/tools": major
---

Fixed an issue with projects using npm workspaces being recognized as yarn projects
Empty file.
7 changes: 7 additions & 0 deletions __fixtures__/basic-npm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@manypkg/basic-npm-fixture",
"version": "1.0.0",
"workspaces": [
"packages/*"
]
}
4 changes: 4 additions & 0 deletions __fixtures__/basic-npm/packages/package-one/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@manypkg/basic-fixture-pkg-one",
"version": "1.0.0"
}
Empty file.
Empty file.
Empty file added __fixtures__/basic/yarn.lock
Empty file.
Empty file.
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions __fixtures__/npm-workspace-base/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"private": true,
"name": "npm-workspace-base",
"description": "Base npm workspace work",
"version": "1.0.0",
"workspaces": [
"packages/*"
]
}
7 changes: 7 additions & 0 deletions __fixtures__/npm-workspace-base/packages/pkg-a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "npm-workspace-base-pkg-a",
"version": "1.0.0",
"dependencies": {
"npm-workspace-base-pkg-b": "1.0.0"
}
}
4 changes: 4 additions & 0 deletions __fixtures__/npm-workspace-base/packages/pkg-b/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "npm-workspace-base-pkg-b",
"version": "1.0.0"
}
Empty file.
3 changes: 2 additions & 1 deletion packages/cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function install(toolType: string, cwd: string) {
const cliRunners: Record<string, string> = {
bolt: "bolt",
lerna: "lerna",
npm: "npm",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the condition below for pnpm needs to apply for npm as well

pnpm: "pnpm",
root: "yarn",
rush: "rushx",
Expand All @@ -26,7 +27,7 @@ export async function install(toolType: string, cwd: string) {

await exec(
cliRunners[toolType],
toolType === "pnpm"
toolType === "npm" || toolType === "pnpm"
? ["install"]
: toolType === "lerna"
? ["bootstrap", "--since", "HEAD"]
Expand Down
19 changes: 18 additions & 1 deletion packages/find-root/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import fixturez from "fixturez";
import path from "node:path";
import { findRoot, findRootSync } from "./index.ts";

import { LernaTool, PnpmTool, RootTool, YarnTool } from "@manypkg/tools";
import {
LernaTool,
NpmTool,
PnpmTool,
RootTool,
YarnTool,
} from "@manypkg/tools";

let f = fixturez(__dirname);

Expand All @@ -21,6 +27,17 @@ const runTests = (findRoot: FindRoot) => {
});
});

test("it returns the root of an npm monorepo", async () => {
let tmpPath = f.copy("basic-npm");
let monorepoRoot = await findRoot(
path.join(tmpPath, "packages", "package-one", "src")
);
expect(monorepoRoot).toEqual({
tool: NpmTool.type,
rootDir: tmpPath,
});
});

test("it returns the root of a lerna monorepo", async () => {
let tmpPath = f.copy("basic-lerna");
let monorepoRoot = await findRoot(
Expand Down
11 changes: 6 additions & 5 deletions packages/find-root/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import path from "node:path";
import fs from "node:fs";
import fsp from "node:fs/promises";

import path from "node:path";
import {
type Tool,
RootTool,
type MonorepoRoot,
BoltTool,
LernaTool,
NpmTool,
PnpmTool,
RootTool,
RushTool,
YarnTool,
type MonorepoRoot,
type Tool,
} from "@manypkg/tools";

/**
Expand All @@ -23,6 +23,7 @@ import {
export const DEFAULT_TOOLS: Tool[] = [
YarnTool,
PnpmTool,
NpmTool,
LernaTool,
RushTool,
BoltTool,
Expand Down
21 changes: 21 additions & 0 deletions packages/get-packages/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,27 @@ let runTests = (getPackages: GetPackages) => {
}
});

it("should resolve workspaces for npm", async () => {
const dir = f.copy("npm-workspace-base");

// Test for both root and subdirectories
for (const location of [".", "packages", "packages/pkg-a"]) {
const allPackages = await getPackages(path.join(dir, location));

if (allPackages.packages === null) {
return expect(allPackages.packages).not.toBeNull();
}

expect(allPackages.packages[0].packageJson.name).toEqual(
"npm-workspace-base-pkg-a"
);
expect(allPackages.packages[1].packageJson.name).toEqual(
"npm-workspace-base-pkg-b"
);
expect(allPackages.tool.type).toEqual("npm");
}
});

it("should resolve yarn workspaces if the yarn option is passed and packages field is used", async () => {
const allPackages = await getPackages(f.copy("yarn-workspace-base"));

Expand Down
119 changes: 119 additions & 0 deletions packages/tools/src/NpmTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import path from "node:path";
import fs from "node:fs";
import fsp from "node:fs/promises";
import { F_OK } from "node:constants";

import {
InvalidMonorepoError,
type PackageJSON,
type Packages,
type Tool,
} from "./Tool.ts";
import {
expandPackageGlobs,
expandPackageGlobsSync,
} from "./expandPackageGlobs.ts";
import { readJson, readJsonSync } from "./utils.ts";

export interface NpmPackageJSON extends PackageJSON {
workspaces?: string[];
}

export const NpmTool: Tool = {
type: "npm",

async isMonorepoRoot(directory: string): Promise<boolean> {
try {
const [pkgJson] = await Promise.all([
readJson(directory, "package.json") as Promise<NpmPackageJSON>,
fsp.access(path.join(directory, "package-lock.json"), F_OK),
]);
if (pkgJson.workspaces) {
if (Array.isArray(pkgJson.workspaces)) {
return true;
}
}
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
return false;
}
throw err;
}
return false;
},

isMonorepoRootSync(directory: string): boolean {
try {
fs.accessSync(path.join(directory, "package-lock.json"), F_OK);
const pkgJson = readJsonSync(directory, "package.json") as NpmPackageJSON;
if (pkgJson.workspaces) {
if (Array.isArray(pkgJson.workspaces)) {
return true;
}
}
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
return false;
}
throw err;
}
return false;
},

async getPackages(directory: string): Promise<Packages> {
const rootDir = path.resolve(directory);

try {
const pkgJson = (await readJson(
rootDir,
"package.json"
)) as NpmPackageJSON;
const packageGlobs: string[] = pkgJson.workspaces!;

return {
tool: NpmTool,
packages: await expandPackageGlobs(packageGlobs, rootDir),
rootPackage: {
dir: rootDir,
relativeDir: ".",
packageJson: pkgJson,
},
rootDir,
};
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
throw new InvalidMonorepoError(
`Directory ${rootDir} is not a valid ${NpmTool.type} monorepo root`
);
}
throw err;
}
},

getPackagesSync(directory: string): Packages {
const rootDir = path.resolve(directory);

try {
const pkgJson = readJsonSync(rootDir, "package.json") as NpmPackageJSON;
const packageGlobs: string[] = pkgJson.workspaces!;

return {
tool: NpmTool,
packages: expandPackageGlobsSync(packageGlobs, rootDir),
rootPackage: {
dir: rootDir,
relativeDir: ".",
packageJson: pkgJson,
},
rootDir,
};
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
throw new InvalidMonorepoError(
`Directory ${rootDir} is not a valid ${NpmTool.type} monorepo root`
);
}
throw err;
}
},
};
13 changes: 7 additions & 6 deletions packages/tools/src/RushTool.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import path from "node:path";
import jju from "jju";
import { F_OK } from "node:constants";
import fs from "node:fs";
import fsp from "node:fs/promises";
import jju from "jju";
import path from "node:path";

import {
type Tool,
InvalidMonorepoError,
type Package,
type PackageJSON,
type Packages,
InvalidMonorepoError,
type Tool,
} from "./Tool.ts";
import { readJson, readJsonSync } from "./utils.ts";

Expand All @@ -26,7 +27,7 @@ export const RushTool: Tool = {

async isMonorepoRoot(directory: string): Promise<boolean> {
try {
await fsp.readFile(path.join(directory, "rush.json"), "utf8");
await fsp.access(path.join(directory, "rush.json"), F_OK);
return true;
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
Expand All @@ -38,7 +39,7 @@ export const RushTool: Tool = {

isMonorepoRootSync(directory: string): boolean {
try {
fs.readFileSync(path.join(directory, "rush.json"), "utf8");
fs.accessSync(path.join(directory, "rush.json"), F_OK);
return true;
} catch (err) {
if (err && (err as { code: string }).code === "ENOENT") {
Expand Down
12 changes: 8 additions & 4 deletions packages/tools/src/YarnTool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import path from "node:path";
import fs from "node:fs";
import fsp from "node:fs/promises";
import { F_OK } from "node:constants";

import {
type Tool,
Expand All @@ -21,10 +24,10 @@ export const YarnTool: Tool = {

async isMonorepoRoot(directory: string): Promise<boolean> {
try {
const pkgJson = (await readJson(
directory,
"package.json"
)) as YarnPackageJSON;
const [pkgJson] = await Promise.all([
readJson(directory, "package.json") as Promise<YarnPackageJSON>,
fsp.access(path.join(directory, "yarn.lock"), F_OK),
]);
if (pkgJson.workspaces) {
if (
Array.isArray(pkgJson.workspaces) ||
Expand All @@ -44,6 +47,7 @@ export const YarnTool: Tool = {

isMonorepoRootSync(directory: string): boolean {
try {
fs.accessSync(path.join(directory, "yarn.lock"), F_OK);
const pkgJson = readJsonSync(
directory,
"package.json"
Expand Down
1 change: 1 addition & 0 deletions packages/tools/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./Tool.ts";
export { BoltTool } from "./BoltTool.ts";
export { LernaTool } from "./LernaTool.ts";
export { NpmTool } from "./NpmTool.ts";
export { PnpmTool } from "./PnpmTool.ts";
export { RootTool } from "./RootTool.ts";
export { RushTool } from "./RushTool.ts";
Expand Down