Skip to content

Commit c2bf6fd

Browse files
feat: add package version for bun
BREAKING CHANGE
1 parent d1488d0 commit c2bf6fd

7 files changed

Lines changed: 153 additions & 117 deletions

File tree

package.json

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,12 @@
77
"files": [
88
"dist/**/*"
99
],
10-
"main": "./dist/cjs/index.js",
11-
"module": "./dist/esm/index.mjs",
10+
"main": "./dist/generic.js",
1211
"exports": {
1312
".": {
14-
"import": {
15-
"types": "./dist/esm/index.d.mts",
16-
"default": "./dist/esm/index.mjs"
17-
},
18-
"require": {
19-
"types": "./dist/cjs/index.d.ts",
20-
"default": "./dist/cjs/index.js"
21-
}
13+
"bun": "./dist/bun.mjs",
14+
"types": "./dist/generic.d.ts",
15+
"default": "./dist/generic.js"
2216
},
2317
"./package.json": "./package.json"
2418
},

src/bun.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { builtinModules } from "node:module";
2+
3+
import { checkModule, getModules, bundledBunModules, implementedNodeModules } from "./shared";
4+
import type { BunVersion, Modules } from "./shared";
5+
6+
export type { BunVersion };
7+
export { MINIMUM_BUN_VERSION } from "./shared";
8+
9+
const currentBunVersion = Bun.version as BunVersion;
10+
11+
const bunModules = { ...bundledBunModules } as Modules;
12+
// don't do the same with node modules because `builtinModules` in bun contains even not implemented node modules
13+
for (const moduleName of builtinModules) {
14+
if (moduleName.startsWith("bun:")) {
15+
bunModules[moduleName] ??= `>=${currentBunVersion}`;
16+
}
17+
}
18+
19+
export function isBunModule(moduleName: string, bunVersion?: BunVersion): boolean {
20+
return checkModule(moduleName, bunModules, bunVersion ?? currentBunVersion);
21+
}
22+
23+
export function isBunImplementedNodeModule(moduleName: string, bunVersion?: BunVersion): boolean {
24+
return checkModule(
25+
moduleName.replace(/^node:/, ""),
26+
implementedNodeModules,
27+
bunVersion ?? currentBunVersion,
28+
);
29+
}
30+
31+
export function isBunBuiltin(moduleName: string, bunVersion?: BunVersion): boolean {
32+
return isBunModule(moduleName, bunVersion) || isBunImplementedNodeModule(moduleName, bunVersion);
33+
}
34+
35+
export function getBunModules(bunVersion?: BunVersion): string[] {
36+
return getModules(bunModules, bunVersion ?? currentBunVersion);
37+
}
38+
39+
export function getBunImplementedNodeModules(bunVersion?: BunVersion): string[] {
40+
return getModules(implementedNodeModules, bunVersion ?? currentBunVersion);
41+
}
42+
43+
export function getBunBuiltinModules(bunVersion?: BunVersion): string[] {
44+
return [...getBunModules(bunVersion), ...getBunImplementedNodeModules(bunVersion)];
45+
}

src/generic.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { checkModule, getModules, bundledBunModules, implementedNodeModules } from "./shared";
2+
import type { BunVersion } from "./shared";
3+
4+
export type { BunVersion };
5+
export { MINIMUM_BUN_VERSION } from "./shared";
6+
7+
export function isBunModule(moduleName: string, bunVersion?: BunVersion): boolean {
8+
return checkModule(moduleName, bundledBunModules, bunVersion ?? "latest");
9+
}
10+
11+
export function isBunImplementedNodeModule(moduleName: string, bunVersion?: BunVersion): boolean {
12+
return checkModule(
13+
moduleName.replace(/^node:/, ""),
14+
implementedNodeModules,
15+
bunVersion ?? "latest",
16+
);
17+
}
18+
19+
export function isBunBuiltin(moduleName: string, bunVersion?: BunVersion): boolean {
20+
return isBunModule(moduleName, bunVersion) || isBunImplementedNodeModule(moduleName, bunVersion);
21+
}
22+
23+
export function getBunModules(bunVersion?: BunVersion): string[] {
24+
return getModules(bundledBunModules, bunVersion ?? "latest");
25+
}
26+
27+
export function getBunImplementedNodeModules(bunVersion?: BunVersion): string[] {
28+
return getModules(implementedNodeModules, bunVersion ?? "latest");
29+
}
30+
31+
export function getBunBuiltinModules(bunVersion?: BunVersion): string[] {
32+
return [...getBunModules(bunVersion), ...getBunImplementedNodeModules(bunVersion)];
33+
}

src/index.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

