-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy pathversion-packages.mjs
178 lines (151 loc) · 5.72 KB
/
version-packages.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import { exec, spawnSync } from 'node:child_process'
import { randomUUID } from 'node:crypto'
import fs from 'node:fs/promises'
import { tmpdir } from 'node:os'
import path from 'node:path'
import url from 'node:url'
import prettier from 'prettier'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const root = path.resolve(__dirname, '..')
const version = process.argv[2] || null
// The known workspace is: @tailwindcss/oxide
// All the workspaces in `crates/node/npm/*` should always be in sync with
// `@tailwindcss/oxide`. You can think of them as one big package, but they are
// split into multiple packages because they are OS specific.
const syncedWorkspaces = new Map([
[
'@tailwindcss/oxide',
[
'crates/node/npm/android-arm-eabi',
'crates/node/npm/android-arm64',
'crates/node/npm/darwin-arm64',
'crates/node/npm/darwin-x64',
'crates/node/npm/freebsd-x64',
'crates/node/npm/linux-arm-gnueabihf',
'crates/node/npm/linux-arm64-gnu',
'crates/node/npm/linux-arm64-musl',
'crates/node/npm/linux-x64-gnu',
'crates/node/npm/linux-x64-musl',
'crates/node/npm/wasm32-wasi',
'crates/node/npm/win32-arm64-msvc',
'crates/node/npm/win32-x64-msvc',
],
],
['@tailwindcss/cli', ['packages/@tailwindcss-standalone']],
])
const inverseSyncedWorkspaces = new Map()
for (let [name, paths] of syncedWorkspaces) {
for (let [idx, filePath] of paths.entries()) {
// Make sure all the paths are absolute paths
paths[idx] = path.resolve(root, filePath, 'package.json')
// Make sure inverse lookup table exists
inverseSyncedWorkspaces.set(paths[idx], name)
}
}
exec(
"pnpm --silent --filter='!./playgrounds/*' --filter='!./integrations' --filter='!./packages/internal-example-plugin' -r exec pwd",
async (err, stdout) => {
if (err) {
console.error(err)
process.exit(1)
}
if (version !== null) {
for (let pkgPath of stdout
.trim()
.split('\n')
.map((x) => path.resolve(x, 'package.json'))) {
let pkg = await fs.readFile(pkgPath, 'utf8').then(JSON.parse)
let name = pkg.name
if (version !== '') {
// Ensure the version is set after the name and before everything else
delete pkg.name
delete pkg.version
// This allows us to keep the order of the keys in the package.json
pkg = { name, version, ...pkg }
}
await fs.writeFile(
pkgPath,
await prettier
.format(JSON.stringify(pkg, null, 2), { filepath: pkgPath })
.then((x) => `${x.trim()}\n`),
)
}
console.log('Done.')
return
}
let paths = stdout
.trim()
.split('\n')
.map((x) => path.resolve(x, 'package.json'))
// Workspaces that are in sync with another workspace should not be updated
// manually, they should be updated by updating the main workspace.
.filter((x) => !inverseSyncedWorkspaces.has(x))
let workspaces = new Map()
// Track all the workspaces
for (let path of paths) {
let pkg = await fs.readFile(path, 'utf8').then(JSON.parse)
if (pkg.private) continue
workspaces.set(pkg.name, { version: pkg.version ?? '', path })
}
// Build the editable output
let lines = ['# Update the versions of the packages you want to change', '']
for (let [name, info] of workspaces) {
lines.push(`${name}: ${info.version}`)
}
let output = lines.join('\n')
// Edit the file
{
// Figure out which editor to use.
//
// In this case we still split on whitespace, because it can happen that the
// EDITOR env variable is configured as `code --wait`. This means that we
// want `code` as the editor, but `--wait` is one of the arguments.
let args = process.env.EDITOR.split(' ')
let editor = args.shift()
// Create a temporary file which will be edited
let filepath = path.resolve(tmpdir(), `version-${randomUUID()}.txt`)
await fs.writeFile(filepath, output)
// Edit the file, once the editor is closed, the file will be saved and we
// can read the changes
spawnSync(editor, [...args, filepath], {
stdio: 'inherit',
})
let newOutput = await fs.readFile(filepath, 'utf8').then((x) => x.trim().split('\n'))
// Cleanup temporary file
await fs.unlink(filepath)
// Update the package.json files
for (let line of newOutput) {
if (line[0] === '#') continue // Skip comment lines
if (line.trim() === '') continue // Skip empty lines
let [name, version = ''] = line.split(':').map((x) => x.trim())
// Figure out all the paths to the package.json files that need to be
// updated with the new version
let paths = [
// The package.json file of the main workspace
workspaces.get(name).path,
// The package.json files of the workspaces that are in sync with the
// main workspace
...(syncedWorkspaces.get(name) ?? []),
]
for (let pkgPath of paths) {
let pkg = await fs.readFile(pkgPath, 'utf8').then(JSON.parse)
let name = pkg.name
if (version !== '') {
// Ensure the version is set after the name and before everything else
delete pkg.name
delete pkg.version
// This allows us to keep the order of the keys in the package.json
pkg = { name, version, ...pkg }
}
await fs.writeFile(
pkgPath,
await prettier
.format(JSON.stringify(pkg, null, 2), { filepath: pkgPath })
.then((x) => `${x.trim()}\n`),
)
}
}
}
console.log('Done.')
},
)