mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
### What does this PR do? Fixes #23521 ### How did you verify your code works? Added 3 previously failing tests for `"bin"`, `"directories.bin"`, and deduplicating entry in both `"bin.directories"` and `"files"` --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1469 lines
44 KiB
TypeScript
1469 lines
44 KiB
TypeScript
import { file, spawn, write } from "bun";
|
|
import { readTarball } from "bun:internal-for-testing";
|
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
import { exists, mkdir, rm } from "fs/promises";
|
|
import { bunEnv, bunExe, pack, runBunInstall, tempDirWithFiles, tmpdirSync } from "harness";
|
|
import fs from "node:fs/promises";
|
|
import { join } from "path";
|
|
|
|
var packageDir: string;
|
|
|
|
beforeEach(() => {
|
|
packageDir = tmpdirSync();
|
|
});
|
|
|
|
async function packExpectError(cwd: string, env: NodeJS.Dict<string>, ...args: string[]) {
|
|
const { stdout, stderr, exited } = spawn({
|
|
cmd: [bunExe(), "pm", "pack", ...args],
|
|
cwd,
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
stdin: "ignore",
|
|
env,
|
|
});
|
|
|
|
const err = await stderr.text();
|
|
expect(err).not.toContain("panic:");
|
|
|
|
const out = await stdout.text();
|
|
|
|
const exitCode = await exited;
|
|
expect(exitCode).toBeGreaterThan(0);
|
|
|
|
return { out, err };
|
|
}
|
|
|
|
test("basic", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-basic",
|
|
version: "1.2.3",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-basic-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/index.js" }]);
|
|
});
|
|
|
|
test("in subdirectory", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-from-subdir",
|
|
version: "7.7.7",
|
|
}),
|
|
),
|
|
mkdir(join(packageDir, "subdir1", "subdir2"), { recursive: true }),
|
|
write(join(packageDir, "root.js"), "console.log(`hello ./root.js`);"),
|
|
write(join(packageDir, "subdir1", "subdir2", "index.js"), "console.log(`hello ./subdir1/subdir2/index.js`);"),
|
|
]);
|
|
|
|
await pack(join(packageDir, "subdir1", "subdir2"), bunEnv);
|
|
|
|
const first = readTarball(join(packageDir, "pack-from-subdir-7.7.7.tgz"));
|
|
expect(first.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/root.js" },
|
|
{ "pathname": "package/subdir1/subdir2/index.js" },
|
|
]);
|
|
|
|
await rm(join(packageDir, "pack-from-subdir-7.7.7.tgz"));
|
|
|
|
await pack(join(packageDir, "subdir1"), bunEnv);
|
|
|
|
const second = readTarball(join(packageDir, "pack-from-subdir-7.7.7.tgz"));
|
|
expect(first).toEqual(second);
|
|
});
|
|
|
|
describe("package.json names and versions", () => {
|
|
const tests = [
|
|
{
|
|
desc: "missing name",
|
|
expectedError: "package.json must have `name` and `version` fields",
|
|
packageJson: {
|
|
version: "1.1.1",
|
|
},
|
|
},
|
|
{
|
|
desc: "missing version",
|
|
expectedError: "package.json must have `name` and `version` fields",
|
|
packageJson: {
|
|
name: "pack-invalid",
|
|
},
|
|
},
|
|
{
|
|
desc: "missing name and version",
|
|
expectedError: "package.json must have `name` and `version` fields",
|
|
packageJson: {
|
|
description: "ooops",
|
|
},
|
|
},
|
|
{
|
|
desc: "empty name",
|
|
expectedError: "package.json `name` and `version` fields must be non-empty strings",
|
|
packageJson: {
|
|
name: "",
|
|
version: "1.1.1",
|
|
},
|
|
},
|
|
{
|
|
desc: "empty version",
|
|
expectedError: "package.json `name` and `version` fields must be non-empty strings",
|
|
packageJson: {
|
|
name: "pack-invalid",
|
|
version: "",
|
|
},
|
|
},
|
|
{
|
|
desc: "empty name and version",
|
|
expectedError: "package.json `name` and `version` fields must be non-empty strings",
|
|
packageJson: {
|
|
name: "",
|
|
version: "",
|
|
},
|
|
},
|
|
];
|
|
|
|
for (const { desc, expectedError, packageJson } of tests) {
|
|
test(desc, async () => {
|
|
await Promise.all([
|
|
write(join(packageDir, "package.json"), JSON.stringify(packageJson)),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
const { err } = await packExpectError(packageDir, bunEnv);
|
|
expect(err).toContain(expectedError);
|
|
});
|
|
}
|
|
|
|
test("missing", async () => {
|
|
await write(join(packageDir, "index.js"), "console.log('hello ./index.js')");
|
|
|
|
const { err } = await packExpectError(packageDir, bunEnv);
|
|
expect(err).toContain(`error: No package.json was found for directory "${packageDir}`);
|
|
});
|
|
|
|
const scopedNames = [
|
|
{
|
|
input: "@scoped/pkg",
|
|
output: "scoped-pkg-1.1.1.tgz",
|
|
},
|
|
{
|
|
input: "@",
|
|
output: "-1.1.1.tgz",
|
|
},
|
|
{
|
|
input: "@/",
|
|
output: "--1.1.1.tgz",
|
|
},
|
|
{
|
|
input: "//",
|
|
output: "-1.1.1.tgz",
|
|
},
|
|
{
|
|
input: "@//",
|
|
fail: true,
|
|
output: "",
|
|
},
|
|
{
|
|
input: "@/s",
|
|
output: "-s-1.1.1.tgz",
|
|
},
|
|
{
|
|
input: "@s",
|
|
output: "s-1.1.1.tgz",
|
|
},
|
|
];
|
|
for (const { input, output, fail } of scopedNames) {
|
|
test(`scoped name: ${input}`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: input,
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
fail ? await packExpectError(packageDir, bunEnv) : await pack(packageDir, bunEnv);
|
|
if (!fail) {
|
|
const tarball = readTarball(join(packageDir, output));
|
|
expect(tarball.entries).toHaveLength(2);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
describe("flags", () => {
|
|
test("--dry-run", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-dry-run",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
const { out } = await pack(packageDir, bunEnv, "--dry-run");
|
|
|
|
expect(out).toContain("files: 2");
|
|
|
|
expect(await exists(join(packageDir, "pack-dry-run-1.1.1.tgz"))).toBeFalse();
|
|
});
|
|
test("--gzip", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-gzip-test",
|
|
version: "111111.1.11111111111111",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
for (const invalidGzipLevel of ["-1", "10", "kjefj"]) {
|
|
const { err } = await packExpectError(packageDir, bunEnv, `--gzip-level=${invalidGzipLevel}`);
|
|
expect(err).toContain(`error: compression level must be between 0 and 9, received ${invalidGzipLevel}\n`);
|
|
}
|
|
|
|
await pack(packageDir, bunEnv, "--gzip-level=0");
|
|
const largerTarball = readTarball(join(packageDir, "pack-gzip-test-111111.1.11111111111111.tgz"));
|
|
expect(largerTarball.entries).toHaveLength(2);
|
|
|
|
await rm(join(packageDir, "pack-gzip-test-111111.1.11111111111111.tgz"));
|
|
|
|
await pack(packageDir, bunEnv, "--gzip-level=9");
|
|
const smallerTarball = readTarball(join(packageDir, "pack-gzip-test-111111.1.11111111111111.tgz"));
|
|
expect(smallerTarball.entries).toHaveLength(2);
|
|
|
|
expect(smallerTarball.size).toBeLessThan(largerTarball.size);
|
|
});
|
|
|
|
const destinationTests = [
|
|
{
|
|
"path": "",
|
|
},
|
|
{
|
|
"path": "dest-dir",
|
|
},
|
|
{
|
|
"path": "more/dir",
|
|
},
|
|
];
|
|
|
|
for (const { path } of destinationTests) {
|
|
test(`--destination="${path}"`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-dest-test",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
const dest = join(packageDir, path);
|
|
await pack(packageDir, bunEnv, `--destination=${dest}`);
|
|
|
|
const tarball = readTarball(join(dest, "pack-dest-test-1.1.1.tgz"));
|
|
expect(tarball.entries).toHaveLength(2);
|
|
});
|
|
}
|
|
|
|
const filenameTests = [
|
|
{
|
|
filename: "test.tgz",
|
|
error: false,
|
|
},
|
|
{
|
|
filename: "no-extension",
|
|
error: false,
|
|
},
|
|
{
|
|
filename: "no-extension.tar",
|
|
error: false,
|
|
},
|
|
{
|
|
filename: "out/foo.tgz",
|
|
error: true,
|
|
},
|
|
{
|
|
filename: "out/foo.tar",
|
|
mkdir: "out",
|
|
error: false,
|
|
},
|
|
];
|
|
|
|
for (const { filename, error, mkdir } of filenameTests) {
|
|
test(`--filename="${filename}"`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-dest-test",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
const dest = join(packageDir, filename);
|
|
if (mkdir) await fs.mkdir(join(packageDir, mkdir));
|
|
|
|
try {
|
|
await pack(packageDir, bunEnv, `--filename=${filename}`);
|
|
|
|
const tarball = readTarball(dest);
|
|
expect(tarball.entries).toHaveLength(2);
|
|
} catch (packError) {
|
|
if (!error) expect(packError).toBeNil();
|
|
}
|
|
});
|
|
}
|
|
|
|
test("--filename and --destination", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-dest-test",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
expect(async () => await pack(packageDir, bunEnv, "--filename=test.tgz", "--destination=packed")).toThrowError();
|
|
});
|
|
|
|
test("--ignore-scripts", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-ignore-scripts",
|
|
version: "1.1.1",
|
|
scripts: {
|
|
prepack: "touch prepack.txt",
|
|
postpack: "touch postpack.txt",
|
|
preprepare: "touch preprepare.txt",
|
|
prepare: "touch prepare.txt",
|
|
postprepare: "touch postprepare.txt",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv, "--ignore-scripts");
|
|
|
|
let results = await Promise.all([
|
|
exists(join(packageDir, "prepack.txt")),
|
|
exists(join(packageDir, "postpack.txt")),
|
|
exists(join(packageDir, "preprepare.txt")),
|
|
exists(join(packageDir, "prepare.txt")),
|
|
exists(join(packageDir, "postprepare.txt")),
|
|
]);
|
|
|
|
expect(results).toEqual([false, false, false, false, false]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
results = await Promise.all([
|
|
exists(join(packageDir, "prepack.txt")),
|
|
exists(join(packageDir, "postpack.txt")),
|
|
exists(join(packageDir, "preprepare.txt")),
|
|
exists(join(packageDir, "prepare.txt")),
|
|
exists(join(packageDir, "postprepare.txt")),
|
|
]);
|
|
|
|
expect(results).toEqual([true, true, false, true, false]);
|
|
});
|
|
|
|
test("--quiet", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-quiet-test",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
const { out } = await pack(packageDir, bunEnv, "--quiet");
|
|
|
|
// Should not contain verbose output
|
|
expect(out).not.toContain("Total files:");
|
|
expect(out).not.toContain("Shasum:");
|
|
expect(out).not.toContain("Integrity:");
|
|
expect(out).not.toContain("Unpacked size:");
|
|
expect(out).not.toContain("Packed size:");
|
|
expect(out).not.toContain("bun pack v");
|
|
|
|
// Should only contain the tarball name
|
|
expect(out.trim()).toBe("pack-quiet-test-1.1.1.tgz");
|
|
|
|
// Should still create the tarball
|
|
expect(await exists(join(packageDir, "pack-quiet-test-1.1.1.tgz"))).toBeTrue();
|
|
});
|
|
});
|
|
|
|
test("shasum and integrity are consistent", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-shasum",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
|
|
let { out } = await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-shasum-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
"pathname": "package/package.json",
|
|
},
|
|
{
|
|
"pathname": "package/index.js",
|
|
},
|
|
]);
|
|
|
|
expect(out).toContain(`Shasum: ${tarball.shasum}`);
|
|
|
|
await rm(join(packageDir, "pack-shasum-1.1.1.tgz"));
|
|
|
|
({ out } = await pack(packageDir, bunEnv));
|
|
|
|
const secondTarball = readTarball(join(packageDir, "pack-shasum-1.1.1.tgz"));
|
|
expect(secondTarball.entries).toMatchObject([
|
|
{
|
|
"pathname": "package/package.json",
|
|
},
|
|
{
|
|
"pathname": "package/index.js",
|
|
},
|
|
]);
|
|
|
|
expect(out).toContain(`Shasum: ${secondTarball.shasum}`);
|
|
expect(tarball.shasum).toBe(secondTarball.shasum);
|
|
expect(tarball.integrity).toBe(secondTarball.integrity);
|
|
});
|
|
|
|
describe("workspaces", () => {
|
|
async function createBasicWorkspace() {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-workspace",
|
|
version: "2.2.2",
|
|
workspaces: ["pkgs/*"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "pkgs", "pkg1", "package.json"), JSON.stringify({ name: "pkg1", version: "1.1.1" })),
|
|
write(join(packageDir, "pkgs", "pkg1", "index.js"), "console.log('hello ./index.js')"),
|
|
]);
|
|
}
|
|
test("in a workspace", async () => {
|
|
await createBasicWorkspace();
|
|
await pack(join(packageDir, "pkgs", "pkg1"), bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pkgs", "pkg1", "pkg1-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/index.js" }]);
|
|
});
|
|
test("in a workspace subdirectory", async () => {
|
|
await createBasicWorkspace();
|
|
await mkdir(join(packageDir, "pkgs", "pkg1", "subdir"));
|
|
|
|
await pack(join(packageDir, "pkgs", "pkg1", "subdir"), bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pkgs", "pkg1", "pkg1-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/index.js" }]);
|
|
});
|
|
test("replaces workspace: protocol without lockfile", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-workspace-protocol",
|
|
version: "2.3.4",
|
|
workspaces: ["pkgs/*"],
|
|
dependencies: {
|
|
"pkg1": "workspace:1.1.1",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "pkgs", "pkg1", "package.json"), JSON.stringify({ name: "pkg1", version: "1.1.1" })),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-workspace-protocol-2.3.4.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/pkgs/pkg1/package.json" },
|
|
{ "pathname": "package/root.js" },
|
|
]);
|
|
expect(JSON.parse(tarball.entries[0].contents)).toEqual({
|
|
name: "pack-workspace-protocol",
|
|
version: "2.3.4",
|
|
workspaces: ["pkgs/*"],
|
|
dependencies: {
|
|
"pkg1": "1.1.1",
|
|
},
|
|
});
|
|
});
|
|
|
|
const withLockfileWorkspaceProtocolTests = [
|
|
{ input: "workspace:^", expected: "^1.1.1" },
|
|
{ input: "workspace:~", expected: "~1.1.1" },
|
|
{ input: "workspace:1.x", expected: "1.x" },
|
|
{ input: "workspace:1.1.x", expected: "1.1.x" },
|
|
{ input: "workspace:*", expected: "1.1.1" },
|
|
{ input: "workspace:-", expected: "-" },
|
|
];
|
|
|
|
for (const { input, expected } of withLockfileWorkspaceProtocolTests) {
|
|
test(`replaces workspace: protocol with lockfile: ${input}`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-workspace-protocol-with-lockfile",
|
|
version: "2.5.6",
|
|
workspaces: ["pkgs/*"],
|
|
dependencies: {
|
|
"pkg1": input,
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "pkgs", "pkg1", "package.json"), JSON.stringify({ name: "pkg1", version: "1.1.1" })),
|
|
]);
|
|
|
|
await runBunInstall(bunEnv, packageDir);
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-workspace-protocol-with-lockfile-2.5.6.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/pkgs/pkg1/package.json" },
|
|
{ "pathname": "package/root.js" },
|
|
]);
|
|
expect(JSON.parse(tarball.entries[0].contents)).toEqual({
|
|
name: "pack-workspace-protocol-with-lockfile",
|
|
version: "2.5.6",
|
|
workspaces: ["pkgs/*"],
|
|
dependencies: {
|
|
"pkg1": expected,
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
test("fails gracefully when workspace version fails to resolve", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-workspace-protocol-fail",
|
|
version: "2.2.3",
|
|
workspaces: ["pkgs/*"],
|
|
dependencies: {
|
|
"pkg1": "workspace:*",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "pkgs", "pkg1", "package.json"), JSON.stringify({ name: "pkg1", version: "1.1.1" })),
|
|
]);
|
|
|
|
const { err } = await packExpectError(packageDir, bunEnv);
|
|
expect(err).toContain(
|
|
'error: Failed to resolve workspace version for "pkg1" in `dependencies`. Run `bun install` and try again.',
|
|
);
|
|
|
|
await runBunInstall(bunEnv, packageDir);
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-workspace-protocol-fail-2.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/pkgs/pkg1/package.json" },
|
|
{ "pathname": "package/root.js" },
|
|
]);
|
|
});
|
|
});
|
|
|
|
test("lifecycle scripts execution order", async () => {
|
|
const script = `const fs = require("fs");
|
|
fs.writeFileSync(\`\${process.argv[2]}.txt\`, \`
|
|
prepack: \${fs.existsSync("prepack.txt")}
|
|
prepare: \${fs.existsSync("prepare.txt")}
|
|
postpack: \${fs.existsSync("postpack.txt")}
|
|
tarball: \${fs.existsSync("pack-lifecycle-order-1.1.1.tgz")}\`)`;
|
|
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-lifecycle-order",
|
|
version: "1.1.1",
|
|
scripts: {
|
|
prepack: `${bunExe()} script.js prepack`,
|
|
postpack: `${bunExe()} script.js postpack`,
|
|
prepare: `${bunExe()} script.js prepare`,
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "script.js"), script),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-lifecycle-order-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/prepack.txt" },
|
|
{ "pathname": "package/prepare.txt" },
|
|
{ "pathname": "package/script.js" },
|
|
]);
|
|
|
|
const results = await Promise.all([
|
|
file(join(packageDir, "prepack.txt")).text(),
|
|
file(join(packageDir, "postpack.txt")).text(),
|
|
file(join(packageDir, "prepare.txt")).text(),
|
|
]);
|
|
|
|
expect(results).toEqual([
|
|
"\nprepack: false\nprepare: false\npostpack: false\ntarball: false",
|
|
"\nprepack: true\nprepare: true\npostpack: false\ntarball: true",
|
|
"\nprepack: true\nprepare: false\npostpack: false\ntarball: false",
|
|
]);
|
|
});
|
|
|
|
describe("bundledDependnecies", () => {
|
|
for (const bundledDependencies of ["bundledDependencies", "bundleDependencies"]) {
|
|
test(`basic (${bundledDependencies})`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bundled",
|
|
version: "4.4.4",
|
|
dependencies: {
|
|
"dep1": "1.1.1",
|
|
},
|
|
[bundledDependencies]: ["dep1"],
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "dep1", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep1",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bundled-4.4.4.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/node_modules/dep1/package.json" },
|
|
]);
|
|
});
|
|
}
|
|
|
|
test(`basic (bundledDependencies: true)`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bundled",
|
|
version: "4.4.4",
|
|
dependencies: {
|
|
"dep1": "1.1.1",
|
|
},
|
|
devDependencies: {
|
|
"dep2": "1.1.1",
|
|
},
|
|
bundledDependencies: true,
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "dep1", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep1",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "dep2", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep2",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bundled-4.4.4.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/node_modules/dep1/package.json" },
|
|
]);
|
|
});
|
|
|
|
test(`scoped bundledDependencies`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bundled",
|
|
version: "4.4.4",
|
|
dependencies: {
|
|
"@oven/bun": "1.1.1",
|
|
},
|
|
bundledDependencies: ["@oven/bun"],
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "@oven", "bun", "package.json"),
|
|
JSON.stringify({
|
|
name: "@oven/bun",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bundled-4.4.4.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/node_modules/@oven/bun/package.json" },
|
|
]);
|
|
});
|
|
|
|
test(`invalid bundledDependencies value should throw`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bundled",
|
|
version: "4.4.4",
|
|
bundledDependencies: "a",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
const { stdout, stderr, exited } = Bun.spawn({
|
|
cmd: [bunExe(), "pm", "pack"],
|
|
cwd: packageDir,
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
stdin: "ignore",
|
|
env: bunEnv,
|
|
});
|
|
|
|
const err = await stderr.text();
|
|
expect(err).toContain("error:");
|
|
expect(err).toContain("to be a boolean or an array of strings");
|
|
expect(err).not.toContain("warning:");
|
|
expect(err).not.toContain("failed");
|
|
expect(err).not.toContain("panic:");
|
|
|
|
const exitCode = await exited;
|
|
expect(exitCode).toBe(1);
|
|
});
|
|
|
|
test("resolve dep of bundled dep", async () => {
|
|
// Test that a bundled dep can have it's dependencies resolved without
|
|
// needing to add them to `bundledDependencies`. Also test that only
|
|
// the bundled deps are included, the other files in node_modules are excluded.
|
|
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-resolved-bundled-dep",
|
|
version: "5.5.5",
|
|
dependencies: {
|
|
dep1: "1.1.1",
|
|
},
|
|
bundledDependencies: ["dep1"],
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "dep1", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep1",
|
|
version: "1.1.1",
|
|
dependencies: {
|
|
dep2: "2.2.2",
|
|
dep3: "3.3.3",
|
|
},
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "dep2", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep2",
|
|
version: "2.2.2",
|
|
}),
|
|
),
|
|
write(join(packageDir, "node_modules", "dep1", "node_modules", "excluded.txt"), "do not add to tarball!"),
|
|
write(
|
|
join(packageDir, "node_modules", "dep1", "node_modules", "dep3", "package.json"),
|
|
JSON.stringify({
|
|
name: "dep3",
|
|
version: "3.3.3",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
const { out } = await pack(packageDir, bunEnv);
|
|
expect(out).toContain("Total files: 4");
|
|
expect(out).toContain("Bundled deps: 3");
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-resolved-bundled-dep-5.5.5.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/node_modules/dep1/node_modules/dep3/package.json" },
|
|
{ "pathname": "package/node_modules/dep1/package.json" },
|
|
{ "pathname": "package/node_modules/dep2/package.json" },
|
|
]);
|
|
});
|
|
|
|
test("scoped names", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-resolve-scoped",
|
|
version: "6.6.6",
|
|
dependencies: {
|
|
"@scoped/dep1": "1.1.1",
|
|
},
|
|
bundledDependencies: ["@scoped/dep1"],
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "@scoped", "dep1", "package.json"),
|
|
JSON.stringify({
|
|
name: "@scoped/dep1",
|
|
version: "1.1.1",
|
|
dependencies: {
|
|
"@scoped/dep2": "2.2.2",
|
|
"@scoped/dep3": "3.3.3",
|
|
},
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "@scoped", "dep2", "package.json"),
|
|
JSON.stringify({
|
|
name: "@scoped/dep2",
|
|
version: "2.2.2",
|
|
}),
|
|
),
|
|
write(
|
|
join(packageDir, "node_modules", "@scoped", "dep1", "node_modules", "@scoped", "dep3", "package.json"),
|
|
JSON.stringify({
|
|
name: "@scoped/dep3",
|
|
version: "3.3.3",
|
|
}),
|
|
),
|
|
]);
|
|
|
|
const { out } = await pack(packageDir, bunEnv);
|
|
expect(out).toContain("Total files: 4");
|
|
expect(out).toContain("Bundled deps: 3");
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-resolve-scoped-6.6.6.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/node_modules/@scoped/dep1/node_modules/@scoped/dep3/package.json" },
|
|
{ "pathname": "package/node_modules/@scoped/dep1/package.json" },
|
|
{ "pathname": "package/node_modules/@scoped/dep2/package.json" },
|
|
]);
|
|
});
|
|
|
|
test("ignore deps that aren't directories", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bundled-dep-not-dir",
|
|
version: "4.5.6",
|
|
dependencies: {
|
|
dep1: "1.1.1",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "node_modules", "dep1"), "hi. this is a file, not a directory"),
|
|
]);
|
|
|
|
const { out } = await pack(packageDir, bunEnv);
|
|
expect(out).toContain("Total files: 1");
|
|
expect(out).not.toContain("Bundled deps");
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bundled-dep-not-dir-4.5.6.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }]);
|
|
});
|
|
});
|
|
|
|
describe("files", () => {
|
|
test("CHANGELOG is not included by default", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-changelog",
|
|
version: "1.1.1",
|
|
files: ["lib"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "CHANGELOG.md"), "hello"),
|
|
write(join(packageDir, "lib", "index.js"), "console.log('hello ./lib/index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-changelog-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/lib/index.js" },
|
|
]);
|
|
});
|
|
|
|
test(".npmignore cannot exclude CHANGELOG", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-changelog",
|
|
version: "1.1.2",
|
|
}),
|
|
),
|
|
write(join(packageDir, ".npmignore"), "CHANGELOG\nCHANGELOG.*"),
|
|
write(join(packageDir, "CHANGELOG"), "hello"),
|
|
write(join(packageDir, "CHANGELOG.md"), "hello"),
|
|
write(join(packageDir, "CHANGELOG.txt"), "hello"),
|
|
]);
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-changelog-1.1.2.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/CHANGELOG" },
|
|
{ "pathname": "package/CHANGELOG.md" },
|
|
{ "pathname": "package/CHANGELOG.txt" },
|
|
]);
|
|
});
|
|
|
|
test("'files' field cannot exclude LICENSE", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-license",
|
|
version: "1.1.1",
|
|
files: ["lib", "!LICENSE"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "LICENSE"), "hello"),
|
|
write(join(packageDir, "lib", "index.js"), "console.log('hello ./lib/index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-license-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/LICENSE" },
|
|
{ "pathname": "package/lib/index.js" },
|
|
]);
|
|
});
|
|
|
|
test(".npmignore cannot exclude LICENSE", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-license",
|
|
version: "1.1.2",
|
|
}),
|
|
),
|
|
write(join(packageDir, ".npmignore"), "LICENSE"),
|
|
write(join(packageDir, "LICENSE"), "hello"),
|
|
]);
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-license-1.1.2.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/LICENSE" }]);
|
|
});
|
|
|
|
test("can include files and directories", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-1",
|
|
version: "1.1.1",
|
|
files: ["root.js", "subdir", "subdir2/subdir"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "subdir", "index.js"), "console.log('hello ./subdir/index.js')"),
|
|
write(join(packageDir, "subdir", "anotherdir", "index.js"), "console.log('hello ./subdir/anotherdir/index.js')"),
|
|
write(join(packageDir, "subdir2", "subdir", "index.js"), "console.log('hello ./subdir2/subdir/index.js')"),
|
|
|
|
// should not be included
|
|
write(join(packageDir, "subdir2", "index.js"), "console.log('hello, dont include me!')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-files-1-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/root.js" },
|
|
{ "pathname": "package/subdir/anotherdir/index.js" },
|
|
{ "pathname": "package/subdir/index.js" },
|
|
{ "pathname": "package/subdir2/subdir/index.js" },
|
|
]);
|
|
});
|
|
|
|
test("matches relative to root by default", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-2",
|
|
version: "1.2.3",
|
|
files: ["index.js"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
write(join(packageDir, "subdir", "index.js"), "console.log('hello ./subdir/index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-2-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/index.js" }]);
|
|
});
|
|
|
|
test("matches './' as the root", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-3",
|
|
version: "1.2.3",
|
|
files: ["./dist", "!./subdir", "!./dist/index.js", "./////src//index.ts"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "dist", "index.js"), "console.log('hello ./dist/index.js')"),
|
|
write(join(packageDir, "subdir", "index.js"), "console.log('hello ./subdir/index.js')"),
|
|
write(join(packageDir, "src", "dist", "index.js"), "console.log('hello ./src/dist/index.js')"),
|
|
write(join(packageDir, "src", "index.ts"), "console.log('hello ./src/index.ts')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-3-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/dist/index.js" },
|
|
{ "pathname": "package/src/index.ts" },
|
|
]);
|
|
});
|
|
|
|
test("recursive only if leading **/", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-files-4",
|
|
version: "1.2.123",
|
|
files: ["**/index.js", "!**/index.test.ts"],
|
|
}),
|
|
),
|
|
write(join(packageDir, "root.js"), "console.log('hello ./root.js')"),
|
|
write(join(packageDir, "subdir", "index.js"), "console.log('hello ./subdir/index.js')"),
|
|
write(join(packageDir, "subdir", "anotherdir", "index.js"), "console.log('hello ./subdir/anotherdir/index.js')"),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
write(join(packageDir, "index.test.ts"), "console.log('hello ./index.test.ts')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-files-4-1.2.123.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/index.js" },
|
|
{ "pathname": "package/subdir/anotherdir/index.js" },
|
|
{ "pathname": "package/subdir/index.js" },
|
|
]);
|
|
});
|
|
|
|
test("excluded entries within included directories are not included", async () => {
|
|
const dir = tempDirWithFiles("bun-pack-files-excluded-entries", {
|
|
"package.json": `
|
|
{
|
|
"name": "pack-excluded-entries-from-files",
|
|
"version": "1.0.0",
|
|
"files": ["src/**", "!src/**/*.test.ts"]
|
|
}
|
|
`,
|
|
src: {
|
|
"index.ts": "console.log('hello ./src/index.js')",
|
|
"index.test.ts": "test('foo', () => expect(1).toBe(1))",
|
|
},
|
|
});
|
|
|
|
const { out } = await pack(dir, bunEnv);
|
|
expect(out).toContain("Total files: 2");
|
|
const tarball = readTarball(join(dir, "pack-excluded-entries-from-files-1.0.0.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/src/index.ts" },
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe(".gitignore/.npmignore", () => {
|
|
for (const ignoreFile of [".gitignore", ".npmignore"]) {
|
|
test(`can ignore and un-ignore a file (${ignoreFile})`, async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-ignore-1",
|
|
version: "0.0.0",
|
|
}),
|
|
),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
write(join(packageDir, ignoreFile), "index.js"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-ignore-1-0.0.0.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }]);
|
|
|
|
await Promise.all([
|
|
rm(join(packageDir, "pack-ignore-1-0.0.0.tgz")),
|
|
write(join(packageDir, ignoreFile), "index.js\n!index.js"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball2 = readTarball(join(packageDir, "pack-ignore-1-0.0.0.tgz"));
|
|
expect(tarball2.entries).toMatchObject([
|
|
{ "pathname": "package/package.json" },
|
|
{ "pathname": "package/index.js" },
|
|
]);
|
|
|
|
await Promise.all([
|
|
rm(join(packageDir, "pack-ignore-1-0.0.0.tgz")),
|
|
write(join(packageDir, ignoreFile), "!index.js\nindex.js"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball3 = readTarball(join(packageDir, "pack-ignore-1-0.0.0.tgz"));
|
|
expect(tarball3.entries).toMatchObject([{ "pathname": "package/package.json" }]);
|
|
});
|
|
}
|
|
|
|
test("excludes files recursively", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-ignore-2",
|
|
version: "1.2.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, ".npmignore"), "index.js"),
|
|
write(join(packageDir, "index.js"), "console.log('hello ./index.js')"),
|
|
write(join(packageDir, "subdir", "index.js"), "console.log('hello ./subdir/index.js')"),
|
|
write(join(packageDir, "subdir", "subsubdir", "index.js"), "console.log('hello ./subdir/subsubdir/index.js')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-ignore-2-1.2.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }]);
|
|
});
|
|
});
|
|
|
|
describe("bins", () => {
|
|
test("basic", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bins",
|
|
version: "1.2.3",
|
|
bin: "bin.js",
|
|
}),
|
|
),
|
|
write(join(packageDir, "bin.js"), `#!/usr/bin/env bun\n`),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bins-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
pathname: "package/package.json",
|
|
},
|
|
{
|
|
pathname: "package/bin.js",
|
|
},
|
|
]);
|
|
|
|
expect(tarball.entries[0].perm & 0o644).toBe(0o644);
|
|
expect(tarball.entries[1].perm & (0o644 | 0o111)).toBe(0o644 | 0o111);
|
|
});
|
|
|
|
test("directory", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bins-dir",
|
|
version: "1.2.3",
|
|
directories: {
|
|
bin: "bins",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "bins", "bin1.js"), `#!/usr/bin/env bun\n`),
|
|
write(join(packageDir, "bins", "bin2.js"), `#!/usr/bin/env bun\n`),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bins-dir-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
pathname: "package/package.json",
|
|
},
|
|
{
|
|
pathname: "package/bins/bin1.js",
|
|
},
|
|
{
|
|
pathname: "package/bins/bin2.js",
|
|
},
|
|
]);
|
|
|
|
expect(tarball.entries[0].perm & 0o644).toBe(0o644);
|
|
expect(tarball.entries[1].perm & (0o644 | 0o111)).toBe(0o644 | 0o111);
|
|
expect(tarball.entries[2].perm & (0o644 | 0o111)).toBe(0o644 | 0o111);
|
|
});
|
|
|
|
test('are included even if not included in "files"', async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bins-and-files-1",
|
|
version: "2.2.2",
|
|
files: ["dist"],
|
|
bin: "bin.js",
|
|
}),
|
|
),
|
|
write(join(packageDir, "dist", "hi.js"), "console.log('hi!')"),
|
|
write(join(packageDir, "bin.js"), "console.log('hello')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bins-and-files-1-2.2.2.tgz"));
|
|
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
pathname: "package/package.json",
|
|
},
|
|
{
|
|
pathname: "package/bin.js",
|
|
},
|
|
{
|
|
pathname: "package/dist/hi.js",
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('"directories" works with "files"', async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bins-and-files-2",
|
|
version: "1.2.3",
|
|
files: ["dist"],
|
|
directories: {
|
|
bin: "bins",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "dist", "hi.js"), "console.log('hi!')"),
|
|
write(join(packageDir, "bins", "bin.js"), "console.log('hello')"),
|
|
write(join(packageDir, "bins", "what", "what.js"), "console.log('hello')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bins-and-files-2-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
pathname: "package/package.json",
|
|
},
|
|
{
|
|
pathname: "package/bins/bin.js",
|
|
},
|
|
{
|
|
pathname: "package/bins/what/what.js",
|
|
},
|
|
{
|
|
pathname: "package/dist/hi.js",
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('deduplicate with "files"', async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-bins-and-files-2",
|
|
version: "1.2.3",
|
|
files: ["dist", "bins/bin.js"],
|
|
directories: {
|
|
bin: "bins",
|
|
},
|
|
}),
|
|
),
|
|
write(join(packageDir, "dist", "hi.js"), "console.log('hi!')"),
|
|
write(join(packageDir, "bins", "bin.js"), "console.log('hello')"),
|
|
write(join(packageDir, "bins", "what", "what.js"), "console.log('hello')"),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
|
|
const tarball = readTarball(join(packageDir, "pack-bins-and-files-2-1.2.3.tgz"));
|
|
expect(tarball.entries).toMatchObject([
|
|
{
|
|
pathname: "package/package.json",
|
|
},
|
|
{
|
|
pathname: "package/bins/bin.js",
|
|
},
|
|
{
|
|
pathname: "package/bins/what/what.js",
|
|
},
|
|
{
|
|
pathname: "package/dist/hi.js",
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
test("unicode", async () => {
|
|
await Promise.all([
|
|
write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-unicode",
|
|
version: "1.1.1",
|
|
}),
|
|
),
|
|
write(join(packageDir, "äöüščří.js"), `console.log('hello ./äöüščří.js');`),
|
|
]);
|
|
|
|
await pack(packageDir, bunEnv);
|
|
const tarball = readTarball(join(packageDir, "pack-unicode-1.1.1.tgz"));
|
|
expect(tarball.entries).toMatchObject([{ "pathname": "package/package.json" }, { "pathname": "package/äöüščří.js" }]);
|
|
});
|
|
|
|
test("$npm_command is accurate", async () => {
|
|
await write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-command",
|
|
version: "1.1.1",
|
|
scripts: {
|
|
postpack: "echo $npm_command",
|
|
},
|
|
}),
|
|
);
|
|
const p = await pack(packageDir, bunEnv);
|
|
expect(p.out.split("\n")).toEqual([
|
|
`bun pack ${Bun.version_with_sha}`,
|
|
``,
|
|
`packed 94B package.json`,
|
|
``,
|
|
`pack-command-1.1.1.tgz`,
|
|
``,
|
|
`Total files: 1`,
|
|
expect.stringContaining(`Shasum: `),
|
|
expect.stringContaining(`Integrity: sha512-`),
|
|
`Unpacked size: 94B`,
|
|
expect.stringContaining(`Packed size: `),
|
|
``,
|
|
`pack`,
|
|
``,
|
|
]);
|
|
expect(p.err).toEqual(`$ echo $npm_command\n`);
|
|
});
|
|
|
|
test("$npm_lifecycle_event is accurate", async () => {
|
|
await write(
|
|
join(packageDir, "package.json"),
|
|
JSON.stringify({
|
|
name: "pack-lifecycle",
|
|
version: "1.1.1",
|
|
scripts: {
|
|
postpack: "echo $npm_lifecycle_event",
|
|
},
|
|
}),
|
|
);
|
|
const p = await pack(packageDir, bunEnv);
|
|
expect(p.out.split("\n")).toEqual([
|
|
`bun pack ${Bun.version_with_sha}`,
|
|
``,
|
|
`packed 104B package.json`,
|
|
``,
|
|
`pack-lifecycle-1.1.1.tgz`,
|
|
``,
|
|
`Total files: 1`,
|
|
expect.stringContaining(`Shasum: `),
|
|
expect.stringContaining(`Integrity: sha512-`),
|
|
`Unpacked size: 104B`,
|
|
expect.stringContaining(`Packed size: `),
|
|
``,
|
|
`postpack`,
|
|
``,
|
|
]);
|
|
expect(p.err).toEqual(`$ echo $npm_lifecycle_event\n`);
|
|
});
|