Skip to content

Commit 8f1c4bc

Browse files
committed
Add optimize support for bun.lock files
1 parent 9e97577 commit 8f1c4bc

File tree

2 files changed

+64
-38
lines changed

2 files changed

+64
-38
lines changed

src/commands/optimize.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,19 @@ const getOverridesDataByAgent: Record<Agent, GetOverrides> = {
108108
}
109109
}
110110

111-
type AgentLockIncludesFn = (lockSrc: string, name: string) => boolean
111+
type AgentLockIncludesFn = (
112+
lockSrc: string,
113+
name: string,
114+
ext?: string
115+
) => boolean
112116

113117
const lockIncludesByAgent: Record<Agent, AgentLockIncludesFn> = (() => {
118+
function npmLockIncludes(lockSrc: string, name: string) {
119+
// Detects the package name in the following cases:
120+
// "name":
121+
return lockSrc.includes(`"${name}":`)
122+
}
123+
114124
function yarnLockIncludes(lockSrc: string, name: string) {
115125
const escapedName = escapeRegExp(name)
116126
return new RegExp(
@@ -125,12 +135,13 @@ const lockIncludesByAgent: Record<Agent, AgentLockIncludesFn> = (() => {
125135
}
126136

127137
return {
128-
[BUN]: yarnLockIncludes,
129-
[NPM](lockSrc: string, name: string) {
130-
// Detects the package name in the following cases:
131-
// "name":
132-
return lockSrc.includes(`"${name}":`)
138+
[BUN](lockSrc: string, name: string, lockBasename?: string) {
139+
return (lockBasename === '.lock' ? npmLockIncludes : yarnLockIncludes)(
140+
lockSrc,
141+
name
142+
)
133143
},
144+
[NPM]: npmLockIncludes,
134145
[PNPM](lockSrc: string, name: string) {
135146
const escapedName = escapeRegExp(name)
136147
return new RegExp(
@@ -576,6 +587,7 @@ function workspacePatternToGlobPattern(workspace: string): string {
576587
type AddOverridesConfig = {
577588
agent: Agent
578589
agentExecPath: string
590+
lockBasename: string
579591
lockSrc: string
580592
manifestEntries: ManifestEntry[]
581593
npmExecPath: string
@@ -611,6 +623,7 @@ async function addOverrides(
611623
{
612624
agent,
613625
agentExecPath,
626+
lockBasename,
614627
lockSrc,
615628
manifestEntries,
616629
npmExecPath,
@@ -646,9 +659,9 @@ async function addOverrides(
646659
const thingToScan = isLockScanned
647660
? lockSrc
648661
: await lsByAgent[agent](agentExecPath, pkgPath, { npmExecPath })
649-
const thingScanner = isLockScanned
650-
? lockIncludesByAgent[agent]
651-
: depsIncludesByAgent[agent]
662+
const thingScanner = <AgentLockIncludesFn>(
663+
(isLockScanned ? lockIncludesByAgent[agent] : depsIncludesByAgent[agent])
664+
)
652665
const depEntries = getDependencyEntries(pkgJson)
653666

654667
const overridesDataObjects = <GetOverridesResult[]>[]
@@ -698,7 +711,10 @@ async function addOverrides(
698711
// Chunk package names to process them in parallel 3 at a time.
699712
await pEach(overridesDataObjects, 3, async ({ overrides, type }) => {
700713
const overrideExists = hasOwn(overrides, origPkgName)
701-
if (overrideExists || thingScanner(thingToScan, origPkgName)) {
714+
if (
715+
overrideExists ||
716+
thingScanner(thingToScan, origPkgName, lockBasename)
717+
) {
702718
const oldSpec = overrideExists ? overrides[origPkgName] : undefined
703719
const depAlias = depAliasMap.get(origPkgName)
704720
const regSpecStartsLike = `${NPM}:${regPkgName}@`
@@ -803,6 +819,7 @@ export const optimize: CliSubcommand = {
803819
agent,
804820
agentExecPath,
805821
agentVersion,
822+
lockBasename,
806823
lockPath,
807824
lockSrc,
808825
minimumNodeVersion,
@@ -830,7 +847,7 @@ export const optimize: CliSubcommand = {
830847
)
831848
return
832849
}
833-
const lockName = lockPath ? path.basename(lockPath) : 'lock file'
850+
const lockName = lockPath ? lockBasename : 'lock file'
834851
if (lockSrc === undefined) {
835852
console.error(`✖️ ${COMMAND_TITLE}: No ${lockName} found`)
836853
return
@@ -865,6 +882,7 @@ export const optimize: CliSubcommand = {
865882
{
866883
agent,
867884
agentExecPath,
885+
lockBasename,
868886
lockSrc,
869887
manifestEntries,
870888
npmExecPath,

src/utils/package-manager-detector.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ async function getAgentVersion(
4747
}
4848

4949
const LOCKS: Record<string, Agent> = {
50+
'bun.lock': BUN,
5051
'bun.lockb': BUN,
5152
// If both package-lock.json and npm-shrinkwrap.json are present in the root
5253
// of a project, npm-shrinkwrap.json will take precedence and package-lock.json
@@ -66,43 +67,46 @@ const LOCKS: Record<string, Agent> = {
6667
'node_modules/.package-lock.json': NPM
6768
}
6869

69-
type ReadLockFile = (
70-
lockPath: string,
71-
agentExecPath: string
72-
) => Promise<string | undefined>
70+
type ReadLockFile =
71+
| ((lockPath: string) => Promise<string | undefined>)
72+
| ((lockPath: string, agentExecPath: string) => Promise<string | undefined>)
7373

7474
const readLockFileByAgent: Record<Agent, ReadLockFile> = (() => {
75-
function wrapReader(
76-
reader: (
77-
lockPath: string,
78-
agentExecPath: string
79-
) => Promise<string | undefined>
80-
): ReadLockFile {
81-
return async (lockPath: string, agentExecPath: string) => {
75+
function wrapReader<T extends (...args: any[]) => Promise<any>>(
76+
reader: T
77+
): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>> | undefined> {
78+
return async (...args: any[]): Promise<any> => {
8279
try {
83-
return await reader(lockPath, agentExecPath)
80+
return await reader(...args)
8481
} catch {}
8582
return undefined
8683
}
8784
}
85+
86+
const binaryReader = wrapReader(readFileBinary)
87+
8888
const defaultReader = wrapReader(
8989
async (lockPath: string) => await readFileUtf8(lockPath)
9090
)
91+
9192
return {
9293
[BUN]: wrapReader(async (lockPath: string, agentExecPath: string) => {
93-
let lockBuffer: Buffer | undefined
94-
try {
95-
lockBuffer = <Buffer>await readFileBinary(lockPath)
96-
} catch {
97-
return undefined
94+
const ext = path.extname(lockPath)
95+
if (ext === '.lock') {
96+
return await defaultReader(lockPath)
97+
}
98+
if (ext === '.lockb') {
99+
const lockBuffer = await binaryReader(lockPath)
100+
if (lockBuffer) {
101+
try {
102+
return parseBunLockb(lockBuffer)
103+
} catch {}
104+
}
105+
// To print a Yarn lockfile to your console without writing it to disk
106+
// use `bun bun.lockb`.
107+
// https://bun.sh/guides/install/yarnlock
108+
return (await spawn(agentExecPath, [lockPath])).stdout.trim()
98109
}
99-
try {
100-
return <string>parseBunLockb(lockBuffer)
101-
} catch {}
102-
// To print a Yarn lockfile to your console without writing it to disk
103-
// use `bun bun.lockb`.
104-
// https://bun.sh/guides/install/yarnlock
105-
return (await spawn(agentExecPath, [lockPath])).stdout.trim()
106110
}),
107111
[NPM]: defaultReader,
108112
[PNPM]: defaultReader,
@@ -121,6 +125,7 @@ export type DetectResult = Readonly<{
121125
agent: Agent
122126
agentExecPath: string
123127
agentVersion: SemVer | undefined
128+
lockBasename: string | undefined
124129
lockPath: string | undefined
125130
lockSrc: string | undefined
126131
minimumNodeVersion: string
@@ -139,7 +144,8 @@ export async function detect({
139144
onUnknown
140145
}: DetectOptions = {}): Promise<DetectResult> {
141146
let lockPath = await findUp(Object.keys(LOCKS), { cwd })
142-
const isHiddenLockFile = lockPath?.endsWith('.package-lock.json') ?? false
147+
let lockBasename = lockPath ? path.basename(lockPath) : undefined
148+
const isHiddenLockFile = lockBasename === '.package-lock.json'
143149
const pkgJsonPath = lockPath
144150
? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`)
145151
: await findUp('package.json', { cwd })
@@ -173,9 +179,9 @@ export async function detect({
173179
agent === undefined &&
174180
!isHiddenLockFile &&
175181
typeof pkgJsonPath === 'string' &&
176-
typeof lockPath === 'string'
182+
typeof lockBasename === 'string'
177183
) {
178-
agent = <Agent>LOCKS[path.basename(lockPath)]
184+
agent = <Agent>LOCKS[lockBasename]
179185
}
180186
if (agent === undefined) {
181187
agent = NPM
@@ -238,12 +244,14 @@ export async function detect({
238244
? await readLockFileByAgent[agent](lockPath, agentExecPath)
239245
: undefined
240246
} else {
247+
lockBasename = undefined
241248
lockPath = undefined
242249
}
243250
return <DetectResult>{
244251
agent,
245252
agentExecPath,
246253
agentVersion,
254+
lockBasename,
247255
lockPath,
248256
lockSrc,
249257
minimumNodeVersion,

0 commit comments

Comments
 (0)