@take-out/scripts 0.0.92 → 0.0.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/up.ts CHANGED
@@ -1,66 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- /**
4
- * @description Upgrade packages by name (takeout, tamagui, one, zero, better-auth)
5
- */
6
-
7
- import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
8
- import { join } from 'node:path'
9
-
10
- import { $ } from 'bun'
11
-
12
- let globalTag: string | undefined
13
- const packagePatterns: string[] = []
14
-
15
- const args = process.argv.slice(2)
16
-
17
- // check if first arg is a named upgrade set
18
- const rootDir = process.cwd()
19
- const rootPackageJson = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf-8'))
20
- const upgradeSets: Record<string, string[]> = rootPackageJson.upgradeSets || {}
21
-
22
- for (let i = 0; i < args.length; i++) {
23
- const arg = args[i]!
24
- if (arg.startsWith('--tag=')) {
25
- const tagValue = arg.split('=')[1]
26
- if (tagValue) {
27
- globalTag = tagValue
28
- } else {
29
- console.error('Error: --tag option requires a value. Example: --tag=canary')
30
- process.exit(1)
31
- }
32
- } else if (arg === '--tag') {
33
- console.error('Error: --tag option requires a value and must use = syntax.')
34
- console.error('Correct usage: --tag=canary')
35
- console.error('Example: bun tko up --tag=canary react react-dom')
36
- process.exit(1)
37
- } else if (arg === '--canary') {
38
- globalTag = 'canary'
39
- } else if (arg === '--rc') {
40
- globalTag = 'rc'
41
- } else if (arg in upgradeSets) {
42
- // expand named upgrade set to its patterns
43
- packagePatterns.push(...upgradeSets[arg]!)
44
- } else {
45
- packagePatterns.push(arg)
46
- }
47
- }
48
-
49
- if (packagePatterns.length === 0) {
50
- const setNames = Object.keys(upgradeSets)
51
- if (setNames.length > 0) {
52
- console.info('Usage: bun tko up <target|pattern> [options]')
53
- console.info(`\nAvailable upgrade sets: ${setNames.join(', ')}`)
54
- console.info('\nOr provide package patterns directly:')
55
- console.info(' bun tko up @vxrn/* vxrn')
56
- console.info(' bun tko up --tag=canary react react-dom')
57
- } else {
58
- console.error('Please provide at least one package pattern to update.')
59
- console.error('Example: bun tko up @vxrn/* vxrn')
60
- console.error('Or with a tag: bun tko up --tag=canary @vxrn/* vxrn')
61
- }
62
- process.exit(1)
63
- }
3
+ import { cmd } from './cmd'
64
4
 