src/shared.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import valid from "semver/functions/valid";
2+
import satisfies from "semver/functions/satisfies";
3+
import lt from "semver/functions/lt";
4+
5+
export { default as bundledBunModules } from "@assets/bun-modules.json";
6+
export { default as implementedNodeModules } from "@assets/implemented-node-modules.json";
7+
8+
type SemVerBaseStringified = `${bigint}.${bigint}.${bigint}`;
9+
type SemVerStringifiedWithReleaseName = `${SemVerBaseStringified}-${string}`;
10+
type SemVerStringified = SemVerBaseStringified | SemVerStringifiedWithReleaseName;
11+
export type BunVersion = SemVerStringified | "latest";
12+
13+
export type Modules = Record<string, string | boolean>;
14+
15+
export const MINIMUM_BUN_VERSION = "1.0.0" satisfies SemVerBaseStringified;
16+
17+
export function checkModule(moduleName: string, modules: Modules, bunVersion: BunVersion): boolean {
18+
if (typeof moduleName !== "string") throw new TypeError("Module name must be a string");
19+
if (!(moduleName in modules)) return false;
20+
21+
const targetBunVersion = toSemVerStringified(bunVersion);
22+
if (lt(targetBunVersion, MINIMUM_BUN_VERSION)) {
23+
throw new RangeError(`Bun version must be at least ${MINIMUM_BUN_VERSION}`);
24+
}
25+
26+
return satisfiesVersionRange(targetBunVersion, modules[moduleName]!);
27+
}
28+
29+
export function getModules(modules: Modules, bunVersion?: BunVersion): string[] {
30+
const targetBunVersion = toSemVerStringified(bunVersion);
31+
if (lt(targetBunVersion, MINIMUM_BUN_VERSION)) {
32+
throw new RangeError(`Bun version must be at least ${MINIMUM_BUN_VERSION}`);
33+
}
34+
35+
return Object.keys(modules).filter((moduleName) => {
36+
return satisfiesVersionRange(targetBunVersion, modules[moduleName]!);
37+
});
38+
}
39+
40+
function satisfiesVersionRange(
41+
version: SemVerStringified,
42+
versionRange: string | boolean,
43+
): boolean {
44+
if (typeof versionRange === "boolean") return versionRange;
45+
return satisfies(version, versionRange);
46+
}
47+
48+
function toSemVerStringified(input: unknown): SemVerStringified {
49+
if (typeof input !== "string") throw new TypeError("Bun version must be a string");
50+
if (input === "latest") return "999.999.999" as SemVerStringified;
51+
if (valid(input)) return input as SemVerBaseStringified;
52+
throw new TypeError("Bun version must be a string like '1.0.0' or 'latest'");
53+
}

test/getModules.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, describe } from "bun:test";
22
import bundledBunModules from "@assets/bun-modules.json";
3-
import bundledNodeModules from "@assets/node-modules.json";
3+
import bundledNodeModules from "@assets/implemented-node-modules.json";
44

55
import {
66
getBunModules,
@@ -25,7 +25,7 @@ describe("Module lists checking", () => {
2525
});
2626
});
2727

28-
test("getBunImplementedNodeModules() equals keys of node-modules.json", () => {
28+
test("getBunImplementedNodeModules() equals keys of implemented-node-modules.json", () => {
2929
expect(getBunImplementedNodeModules()).toContainAllValues(nodeModulesList);
3030
});
3131
test("getBunImplementedNodeModules() returns only node modules", () => {
@@ -37,7 +37,7 @@ describe("Module lists checking", () => {
3737
expect(getBunImplementedNodeModules("1.0.0")).not.toContain("http2");
3838
});
3939

40-
test("getBunBuiltinModules() equals keys of node-modules.json && bun-modules.json", () => {
40+
test("getBunBuiltinModules() equals keys of implemented-node-modules.json && bun-modules.json", () => {
4141
expect(getBunBuiltinModules()).toContainAllValues(builtinModulesList);
4242
});
4343
test("getBunBuiltinModules() returns only built-in modules", () => {

tsup.config.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
import { defineConfig, type Options } from "tsup";
22

3-
const baseConfig = {
4-
entry: ["src/index.ts"],
3+
const sharedConfig = {
4+
entry: ["src/shared.ts"],
55
target: "es2019",
6+
format: ["cjs"],
67
dts: true,
78
clean: true,
89
} satisfies Options;
910

10-
const cjsConfig = {
11-
...baseConfig,
12-
format: "cjs",
13-
outDir: "dist/cjs",
11+
const genericConfig = {
12+
entry: ["src/generic.ts"],
13+
target: "es2019",
14+
format: ["cjs"],
15+
external: ["./shared"],
16+
dts: true,
1417
} satisfies Options;
1518

16-
const esmConfig = {
17-
...baseConfig,
18-
format: "esm",
19-
outDir: "dist/esm",
19+
const bunConfig = {
20+
entry: ["src/bun.ts"],
21+
target: "es2022",
22+
format: ["esm"],
23+
external: ["./shared"],
2024
} satisfies Options;
2125

22-
export default defineConfig([cjsConfig, esmConfig]);
26+
export default defineConfig([sharedConfig, genericConfig, bunConfig]);

0 commit comments

Comments
 (0)