@grest-ts/cli 0.0.29 → 0.0.32
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/README.md +11 -21
- package/index.mjs +78 -14
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,31 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
# @grest-ts/cli
|
|
7
7
|
|
|
8
|
-
CLI for
|
|
9
|
-
|
|
10
|
-
## Why
|
|
11
|
-
|
|
12
|
-
grest-ts is single-version: every `@grest-ts/*` package in a project must be at the same version. Inter-package peer dependencies are pinned exactly, so bumping one package forces bumping all of them — and once a `package-lock.json` is in play, npm's resolver can't reconcile the cross-package pins through a partial update.
|
|
13
|
-
|
|
14
|
-
This CLI does the bump atomically.
|
|
8
|
+
CLI for keeping every `@grest-ts/*` package in your project on the same version. Full guide: [Guide → CLI](@guide/cli).
|
|
15
9
|
|
|
16
10
|
## Usage
|
|
17
11
|
|
|
18
|
-
Run from your project root (single-package or npm workspaces monorepo):
|
|
19
|
-
|
|
20
12
|
```bash
|
|
21
|
-
npx @grest-ts/cli
|
|
22
|
-
npx @grest-ts/cli
|
|
23
|
-
npx @grest-ts/cli
|
|
24
|
-
npx @grest-ts/cli
|
|
13
|
+
npx @grest-ts/cli update # bump to "latest"
|
|
14
|
+
npx @grest-ts/cli update 0.0.30 # bump to a specific version
|
|
15
|
+
npx @grest-ts/cli update next # bump to a dist-tag
|
|
16
|
+
npx @grest-ts/cli update --dry-run # preview only
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
##
|
|
19
|
+
## Install (optional)
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
6. Deletes `package-lock.json`.
|
|
35
|
-
7. Runs `npm install`.
|
|
21
|
+
`npx` works without installing anything. To pin a CLI version per-project:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -D @grest-ts/cli
|
|
25
|
+
```
|
package/index.mjs
CHANGED
|
@@ -5,9 +5,10 @@ import { join, resolve, dirname } from "path"
|
|
|
5
5
|
import { spawnSync } from "child_process"
|
|
6
6
|
|
|
7
7
|
const GREST_PREFIX = "@grest-ts/"
|
|
8
|
+
const DEP_BLOCKS = ["dependencies", "devDependencies", "peerDependencies"]
|
|
8
9
|
|
|
9
10
|
const COMMANDS = {
|
|
10
|
-
|
|
11
|
+
update: runUpdate,
|
|
11
12
|
help: runHelp,
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -36,16 +37,18 @@ Usage:
|
|
|
36
37
|
grest-ts <command> [options]
|
|
37
38
|
|
|
38
39
|
Commands:
|
|
39
|
-
|
|
40
|
-
Version can be a semver (e.g. 0.0.
|
|
41
|
-
(latest, next). Defaults to "latest".
|
|
40
|
+
update [version] Atomically update all @grest-ts/* deps to a single version.
|
|
41
|
+
Version can be a semver (e.g. 0.0.30) or a dist-tag
|
|
42
|
+
(latest, next). Defaults to "latest". Also walks the
|
|
43
|
+
published peer-dep graph and silently adds any missing
|
|
44
|
+
@grest-ts/* peers to your dependencies.
|
|
42
45
|
Flags:
|
|
43
46
|
--dry-run Show what would change without writing.
|
|
44
47
|
help Show this message.
|
|
45
48
|
`)
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
async function
|
|
51
|
+
async function runUpdate(args) {
|
|
49
52
|
const dryRun = args.includes("--dry-run") || args.includes("--dry")
|
|
50
53
|
const positional = args.filter(a => !a.startsWith("--"))
|
|
51
54
|
const versionArg = positional[0] || "latest"
|
|
@@ -65,7 +68,7 @@ async function runUpgrade(args) {
|
|
|
65
68
|
const grestDeps = new Set()
|
|
66
69
|
for (const p of allPkgPaths) {
|
|
67
70
|
const pkg = readJson(p)
|
|
68
|
-
for (const block of
|
|
71
|
+
for (const block of DEP_BLOCKS) {
|
|
69
72
|
if (!pkg[block]) continue
|
|
70
73
|
for (const key of Object.keys(pkg[block])) {
|
|
71
74
|
if (key.startsWith(GREST_PREFIX)) grestDeps.add(key)
|
|
@@ -79,10 +82,12 @@ async function runUpgrade(args) {
|
|
|
79
82
|
}
|
|
80
83
|
console.log(`Found ${grestDeps.size} unique @grest-ts/* dependency name(s).`)
|
|
81
84
|
|
|
82
|
-
// 3. Resolve target version (handle dist-tags)
|
|
85
|
+
// 3. Resolve target version (handle dist-tags). Pin exactly — grest-ts
|
|
86
|
+
// publishes all packages in lockstep with each other's peers declared
|
|
87
|
+
// at the exact version, so the consumer must match exactly.
|
|
83
88
|
const targetVersion = await resolveTargetVersion(versionArg)
|
|
84
|
-
const canonicalRange =
|
|
85
|
-
console.log(`Target version: ${targetVersion}
|
|
89
|
+
const canonicalRange = targetVersion
|
|
90
|
+
console.log(`Target version: ${targetVersion}`)
|
|
86
91
|
|
|
87
92
|
// 4. Pre-flight: every grest-ts package must be published at target version.
|
|
88
93
|
// grest-ts is single-version across all packages — partial publishes would
|
|
@@ -101,14 +106,66 @@ async function runUpgrade(args) {
|
|
|
101
106
|
)
|
|
102
107
|
}
|
|
103
108
|
|
|
104
|
-
// 5.
|
|
109
|
+
// 5. Walk the peer-dep graph at the target version and silently add any
|
|
110
|
+
// missing @grest-ts/* peers to the root project. Each grest-ts package
|
|
111
|
+
// declares its internal cross-deps as peerDependencies — when a consumer
|
|
112
|
+
// adds @grest-ts/http but forgets @grest-ts/schema, npm warns and the
|
|
113
|
+
// framework's runtime dedup check has nothing to dedup against. Better
|
|
114
|
+
// to fix it here.
|
|
115
|
+
console.log("Walking peer-dep graph to discover missing peers...")
|
|
116
|
+
const peerCache = new Map()
|
|
117
|
+
const expandedDeps = new Set(grestDeps)
|
|
118
|
+
const queue = [...grestDeps]
|
|
119
|
+
while (queue.length > 0) {
|
|
120
|
+
const name = queue.shift()
|
|
121
|
+
let manifest
|
|
122
|
+
try {
|
|
123
|
+
manifest = await fetchJson(`https://registry.npmjs.org/${name}/${targetVersion}`)
|
|
124
|
+
} catch (e) {
|
|
125
|
+
throw new Error(`Failed to fetch ${name}@${targetVersion} manifest: ${e.message}`)
|
|
126
|
+
}
|
|
127
|
+
const peers = manifest.peerDependencies || {}
|
|
128
|
+
peerCache.set(name, peers)
|
|
129
|
+
for (const peerName of Object.keys(peers)) {
|
|
130
|
+
if (peerName.startsWith(GREST_PREFIX) && !expandedDeps.has(peerName)) {
|
|
131
|
+
expandedDeps.add(peerName)
|
|
132
|
+
queue.push(peerName)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Anything in expandedDeps not already in the root package.json gets added
|
|
138
|
+
// to its dependencies block at the target version.
|
|
139
|
+
const autoAdded = []
|
|
140
|
+
for (const name of expandedDeps) {
|
|
141
|
+
if (!isInAnyBlock(rootPkg, name)) {
|
|
142
|
+
autoAdded.push(name)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (autoAdded.length > 0) {
|
|
146
|
+
console.log(`Adding ${autoAdded.length} missing peer(s) to ${relativeTo(cwd, rootPkgPath)}:`)
|
|
147
|
+
for (const name of autoAdded) console.log(` + ${name}`)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 6. Rewrite every package.json — normalize every @grest-ts/* range to canonical form.
|
|
151
|
+
// For the root, also insert any auto-discovered missing peers into "dependencies".
|
|
105
152
|
let totalChanged = 0
|
|
106
153
|
let filesChanged = 0
|
|
107
154
|
for (const p of allPkgPaths) {
|
|
108
155
|
const raw = readFileSync(p, "utf-8")
|
|
109
156
|
const pkg = JSON.parse(raw)
|
|
110
157
|
let fileChanged = false
|
|
111
|
-
|
|
158
|
+
|
|
159
|
+
if (p === rootPkgPath && autoAdded.length > 0) {
|
|
160
|
+
pkg.dependencies = pkg.dependencies || {}
|
|
161
|
+
for (const name of autoAdded) {
|
|
162
|
+
pkg.dependencies[name] = canonicalRange
|
|
163
|
+
}
|
|
164
|
+
fileChanged = true
|
|
165
|
+
totalChanged += autoAdded.length
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const block of DEP_BLOCKS) {
|
|
112
169
|
if (!pkg[block]) continue
|
|
113
170
|
for (const key of Object.keys(pkg[block])) {
|
|
114
171
|
if (!key.startsWith(GREST_PREFIX)) continue
|
|
@@ -138,7 +195,7 @@ async function runUpgrade(args) {
|
|
|
138
195
|
return
|
|
139
196
|
}
|
|
140
197
|
|
|
141
|
-
//
|
|
198
|
+
// 7. Clear lockfile + installed @grest-ts/* state.
|
|
142
199
|
// Three things hold npm to old grest-ts versions:
|
|
143
200
|
// - package-lock.json (the visible lockfile)
|
|
144
201
|
// - node_modules/.package-lock.json (npm's hidden install-state lockfile)
|
|
@@ -161,7 +218,7 @@ async function runUpgrade(args) {
|
|
|
161
218
|
rmSync(grestNodeModulesPath, { recursive: true, force: true })
|
|
162
219
|
}
|
|
163
220
|
|
|
164
|
-
//
|
|
221
|
+
// 8. Reinstall. Pass as a single shell command string — Node refuses to spawn
|
|
165
222
|
// .cmd files directly on Windows (CVE-2024-27980), and passing arg arrays
|
|
166
223
|
// with shell:true triggers DEP0190.
|
|
167
224
|
console.log("Running npm install...")
|
|
@@ -170,7 +227,7 @@ async function runUpgrade(args) {
|
|
|
170
227
|
throw new Error(`npm install exited with code ${result.status}`)
|
|
171
228
|
}
|
|
172
229
|
|
|
173
|
-
console.log(`\n✓
|
|
230
|
+
console.log(`\n✓ Updated all @grest-ts/* to ${canonicalRange}`)
|
|
174
231
|
}
|
|
175
232
|
|
|
176
233
|
// ---- helpers ----
|
|
@@ -179,6 +236,13 @@ function readJson(path) {
|
|
|
179
236
|
return JSON.parse(readFileSync(path, "utf-8"))
|
|
180
237
|
}
|
|
181
238
|
|
|
239
|
+
function isInAnyBlock(pkg, depName) {
|
|
240
|
+
for (const block of DEP_BLOCKS) {
|
|
241
|
+
if (pkg[block] && Object.hasOwn(pkg[block], depName)) return true
|
|
242
|
+
}
|
|
243
|
+
return false
|
|
244
|
+
}
|
|
245
|
+
|
|
182
246
|
function relativeTo(base, path) {
|
|
183
247
|
if (path.startsWith(base)) {
|
|
184
248
|
const rel = path.slice(base.length).replace(/^[\\/]+/, "")
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "THIS FILE IS GENERATED - DO NOT EDIT",
|
|
3
3
|
"name": "@grest-ts/cli",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.32",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"description": "CLI for managing grest-ts in a project (atomic version
|
|
7
|
+
"description": "CLI for managing grest-ts in a project (atomic version updates, etc.)",
|
|
8
8
|
"files": [
|
|
9
9
|
"index.mjs"
|
|
10
10
|
],
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"testing",
|
|
30
30
|
"grest-ts",
|
|
31
31
|
"cli",
|
|
32
|
-
"
|
|
32
|
+
"update",
|
|
33
33
|
"tooling"
|
|
34
34
|
],
|
|
35
35
|
"engines": {
|