65
5
  interface PackageJson {
66
6
  dependencies?: Record<string, string>
@@ -69,383 +9,424 @@ interface PackageJson {
69
9
  optionalDependencies?: Record<string, string>
70
10
  }
71
11
 
72
- function findPackageJsonFiles(dir: string): string[] {
73
- const results: string[] = []
12
+ await cmd`upgrade packages by name or pattern`
13
+ .args('--tag string --canary boolean --rc boolean')
14
+ .run(async ({ args, $, path, fs }) => {
15
+ const { existsSync, readdirSync, readFileSync, writeFileSync, rmSync } =
16
+ await import('node:fs')
17
+
18
+ let globalTag: string | undefined = args.tag
19
+ if (args.canary) globalTag = 'canary'
20
+ if (args.rc) globalTag = 'rc'
21
+
22
+ const packagePatterns: string[] = []
23
+ const rootDir = process.cwd()
24
+ const rootPackageJson = JSON.parse(readFileSync(path.join(rootDir, 'package.json'), 'utf-8'))
25
+ const upgradeSets: Record<string, string[]> = rootPackageJson.upgradeSets || {}
26
+
27
+ for (const arg of args.rest) {
28
+ if (arg in upgradeSets) {
29
+ // expand named upgrade set to its patterns
30
+ packagePatterns.push(...upgradeSets[arg]!)
31
+ } else {
32
+ packagePatterns.push(arg)
33
+ }
34
+ }
74
35
 
75
- if (existsSync(join(dir, 'package.json'))) {
76
- results.push(join(dir, 'package.json'))
77
- }
36
+ if (packagePatterns.length === 0) {
37
+ const setNames = Object.keys(upgradeSets)
38
+ if (setNames.length > 0) {
39
+ console.info('Usage: bun tko up <target|pattern> [options]')
40
+ console.info(`\nAvailable upgrade sets: ${setNames.join(', ')}`)
41
+ console.info('\nOr provide package patterns directly:')
42
+ console.info(' bun tko up @vxrn/* vxrn')
43
+ console.info(' bun tko up --tag canary react react-dom')
44
+ } else {
45
+ console.error('Please provide at least one package pattern to update.')
46
+ console.error('Example: bun tko up @vxrn/* vxrn')
47
+ console.error('Or with a tag: bun tko up --tag canary @vxrn/* vxrn')
48
+ }
49
+ process.exit(1)
50
+ }
78
51
 
79
- // check if it's a monorepo with workspaces
80
- try {
81
- const packageJson = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))
82
- if (packageJson.workspaces) {
83
- let workspacePaths: string[] = []
52
+ function findPackageJsonFiles(dir: string): string[] {
53
+ const results: string[] = []
84
54
 
85
- if (Array.isArray(packageJson.workspaces)) {
86
- workspacePaths = packageJson.workspaces
87
- } else if (packageJson.workspaces.packages) {
88
- workspacePaths = packageJson.workspaces.packages
55
+ if (existsSync(path.join(dir, 'package.json'))) {
56
+ results.push(path.join(dir, 'package.json'))
89
57
  }
90
58
 
91
- for (const workspace of workspacePaths) {
92
- // handle glob patterns like "packages/*", "code/**/*", "./code/ui/**/*"
93
- const normalizedWorkspace = workspace.replace(/^\.\//, '')
94
-
95
- if (normalizedWorkspace.includes('**')) {
96
- // nested glob pattern - use glob to find all package.json files
97
- const baseDir = normalizedWorkspace.split('**')[0]!.replace(/\/$/, '')
98
- const basePath = join(dir, baseDir)
99
-
100
- if (existsSync(basePath)) {
101
- const findPackages = (searchDir: string) => {
102
- try {
103
- const entries = readdirSync(searchDir, { withFileTypes: true })
104
- for (const entry of entries) {
105
- if (entry.isDirectory() && entry.name !== 'node_modules') {
106
- const subPath = join(searchDir, entry.name)
107
- const pkgPath = join(subPath, 'package.json')
108
- if (existsSync(pkgPath)) {
109
- results.push(pkgPath)
59
+ // check if it's a monorepo with workspaces
60
+ try {
61
+ const packageJson = JSON.parse(
62
+ readFileSync(path.join(dir, 'package.json'), 'utf-8')
63
+ )
64
+ if (packageJson.workspaces) {
65
+ let workspacePaths: string[] = []
66
+
67
+ if (Array.isArray(packageJson.workspaces)) {
68
+ workspacePaths = packageJson.workspaces
69
+ } else if (packageJson.workspaces.packages) {
70
+ workspacePaths = packageJson.workspaces.packages
71
+ }
72
+
73
+ for (const workspace of workspacePaths) {
74
+ // handle glob patterns like "packages/*", "code/**/*", "./code/ui/**/*"
75
+ const normalizedWorkspace = workspace.replace(/^\.\//, '')
76
+
77
+ if (normalizedWorkspace.includes('**')) {
78
+ // nested glob pattern - use glob to find all package.json files
79
+ const baseDir = normalizedWorkspace.split('**')[0]!.replace(/\/$/, '')
80
+ const basePath = path.join(dir, baseDir)
81
+
82
+ if (existsSync(basePath)) {
83
+ const findPackages = (searchDir: string) => {
84
+ try {
85
+ const entries = readdirSync(searchDir, { withFileTypes: true })
86
+ for (const entry of entries) {
87
+ if (entry.isDirectory() && entry.name !== 'node_modules') {
88
+ const subPath = path.join(searchDir, entry.name)
89
+ const pkgPath = path.join(subPath, 'package.json')
90
+ if (existsSync(pkgPath)) {
91
+ results.push(pkgPath)
92
+ }
93
+ // recurse into subdirectories
94
+ findPackages(subPath)
95
+ }
110
96
  }
111
- // recurse into subdirectories
112
- findPackages(subPath)
97
+ } catch (_e) {
98
+ // ignore permission errors
113
99
  }
114
100
  }
115
- } catch (_e) {
116
- // ignore permission errors
101
+ findPackages(basePath)
117
102
  }
118
- }
119
- findPackages(basePath)
120
- }
121
- } else if (normalizedWorkspace.includes('*')) {
122
- // simple glob pattern like "packages/*"
123
- const workspaceDir = normalizedWorkspace.replace(/\/\*$/, '')
124
- if (existsSync(join(dir, workspaceDir))) {
125
- const subdirs = readdirSync(join(dir, workspaceDir), { withFileTypes: true })
126
- .filter((dirent) => dirent.isDirectory())
127
- .map((dirent) => join(dir, workspaceDir, dirent.name))
128
-
129
- for (const subdir of subdirs) {
130
- if (existsSync(join(subdir, 'package.json'))) {
131
- results.push(join(subdir, 'package.json'))
103
+ } else if (normalizedWorkspace.includes('*')) {
104
+ // simple glob pattern like "packages/*"
105
+ const workspaceDir = normalizedWorkspace.replace(/\/\*$/, '')
106
+ if (existsSync(path.join(dir, workspaceDir))) {
107
+ const subdirs = readdirSync(path.join(dir, workspaceDir), {
108
+ withFileTypes: true,
109
+ })
110
+ .filter((dirent) => dirent.isDirectory())
111
+ .map((dirent) => path.join(dir, workspaceDir, dirent.name))
112
+
113
+ for (const subdir of subdirs) {
114
+ if (existsSync(path.join(subdir, 'package.json'))) {
115
+ results.push(path.join(subdir, 'package.json'))
116
+ }
117
+ }
118
+ }
119
+ } else {
120
+ // exact path like "code/tamagui.dev" or "./code/sandbox"
121
+ const pkgPath = path.join(dir, normalizedWorkspace, 'package.json')
122
+ if (existsSync(pkgPath)) {
123
+ results.push(pkgPath)
132
124
  }
133
125
  }
134
126
  }
135
- } else {
136
- // exact path like "code/tamagui.dev" or "./code/sandbox"
137
- const pkgPath = join(dir, normalizedWorkspace, 'package.json')
138
- if (existsSync(pkgPath)) {
139
- results.push(pkgPath)
140
- }
141
127
  }
128
+ } catch (_error) {
129
+ // ignore errors parsing package.json
142
130
  }
143
- }
144
- } catch (_error) {
145
- // ignore errors parsing package.json
146
- }
147
131
 
148
- return results
149
- }
132
+ return results
133
+ }
150
134
 
151
- function extractDependencies(packageJsonPath: string): string[] {
152
- try {
153
- const content = readFileSync(packageJsonPath, 'utf-8')
154
- const packageJson = JSON.parse(content) as PackageJson
135
+ function extractDependencies(packageJsonPath: string): string[] {
136
+ try {
137
+ const content = readFileSync(packageJsonPath, 'utf-8')
138
+ const packageJson = JSON.parse(content) as PackageJson
155
139
 
156
- const deps: string[] = []
140
+ const deps: string[] = []
157
141
 
158
- const addNonWorkspaceDeps = (depsObject: Record<string, string> | undefined) => {
159
- if (!depsObject) return
160
- for (const [name, version] of Object.entries(depsObject)) {
161
- // skip workspace dependencies
162
- if (!version.startsWith('workspace:')) {
163
- deps.push(name)
142
+ const addNonWorkspaceDeps = (depsObject: Record<string, string> | undefined) => {
143
+ if (!depsObject) return
144
+ for (const [name, version] of Object.entries(depsObject)) {
145
+ // skip workspace dependencies
146
+ if (!version.startsWith('workspace:')) {
147
+ deps.push(name)
148
+ }
149
+ }
164
150
  }
165
- }
166
- }
167
151
 
168
- addNonWorkspaceDeps(packageJson.dependencies)
169
- addNonWorkspaceDeps(packageJson.devDependencies)
170
- addNonWorkspaceDeps(packageJson.peerDependencies)
171
- addNonWorkspaceDeps(packageJson.optionalDependencies)
152
+ addNonWorkspaceDeps(packageJson.dependencies)
153
+ addNonWorkspaceDeps(packageJson.devDependencies)
154
+ addNonWorkspaceDeps(packageJson.peerDependencies)
155
+ addNonWorkspaceDeps(packageJson.optionalDependencies)
172
156
 
173
- return deps
174
- } catch (error) {
175
- console.error(`Error parsing ${packageJsonPath}:`, error)
176
- return []
177
- }
178
- }
157
+ return deps
158
+ } catch (error) {
159
+ console.error(`Error parsing ${packageJsonPath}:`, error)
160
+ return []
161
+ }
162
+ }
179
163
 
180
- function doesPackageMatchPattern(packageName: string, pattern: string): boolean {
181
- if (pattern.includes('*')) {
182
- const regex = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
183
- return regex.test(packageName)
184
- }
185
- return packageName === pattern
186
- }
164
+ function doesPackageMatchPattern(packageName: string, pattern: string): boolean {
165
+ if (pattern.includes('*')) {
166
+ const regex = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
167
+ return regex.test(packageName)
168
+ }
169
+ return packageName === pattern
170
+ }
187
171
 
188
- function updatePackageJsonVersions(
189
- packageJsonPath: string,
190
- packagesToUpdate: string[],
191
- versionMap: Map<string, string>
192
- ): number {
193
- const content = readFileSync(packageJsonPath, 'utf-8')
194
- const packageJson = JSON.parse(content) as PackageJson
195
- let updatedCount = 0
196
-
197
- const updateDeps = (depsObject: Record<string, string> | undefined) => {
198
- if (!depsObject) return
199
- for (const pkg of packagesToUpdate) {
200
- const current = depsObject[pkg]
201
- if (current && !current.startsWith('workspace:')) {
202
- const newVersion = versionMap.get(pkg)
203
- if (newVersion) {
204
- // for tagged versions (canary, rc, etc), use exact version (no prefix)
205
- // otherwise preserve version prefix (^, ~, >=, etc)
206
- if (globalTag) {
207
- depsObject[pkg] = newVersion
208
- } else {
209
- // wildcard "*" means newly added placeholder, use ^ prefix
210
- if (current === '*') {
211
- depsObject[pkg] = `^${newVersion}`
172
+ function updatePackageJsonVersions(
173
+ packageJsonPath: string,
174
+ packagesToUpdate: string[],
175
+ versionMap: Map<string, string>
176
+ ): number {
177
+ const content = readFileSync(packageJsonPath, 'utf-8')
178
+ const packageJson = JSON.parse(content) as PackageJson
179
+ let updatedCount = 0
180
+
181
+ const updateDeps = (depsObject: Record<string, string> | undefined) => {
182
+ if (!depsObject) return
183
+ for (const pkg of packagesToUpdate) {
184
+ const current = depsObject[pkg]
185
+ if (current && !current.startsWith('workspace:')) {
186
+ const newVersion = versionMap.get(pkg)
187
+ if (newVersion) {
188
+ // for tagged versions (canary, rc, etc), use exact version (no prefix)
189
+ // otherwise preserve version prefix (^, ~, >=, etc)
190
+ if (globalTag) {
191
+ depsObject[pkg] = newVersion
192
+ } else {
193
+ // wildcard "*" means newly added placeholder, use ^ prefix
194
+ if (current === '*') {
195
+ depsObject[pkg] = `^${newVersion}`
196
+ updatedCount++
197
+ continue
198
+ }
199
+ const prefixMatch = current.match(/^([^\d]*)/)
200
+ const prefix = prefixMatch?.[1] || ''
201
+ depsObject[pkg] = `${prefix}${newVersion}`
202
+ }
212
203
  updatedCount++
213
- continue
214
204
  }
215
- const prefixMatch = current.match(/^([^\d]*)/)
216
- const prefix = prefixMatch?.[1] || ''
217
- depsObject[pkg] = `${prefix}${newVersion}`
218
205
  }
219
- updatedCount++
220
206
  }
221
207
  }
222
- }
223
- }
224
208
 
225
- updateDeps(packageJson.dependencies)
226
- updateDeps(packageJson.devDependencies)
227
- updateDeps(packageJson.peerDependencies)
228
- updateDeps(packageJson.optionalDependencies)
209
+ updateDeps(packageJson.dependencies)
210
+ updateDeps(packageJson.devDependencies)
211
+ updateDeps(packageJson.peerDependencies)
212
+ updateDeps(packageJson.optionalDependencies)
229
213
 
230
- if (updatedCount > 0) {
231
- writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
232
- }
214
+ if (updatedCount > 0) {
215
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
216
+ }
233
217
 
234
- return updatedCount
235
- }
218
+ return updatedCount
219
+ }
236
220
 
237
- async function updatePackages(
238
- packagesByWorkspace: Map<string, { dir: string; packages: string[] }>,
239
- rootDir: string,
240
- packageJsonFiles: string[]
241
- ) {
242
- try {
243
- rmSync(`node_modules/vite`, {
244
- recursive: true,
245
- force: true,
246
- })
247
- } catch (_e) {
248
- // ignore if vite is not there
249
- }
250
-
251
- // collect all unique packages to update
252
- const allPackages = new Set<string>()
253
- for (const { packages } of packagesByWorkspace.values()) {
254
- packages.forEach((pkg) => allPackages.add(pkg))
255
- }
256
-
257
- // fetch versions for all packages (with tag if specified)
258
- const versionMap = new Map<string, string>()
259
- console.info(`\nšŸ” Fetching versions for ${allPackages.size} package(s)...`)
260
-
261
- await Promise.all(
262
- [...allPackages].map(async (pkg) => {
221
+ async function updatePackages(
222
+ packagesByWorkspace: Map<string, { dir: string; packages: string[] }>,
223
+ rootDir: string,
224
+ packageJsonFiles: string[]
225
+ ) {
263
226
  try {
264
- const tag = globalTag || 'latest'
265
- const result = await $`npm view ${pkg}@${tag} version`.quiet()
266
- const version = result.text().trim()
267
- if (version) {
268
- versionMap.set(pkg, version)
269
- console.info(` āœ“ ${pkg}@${tag} → ${version}`)
270
- }
271
- } catch {
272
- if (globalTag) {
273
- console.info(` ⊘ ${pkg}@${globalTag} not found, skipping`)
274
- } else {
275
- console.info(` ⊘ ${pkg} not found, skipping`)
276
- }
227
+ rmSync(`node_modules/vite`, {
228
+ recursive: true,
229
+ force: true,
230
+ })
231
+ } catch (_e) {
232
+ // ignore if vite is not there
277
233
  }
278
- })
279
- )
280
-
281
- if (versionMap.size === 0) {
282
- console.info(`\nāš ļø No packages found to update`)
283
- return
284
- }
285
-
286
- // update all package.json files directly
287
- console.info(`\nšŸ“¦ Updating ${packageJsonFiles.length} package.json file(s)...`)
288
- let totalUpdates = 0
289
-
290
- for (const packageJsonPath of packageJsonFiles) {
291
- const packagesInWorkspace =
292
- packagesByWorkspace.get(getWorkspaceName(packageJsonPath, rootDir))?.packages || []
293
-
294
- if (packagesInWorkspace.length > 0) {
295
- const updates = updatePackageJsonVersions(
296
- packageJsonPath,
297
- packagesInWorkspace,
298
- versionMap
234
+
235
+ // collect all unique packages to update
236
+ const allPackages = new Set<string>()
237
+ for (const { packages } of packagesByWorkspace.values()) {
238
+ packages.forEach((pkg) => allPackages.add(pkg))
239
+ }
240
+
241
+ // fetch versions for all packages (with tag if specified)
242
+ const versionMap = new Map<string, string>()
243
+ console.info(`\nšŸ” Fetching versions for ${allPackages.size} package(s)...`)
244
+
245
+ await Promise.all(
246
+ [...allPackages].map(async (pkg) => {
247
+ try {
248
+ const tag = globalTag || 'latest'
249
+ const result = await $`npm view ${pkg}@${tag} version`.quiet()
250
+ const version = result.text().trim()
251
+ if (version) {
252
+ versionMap.set(pkg, version)
253
+ console.info(` āœ“ ${pkg}@${tag} → ${version}`)
254
+ }
255
+ } catch {
256
+ if (globalTag) {
257
+ console.info(` ⊘ ${pkg}@${globalTag} not found, skipping`)
258
+ } else {
259
+ console.info(` ⊘ ${pkg} not found, skipping`)
260
+ }
261
+ }
262
+ })
299
263
  )
300
- if (updates > 0) {
301
- const name = getWorkspaceName(packageJsonPath, rootDir)
302
- console.info(` āœ“ ${name}: ${updates} package(s)`)
303
- totalUpdates += updates
264
+
265
+ if (versionMap.size === 0) {
266
+ console.info(`\nāš ļø No packages found to update`)
267
+ return
304
268
  }
305
- }
306
- }
307
-
308
- console.info(`\nšŸ“ Updated ${totalUpdates} dependency version(s)`)
309
-
310
- console.info(`\nāš™ļø Running 'bun install'...`)
311
- $.cwd(rootDir)
312
- try {
313
- await $`bun install`
314
- console.info('āœ… Done!')
315
- } catch (error: any) {
316
- const stderr = error.stderr?.toString() || error.message || ''
317
- // check if it's a version resolution error (common after new publish)
318
- if (stderr.includes('No version matching') || stderr.includes('failed to resolve')) {
319
- console.info(`āš ļø Version not in cache, clearing cache and retrying...`)
269
+
270
+ // update all package.json files directly
271
+ console.info(`\nšŸ“¦ Updating ${packageJsonFiles.length} package.json file(s)...`)
272
+ let totalUpdates = 0
273
+
274
+ for (const packageJsonPath of packageJsonFiles) {
275
+ const packagesInWorkspace =
276
+ packagesByWorkspace.get(getWorkspaceName(packageJsonPath, rootDir))?.packages || []
277
+
278
+ if (packagesInWorkspace.length > 0) {
279
+ const updates = updatePackageJsonVersions(
280
+ packageJsonPath,
281
+ packagesInWorkspace,
282
+ versionMap
283
+ )
284
+ if (updates > 0) {
285
+ const name = getWorkspaceName(packageJsonPath, rootDir)
286
+ console.info(` āœ“ ${name}: ${updates} package(s)`)
287
+ totalUpdates += updates
288
+ }
289
+ }
290
+ }
291
+
292
+ console.info(`\nšŸ“ Updated ${totalUpdates} dependency version(s)`)
293
+
294
+ console.info(`\nāš™ļø Running 'bun install'...`)
295
+ $.cwd(rootDir)
320
296
  try {
321
- await $`bun pm cache rm`.quiet()
322
297
  await $`bun install`
323
298
  console.info('āœ… Done!')
324
- } catch (retryError: any) {
325
- const retryStderr = retryError.stderr?.toString() || retryError.message || ''
326
- console.error(
327
- `🚨 'bun install' failed after cache clear: ${retryStderr.split('\n')[0]}`
328
- )
299
+ } catch (error: any) {
300
+ const stderr = error.stderr?.toString() || error.message || ''
301
+ // check if it's a version resolution error (common after new publish)
302
+ if (stderr.includes('No version matching') || stderr.includes('failed to resolve')) {
303
+ console.info(`āš ļø Version not in cache, clearing cache and retrying...`)
304
+ try {
305
+ await $`bun pm cache rm`.quiet()
306
+ await $`bun install`
307
+ console.info('āœ… Done!')
308
+ } catch (retryError: any) {
309
+ const retryStderr = retryError.stderr?.toString() || retryError.message || ''
310
+ console.error(
311
+ `🚨 'bun install' failed after cache clear: ${retryStderr.split('\n')[0]}`
312
+ )
313
+ }
314
+ } else {
315
+ console.error(`🚨 'bun install' failed: ${stderr.split('\n')[0]}`)
316
+ }
329
317
  }
330
- } else {
331
- console.error(`🚨 'bun install' failed: ${stderr.split('\n')[0]}`)
332
318
  }
333
- }
334
- }
335
319
 
336
- function getWorkspaceName(packageJsonPath: string, rootDir: string): string {
337
- const dir = packageJsonPath.replace('/package.json', '')
338
- if (dir === rootDir) return 'root'
339
- return dir.replace(rootDir + '/', '')
340
- }
320
+ function getWorkspaceName(packageJsonPath: string, rootDir: string): string {
321
+ const dir = packageJsonPath.replace('/package.json', '')
322
+ if (dir === rootDir) return 'root'
323
+ return dir.replace(rootDir + '/', '')
324
+ }
341
325
 
342
- async function main() {
343
- const packageJsonFiles = findPackageJsonFiles(rootDir)
344
- console.info(`Found ${packageJsonFiles.length} package.json files`)
326
+ const packageJsonFiles = findPackageJsonFiles(rootDir)
327
+ console.info(`Found ${packageJsonFiles.length} package.json files`)
345
328
 
346
- // get workspace package names to exclude from updates
347
- const workspacePackageNames = new Set<string>()
348
- for (const packageJsonPath of packageJsonFiles) {
349
- if (packageJsonPath === join(rootDir, 'package.json')) continue
329
+ // get workspace package names to exclude from updates
330
+ const workspacePackageNames = new Set<string>()
331
+ for (const packageJsonPath of packageJsonFiles) {
332
+ if (packageJsonPath === path.join(rootDir, 'package.json')) continue
350
333
 
351
- try {
352
- const content = readFileSync(packageJsonPath, 'utf-8')
353
- const packageJson = JSON.parse(content)
354
- if (packageJson.name) {
355
- workspacePackageNames.add(packageJson.name)
334
+ try {
335
+ const content = readFileSync(packageJsonPath, 'utf-8')
336
+ const packageJson = JSON.parse(content)
337
+ if (packageJson.name) {
338
+ workspacePackageNames.add(packageJson.name)
339
+ }
340
+ } catch (_error) {
341
+ // ignore errors
356
342
  }
357
- } catch (_error) {
358
- // ignore errors
359
343
  }
360
- }
361
344
 
362
- console.info(
363
- `Found ${workspacePackageNames.size} workspace packages to exclude from updates`
364
- )
345
+ console.info(
346
+ `Found ${workspacePackageNames.size} workspace packages to exclude from updates`
347
+ )
365
348
 
366
- // build map of packages to update per workspace
367
- const packagesByWorkspace = new Map<string, { dir: string; packages: string[] }>()
368
- const allMatchingDeps = new Set<string>()
349
+ // build map of packages to update per workspace
350
+ const packagesByWorkspace = new Map<string, { dir: string; packages: string[] }>()
351
+ const allMatchingDeps = new Set<string>()
369
352
 
370
- for (const packageJsonPath of packageJsonFiles) {
371
- const deps = extractDependencies(packageJsonPath)
372
- const matchingDeps: string[] = []
353
+ for (const packageJsonPath of packageJsonFiles) {
354
+ const deps = extractDependencies(packageJsonPath)
355
+ const matchingDeps: string[] = []
373
356
 
374
- for (const dep of deps) {
375
- // skip workspace packages
376
- if (workspacePackageNames.has(dep)) continue
357
+ for (const dep of deps) {
358
+ // skip workspace packages
359
+ if (workspacePackageNames.has(dep)) continue
377
360
 
378
- for (const pattern of packagePatterns) {
379
- if (doesPackageMatchPattern(dep, pattern)) {
380
- matchingDeps.push(dep)
381
- allMatchingDeps.add(dep)
382
- break
361
+ for (const pattern of packagePatterns) {
362
+ if (doesPackageMatchPattern(dep, pattern)) {
363
+ matchingDeps.push(dep)
364
+ allMatchingDeps.add(dep)
365
+ break
366
+ }
383
367
  }
384
368
  }
385
- }
386
369
 
387
- if (matchingDeps.length > 0) {
388
- const dir = packageJsonPath.replace('/package.json', '')
389
- const name = getWorkspaceName(packageJsonPath, rootDir)
390
- packagesByWorkspace.set(name, { dir, packages: matchingDeps })
370
+ if (matchingDeps.length > 0) {
371
+ const dir = packageJsonPath.replace('/package.json', '')
372
+ const name = getWorkspaceName(packageJsonPath, rootDir)
373
+ packagesByWorkspace.set(name, { dir, packages: matchingDeps })
374
+ }
391
375
  }
392
- }
393
376
 
394
- if (allMatchingDeps.size === 0) {
395
- // no existing deps matched, but exact patterns (no wildcards) can be added fresh
396
- const exactPatterns = packagePatterns.filter((p) => !p.includes('*'))
397
- if (exactPatterns.length === 0) {
398
- console.info(
399
- `Found 0 dependencies matching patterns: ${packagePatterns.join(', ')}`
400
- )
401
- console.info('No matching packages found to update.')
402
- return
403
- }
377
+ if (allMatchingDeps.size === 0) {
378
+ // no existing deps matched, but exact patterns (no wildcards) can be added fresh
379
+ const exactPatterns = packagePatterns.filter((p) => !p.includes('*'))
380
+ if (exactPatterns.length === 0) {
381
+ console.info(
382
+ `Found 0 dependencies matching patterns: ${packagePatterns.join(', ')}`
383
+ )
384
+ console.info('No matching packages found to update.')
385
+ return
386
+ }
404
387
 
405
- // add as new dependencies to the root package.json
406
- console.info(`No existing deps found, adding to root: ${exactPatterns.join(', ')}`)
407
- const rootPkgPath = join(rootDir, 'package.json')
388
+ // add as new dependencies to the root package.json
389
+ console.info(`No existing deps found, adding to root: ${exactPatterns.join(', ')}`)
390
+ const rootPkgPath = path.join(rootDir, 'package.json')
408
391
 
409
- for (const pkg of exactPatterns) {
410
- allMatchingDeps.add(pkg)
411
- }
392
+ for (const pkg of exactPatterns) {
393
+ allMatchingDeps.add(pkg)
394
+ }
412
395
 
413
- packagesByWorkspace.set('root', {
414
- dir: rootDir,
415
- packages: exactPatterns,
416
- })
396
+ packagesByWorkspace.set('root', {
397
+ dir: rootDir,
398
+ packages: exactPatterns,
399
+ })
417
400
 
418
- // insert placeholder so updatePackageJsonVersions can set the real version
419
- const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
420
- if (!rootPkg.dependencies) {
421
- rootPkg.dependencies = {}
422
- }
423
- for (const pkg of exactPatterns) {
424
- if (!rootPkg.dependencies[pkg] && !rootPkg.devDependencies?.[pkg]) {
425
- rootPkg.dependencies[pkg] = '*'
401
+ // insert placeholder so updatePackageJsonVersions can set the real version
402
+ const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
403
+ if (!rootPkg.dependencies) {
404
+ rootPkg.dependencies = {}
405
+ }
406
+ for (const pkg of exactPatterns) {
407
+ if (!rootPkg.dependencies[pkg] && !rootPkg.devDependencies?.[pkg]) {
408
+ rootPkg.dependencies[pkg] = '*'
409
+ }
426
410
  }
411
+ writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
412
+ } else {
413
+ console.info(
414
+ `Found ${allMatchingDeps.size} dependencies matching patterns: ${packagePatterns.join(', ')}`
415
+ )
416
+ console.info(`Found matches in ${packagesByWorkspace.size} workspace(s)`)
427
417
  }
428
- writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
429
- } else {
430
- console.info(
431
- `Found ${allMatchingDeps.size} dependencies matching patterns: ${packagePatterns.join(', ')}`
432
- )
433
- console.info(`Found matches in ${packagesByWorkspace.size} workspace(s)`)
434
- }
435
-
436
- if (globalTag) {
437
- console.info(`šŸ·ļø Using tag '${globalTag}'`)
438
- }
439
418
 
440
- await updatePackages(packagesByWorkspace, rootDir, packageJsonFiles)
419
+ if (globalTag) {
420
+ console.info(`šŸ·ļø Using tag '${globalTag}'`)
421
+ }
441
422
 
442
- // special handling for zero - update ZERO_VERSION in .env
443
- if (packagePatterns.includes('@rocicorp/zero')) {
444
- console.info('\nšŸ”„ Updating local env for Zero...')
445
- await $`bun tko run update-local-env`
446
- }
423
+ await updatePackages(packagesByWorkspace, rootDir, packageJsonFiles)
447
424
 
448
- console.info('\nšŸŽ‰ Dependency update complete!')
449
- }
425
+ // special handling for zero - update ZERO_VERSION in .env
426
+ if (packagePatterns.includes('@rocicorp/zero')) {
427
+ console.info('\nšŸ”„ Updating local env for Zero...')
428
+ await $`bun tko run update-local-env`
429
+ }
450
430
 
451
- await main()
431
+ console.info('\nšŸŽ‰ Dependency update complete!')
432
+ })