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

allow importing bun.lock (+ types for it) #16244

Merged
merged 16 commits into from
Jan 13, 2025
10 changes: 10 additions & 0 deletions packages/bun-types/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ declare module "*.toml" {
var contents: any;
export = contents;
}

declare module "*.jsonc" {
var contents: any;
export = contents;
}

declare module "*/bun.lock" {
var contents: import("bun").BunLockFile;
export = contents;
}
71 changes: 67 additions & 4 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1233,13 +1233,13 @@ declare module "bun" {

/**
* Deletes the file. ( same as unlink )
*/
delete(): Promise<void>
*/
delete(): Promise<void>;

/**
* Provides useful information about the file.
*/
stat(): Promise<Stats>
*/
stat(): Promise<Stats>;
}
interface NetworkSink extends FileSink {
/**
Expand Down Expand Up @@ -6431,6 +6431,69 @@ declare module "bun" {
*/
timestamp?: number | Date,
): Buffer;

/**
* Types for `bun.lock`
*/
type BunLockFile = {
lockfileVersion: 0;
workspaces: {
[workspace: string]: BunLockFileWorkspacePackage;
};
overrides?: Record<string, string>;
patchedDependencies?: Record<string, string>;
trustedDependencies?: string[];

/**
* ```
* INFO = { prod/dev/optional/peer dependencies, os, cpu, libc (TODO), bin, binDir }
*
* npm -> [ "name@version", registry (TODO: remove if default), INFO, integrity]
* symlink -> [ "name@link:path", INFO ]
* folder -> [ "name@file:path", INFO ]
* workspace -> [ "name@workspace:path", INFO ]
* tarball -> [ "name@tarball", INFO ]
* root -> [ "name@root:", { bin, binDir } ]
* git -> [ "name@git+repo", INFO, .bun-tag string (TODO: remove this) ]
* github -> [ "name@github:user/repo", INFO, .bun-tag string (TODO: remove this) ]
* ```
* */
packages: {
[pkg: string]: BunLockFilePackageArray;
};
};

type BunLockFileBasePackageInfo = {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
optionalPeers?: string[];
};

type BunLockFileWorkspacePackage = BunLockFileBasePackageInfo & {
name?: string;
version?: string;
};

type BunLockFilePackageInfo = BunLockFileBasePackageInfo & {
os?: string | string[];
cpu?: string | string[];
bin?: Record<string, string>;
binDir?: string;
bundled?: true;
};

/** @see {@link BunLockFile.packages} for more info */
type BunLockFilePackageArray =
/** npm */
| [pkg: string, registry: string, info: BunLockFilePackageInfo, integrity: string]
/** symlink, folder, tarball, workspace */
| [pkg: string, info: BunLockFilePackageInfo]
/** git, github */
| [pkg: string, info: BunLockFilePackageInfo, bunTag: string]
/** root */
| [pkg: string, info: Pick<BunLockFilePackageInfo, "bin" | "binDir">];
}

// extends lib.dom.d.ts
Expand Down
4 changes: 4 additions & 0 deletions src/bun.js/module_loader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2392,6 +2392,10 @@ pub const ModuleLoader = struct {
}
}

if (strings.eqlComptime(path.name.filename, "bun.lock")) {
loader = .json;
}

// We only run the transpiler concurrently when we can.
// Today, that's:
//
Expand Down
13 changes: 9 additions & 4 deletions src/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1713,15 +1713,20 @@ pub const Path = struct {

pub fn isJSONCFile(this: *const Path) bool {
const str = this.name.filename;
if (strings.eqlComptime(str, "package.json")) {

if (strings.eqlComptime(str, "package.json") or strings.eqlComptime(str, "bun.lock")) {
return true;
}

if (strings.hasSuffixComptime(str, ".jsonc")) {
return true;
}

if (!(strings.hasPrefixComptime(str, "tsconfig.") or strings.hasPrefixComptime(str, "jsconfig."))) {
return false;
if (strings.hasPrefixComptime(str, "tsconfig.") or strings.hasPrefixComptime(str, "jsconfig.")) {
return strings.hasSuffixComptime(str, ".json");
}

return strings.hasSuffixComptime(str, ".json");
return false;
}

pub const PackageRelative = struct {
Expand Down
20 changes: 13 additions & 7 deletions src/options.zig
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ pub const Loader = enum(u8) {
.{ "css", .css },
.{ "file", .file },
.{ "json", .json },
.{ "jsonc", .json },
.{ "toml", .toml },
.{ "wasm", .wasm },
.{ "node", .napi },
Expand All @@ -783,6 +784,7 @@ pub const Loader = enum(u8) {
.{ "css", .css },
.{ "file", .file },
.{ "json", .json },
.{ "jsonc", .json },
.{ "toml", .toml },
.{ "wasm", .wasm },
.{ "node", .napi },
Expand Down Expand Up @@ -908,6 +910,7 @@ const default_loaders_posix = .{
.{ ".txt", .text },
.{ ".text", .text },
.{ ".html", .html },
.{ ".jsonc", .json },
};
const default_loaders_win32 = default_loaders_posix ++ .{
.{ ".sh", .bunsh },
Expand Down Expand Up @@ -1286,16 +1289,18 @@ pub fn definesFromTransformOptions(

const default_loader_ext_bun = [_]string{".node"};
const default_loader_ext = [_]string{
".jsx", ".json",
".js", ".mjs",
".cjs", ".css",
".jsx", ".json",
".js", ".mjs",
".cjs", ".css",

// https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/#new-file-extensions
".ts", ".tsx",
".mts", ".cts",
".ts", ".tsx",
".mts", ".cts",

".toml", ".wasm",
".txt", ".text",
".toml", ".wasm",
".txt", ".text",

".jsonc",
};

// Only set it for browsers by default.
Expand All @@ -1314,6 +1319,7 @@ const node_modules_default_loader_ext = [_]string{
".toml",
".txt",
".json",
".jsonc",
".css",
".tsx",
".cts",
Expand Down
27 changes: 27 additions & 0 deletions test/js/bun/resolve/bun-lock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { expect, test } from "bun:test";
import { tempDirWithFiles } from "harness";
import { join } from "path";

const lockfile = `{
"lockfileVersion": 0,
"workspaces": {
"": {
"name": "something",
"dependencies": { },
},
},
"packages": { },
}`;

test("import bun.lock file as json", async () => {
const dir = tempDirWithFiles("bun-lock", {
"bun.lock": lockfile,
"index.ts": `
import lockfile from './bun.lock';
const _lockfile = ${lockfile}
if (!Bun.deepEquals(lockfile, _lockfile)) throw new Error('bun.lock wasnt imported as jsonc');
`,
});

expect([join(dir, "index.ts")]).toRun();
});
16 changes: 16 additions & 0 deletions test/js/bun/resolve/jsonc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,19 @@ test("empty jsonc - tsconfig.json", async () => {
});
expect([join(dir, "index.ts")]).toRun();
});

test("import anything.jsonc as json", async () => {
const jsoncFile = `{
// comment
"trailingComma": 0,
}`;
const dir = tempDirWithFiles("jsonc", {
"anything.jsonc": jsoncFile,
"index.ts": `
import file from './anything.jsonc';
const _file = ${jsoncFile}
if (!Bun.deepEquals(file, _file)) throw new Error('anything.jsonc wasnt imported as jsonc');
`,
});
expect([join(dir, "index.ts")]).toRun();
});
Loading