Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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.
1 change: 1 addition & 0 deletions 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 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