Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: .npmrc not written into workspace root #73

Merged
merged 1 commit into from
Apr 15, 2024
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
16 changes: 11 additions & 5 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,15 @@ export interface InstallOptions extends BaseOptions {
}

export async function install(packages: JsrPackage[], options: InstallOptions) {
const pkgManager = await getPkgManager(process.cwd(), options.pkgManagerName);
const { pkgManager, root } = await getPkgManager(
process.cwd(),
options.pkgManagerName,
);

if (packages.length > 0) {
if (pkgManager instanceof Bun) {
// Bun doesn't support reading from .npmrc yet
await setupBunfigToml(pkgManager.cwd);
await setupBunfigToml(root);
} else if (pkgManager instanceof YarnBerry) {
// Yarn v2+ does not read from .npmrc intentionally
// https://yarnpkg.com/migration/guide#update-your-configuration-to-the-new-settings
Expand All @@ -101,7 +104,7 @@ export async function install(packages: JsrPackage[], options: InstallOptions) {
JSR_NPM_REGISTRY_URL,
);
} else {
await setupNpmRc(pkgManager.cwd);
await setupNpmRc(root);
}

console.log(`Installing ${kl.cyan(packages.join(", "))}...`);
Expand All @@ -111,7 +114,10 @@ export async function install(packages: JsrPackage[], options: InstallOptions) {
}

export async function remove(packages: JsrPackage[], options: BaseOptions) {
const pkgManager = await getPkgManager(process.cwd(), options.pkgManagerName);
const { pkgManager } = await getPkgManager(
process.cwd(),
options.pkgManagerName,
);
console.log(`Removing ${kl.cyan(packages.join(", "))}...`);
await pkgManager.remove(packages);
}
Expand Down Expand Up @@ -186,7 +192,7 @@ export async function runScript(
script: string,
options: BaseOptions,
) {
const pkgManager = await getPkgManager(cwd, options.pkgManagerName);
const { pkgManager } = await getPkgManager(cwd, options.pkgManagerName);
await pkgManager.runScript(script);
}

Expand Down
21 changes: 13 additions & 8 deletions src/pkg_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,27 +195,32 @@ function getPkgManagerFromEnv(value: string): PkgManagerName | null {
export async function getPkgManager(
cwd: string,
pkgManagerName: PkgManagerName | null,
) {
): Promise<{ root: string; pkgManager: PackageManager }> {
const envPkgManager = process.env.npm_config_user_agent;
const fromEnv = envPkgManager !== undefined
? getPkgManagerFromEnv(envPkgManager)
: null;

const { projectDir, pkgManagerName: fromLockfile } = await findProjectDir(
cwd,
);
const { projectDir, pkgManagerName: fromLockfile, root } =
await findProjectDir(
cwd,
);
const rootPath = root || projectDir;

const result = pkgManagerName || fromEnv || fromLockfile || "npm";

let pkgManager: PackageManager;
if (result === "yarn") {
return await isYarnBerry(projectDir)
pkgManager = await isYarnBerry(projectDir)
? new YarnBerry(projectDir)
: new Yarn(projectDir);
} else if (result === "pnpm") {
return new Pnpm(projectDir);
pkgManager = new Pnpm(projectDir);
} else if (result === "bun") {
return new Bun(projectDir);
pkgManager = new Bun(projectDir);
} else {
pkgManager = new Npm(projectDir);
}

return new Npm(projectDir);
return { root: rootPath, pkgManager };
}
15 changes: 15 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface ProjectInfo {
projectDir: string;
pkgManagerName: PkgManagerName | null;
pkgJsonPath: string | null;
root: string | null;
}
export async function findProjectDir(
cwd: string,
Expand All @@ -80,6 +81,7 @@ export async function findProjectDir(
projectDir: cwd,
pkgManagerName: null,
pkgJsonPath: null,
root: null,
},
): Promise<ProjectInfo> {
// Ensure we check for `package.json` first as this defines
Expand All @@ -92,6 +94,18 @@ export async function findProjectDir(
result.projectDir = dir;
result.pkgJsonPath = pkgJsonPath;
}
} else {
const pkgJsonPath = path.join(dir, "package.json");
if (await fileExists(pkgJsonPath)) {
const json = await readJson<PkgJson>(pkgJsonPath);
// npm + yarn + bun workspaces
if (Array.isArray(json.workspaces)) {
result.root = dir;
} // pnpm workspaces
else if (await fileExists(path.join(dir, "pnpm-workspace.yaml"))) {
result.root = dir;
}
}
}

const npmLockfile = path.join(dir, "package-lock.json");
Expand Down Expand Up @@ -245,6 +259,7 @@ export interface PkgJson {
name?: string;
version?: string;
license?: string;
workspaces?: string[];

dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
Expand Down
73 changes: 73 additions & 0 deletions test/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,79 @@ describe("install", () => {
});
});

it("jsr i @std/encoding - inside workspace member", async () => {
await runInTempDir(async (dir) => {
const parentPkgJson = { name: "", private: true, workspaces: ["sub"] };
const parentPkgJsonPath = path.join(dir, "package.json");
await writeJson<PkgJson>(parentPkgJsonPath, parentPkgJson);

// Create sub folder with package.json
const subPkgJsonPath = path.join(dir, "sub", "package.json");
await writeJson(subPkgJsonPath, { name: "foo" });

await runJsr(["i", "@std/encoding"], path.join(dir, "sub"));

assert.deepEqual(
await readJson<PkgJson>(path.join(dir, "package.json")),
parentPkgJson,
);

const pkgJson = await readJson<PkgJson>(subPkgJsonPath);
assert.ok(
pkgJson.dependencies && "@std/encoding" in pkgJson.dependencies,
"Missing dependency entry",
);

assert.match(
pkgJson.dependencies["@std/encoding"],
/^npm:@jsr\/std__encoding@\^\d+\.\d+\.\d+.*$/,
);

const npmRc = await readTextFile(path.join(dir, ".npmrc"));
assert.ok(
npmRc.includes("@jsr:registry=https://npm.jsr.io"),
"Missing npmrc registry",
);
});
});

it("jsr i @std/encoding - inside pnpm workspace member", async () => {
await runInTempDir(async (dir) => {
const parentPkgJson = { name: "", private: true };
const parentPkgJsonPath = path.join(dir, "package.json");
await writeJson<PkgJson>(parentPkgJsonPath, parentPkgJson);
await writeTextFile(path.join(dir, "pnpm-workspace.yaml"), "");

// Create sub folder with package.json
const subPkgJsonPath = path.join(dir, "sub", "package.json");
await writeJson(subPkgJsonPath, { name: "foo" });

await runJsr(["i", "--pnpm", "@std/encoding"], path.join(dir, "sub"));

assert.deepEqual(
await readJson<PkgJson>(path.join(dir, "package.json")),
parentPkgJson,
);

const pkgJson = await readJson<PkgJson>(subPkgJsonPath);
assert.ok(
pkgJson.dependencies && "@std/encoding" in pkgJson.dependencies,
"Missing dependency entry",
);

assert.match(
pkgJson.dependencies["@std/encoding"],
/^npm:@jsr\/std__encoding@\^\d+\.\d+\.\d+.*$/,
);

const npmRc = await readTextFile(path.join(dir, ".npmrc"));
assert.ok(
npmRc.includes("@jsr:registry=https://npm.jsr.io"),
"Missing npmrc registry",
);
});
});

it("jsr i @std/[email protected] - with version", async () => {
await withTempEnv(["i", "@std/[email protected]"], async (dir) => {
const pkgJson = await readJson<PkgJson>(path.join(dir, "package.json"));
Expand Down
38 changes: 37 additions & 1 deletion test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as assert from "assert/strict";
import * as path from "node:path";
import { runInTempDir } from "./test_utils";
import { findProjectDir, writeJson, writeTextFile } from "../src/utils";
import {
findProjectDir,
PkgJson,
writeJson,
writeTextFile,
} from "../src/utils";

describe("findProjectDir", () => {
it("should return npm if package-lock.json is found", async () => {
Expand Down Expand Up @@ -57,4 +62,35 @@ describe("findProjectDir", () => {
assert.strictEqual(result.projectDir, sub);
});
});

it("should find workspace root folder", async () => {
await runInTempDir(async (tempDir) => {
const sub = path.join(tempDir, "sub");

await writeJson<PkgJson>(path.join(tempDir, "package.json"), {
workspaces: ["sub"],
});
await writeJson(path.join(sub, "package.json"), {});
const result = await findProjectDir(sub);
assert.strictEqual(
result.root,
tempDir,
);
});
});

it("should find workspace root folder with pnpm workspaces", async () => {
await runInTempDir(async (tempDir) => {
const sub = path.join(tempDir, "sub");

await writeJson<PkgJson>(path.join(tempDir, "package.json"), {});
await writeJson(path.join(sub, "package.json"), {});
await writeTextFile(path.join(tempDir, "pnpm-workspace.yaml"), "");
const result = await findProjectDir(sub);
assert.strictEqual(
result.root,
tempDir,
);
});
});
});
Loading