bumpcheck 0.0.0-stage → 0.1.1
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/LICENSE +15 -0
- package/README.md +199 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +127 -0
- package/dist/cli.js.map +1 -0
- package/dist/git.d.ts +33 -0
- package/dist/git.js +94 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/npm/analyze.d.ts +18 -0
- package/dist/npm/analyze.js +190 -0
- package/dist/npm/analyze.js.map +1 -0
- package/dist/npm/diagnostics.d.ts +21 -0
- package/dist/npm/diagnostics.js +269 -0
- package/dist/npm/diagnostics.js.map +1 -0
- package/dist/npm/exports.d.ts +22 -0
- package/dist/npm/exports.js +101 -0
- package/dist/npm/exports.js.map +1 -0
- package/dist/npm/imports.d.ts +29 -0
- package/dist/npm/imports.js +215 -0
- package/dist/npm/imports.js.map +1 -0
- package/dist/npm/program.d.ts +32 -0
- package/dist/npm/program.js +187 -0
- package/dist/npm/program.js.map +1 -0
- package/dist/registry/provider.d.ts +50 -0
- package/dist/registry/provider.js +164 -0
- package/dist/registry/provider.js.map +1 -0
- package/dist/report/render.d.ts +5 -0
- package/dist/report/render.js +227 -0
- package/dist/report/render.js.map +1 -0
- package/dist/types.d.ts +99 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,3 +1,200 @@
|
|
|
1
|
-
#
|
|
1
|
+
# bumpcheck
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Prove whether a dependency bump breaks the code that imports it.
|
|
4
|
+
|
|
5
|
+
Dependabot or Renovate opens a pull request bumping `zod` from 3 to 4. bumpcheck
|
|
6
|
+
reads the type declarations of both versions and your source, then reports
|
|
7
|
+
three kinds of facts, each with a file and line:
|
|
8
|
+
|
|
9
|
+
- a symbol you import was removed,
|
|
10
|
+
- a call you make no longer typechecks against the new declarations,
|
|
11
|
+
- a symbol you import changed, and whether your uses still typecheck.
|
|
12
|
+
|
|
13
|
+
Anything it cannot prove is listed as "could not be checked". It never guesses
|
|
14
|
+
and it never says "safe".
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
$ bumpcheck zod 3.23.8 4.1.12 --repo ./my-app
|
|
18
|
+
|
|
19
|
+
zod 3.23.8 -> 4.1.12
|
|
20
|
+
You import 3 symbols from zod. 2 breaks in 2 symbols, 1 changed but still typechecks. Behavior not checked.
|
|
21
|
+
|
|
22
|
+
BREAKS
|
|
23
|
+
ZodError Property 'errors' does not exist on type 'ZodError<unknown>'.
|
|
24
|
+
src/schema.ts:15:25 (TS2339)
|
|
25
|
+
ZodTypeAny Property 'typeName' does not exist on type '$ZodTypeDef'.
|
|
26
|
+
src/schema.ts:21:22 (TS2339)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
In the common case the whole output is one line:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
You import 5 symbols from axios. None changed. Behavior not checked.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
npm install -g bumpcheck
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Requires Node 20 or newer and `npm` on your PATH. bumpcheck fetches both
|
|
42
|
+
versions of the bumped package into its own cache. Run it with the repo's
|
|
43
|
+
other dependencies installed: types from them, such as a tRPC wrapper around
|
|
44
|
+
react-query, are part of what can break. Without `node_modules` the report
|
|
45
|
+
says how many imports could not be resolved.
|
|
46
|
+
|
|
47
|
+
Each run analyzes one project root under that directory's `tsconfig.json`.
|
|
48
|
+
`--since` picks the right directory for each bumped `package.json`. Nested
|
|
49
|
+
packages that share a `package.json` but have their own `tsconfig.json` are
|
|
50
|
+
not yet discovered. A `tsconfig.json` that only lists `references`, as Vite
|
|
51
|
+
templates do, is followed: the referenced projects are analyzed as one program
|
|
52
|
+
with the first one's options, and the report says so.
|
|
53
|
+
|
|
54
|
+
## Use
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
bumpcheck <package> <from> <to> [--repo <dir>] [--format text|markdown|json]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Exit code is 1 when at least one break is found, 0 otherwise, 2 on error.
|
|
61
|
+
Pass `--no-fail` to always exit 0.
|
|
62
|
+
|
|
63
|
+
`--format markdown` produces a pull request comment. `--format json` emits the
|
|
64
|
+
full report, documented in [src/types.ts](src/types.ts), for other tools.
|
|
65
|
+
|
|
66
|
+
## In a pull request
|
|
67
|
+
|
|
68
|
+
`bumpcheck --since <ref>` finds every direct dependency whose version changed
|
|
69
|
+
between a git ref and HEAD, in any `package.json` in the repo, and checks each
|
|
70
|
+
one in its own directory. That makes the CI step one line, and it works for
|
|
71
|
+
repos with more than one project, such as an API at the root and a web app in
|
|
72
|
+
`web/`.
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
name: bumpcheck
|
|
76
|
+
on:
|
|
77
|
+
pull_request:
|
|
78
|
+
paths: ['**/package.json', '**/package-lock.json']
|
|
79
|
+
permissions:
|
|
80
|
+
contents: read
|
|
81
|
+
pull-requests: write
|
|
82
|
+
jobs:
|
|
83
|
+
check:
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/checkout@v4
|
|
87
|
+
with: { fetch-depth: 0 }
|
|
88
|
+
- uses: actions/setup-node@v4
|
|
89
|
+
with: { node-version: 22, cache: npm }
|
|
90
|
+
- run: npm ci --ignore-scripts
|
|
91
|
+
- name: bumpcheck
|
|
92
|
+
id: run
|
|
93
|
+
run: |
|
|
94
|
+
npx bumpcheck --since origin/${{ github.base_ref }} --format markdown --json-out report.json > comment.md \
|
|
95
|
+
|| echo "failed=1" >> "$GITHUB_OUTPUT"
|
|
96
|
+
unknown=$(node -p 'const r=[].concat(require("./report.json")); r.reduce((n,x)=>n+x.summary.unknown+x.summary.unanalyzed,0)' 2>/dev/null || echo 0)
|
|
97
|
+
if [ "$unknown" != "0" ]; then
|
|
98
|
+
echo "::warning title=bumpcheck::$unknown import(s) could not be checked; see the pull request comment"
|
|
99
|
+
fi
|
|
100
|
+
- uses: marocchino/sticky-pull-request-comment@v2
|
|
101
|
+
with:
|
|
102
|
+
header: bumpcheck
|
|
103
|
+
path: comment.md
|
|
104
|
+
- name: Fail on breaks
|
|
105
|
+
if: steps.run.outputs.failed == '1'
|
|
106
|
+
run: exit 1
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The job fails when any package reported a break, after the comment is
|
|
110
|
+
posted. Imports that could not be checked keep the job green and add a
|
|
111
|
+
warning annotation, so a green check means "no proven break", not "safe".
|
|
112
|
+
If more than one project needs `npm ci`, add a step per directory.
|
|
113
|
+
|
|
114
|
+
## How it works
|
|
115
|
+
|
|
116
|
+
1. Both versions are installed with `npm install --ignore-scripts` into a
|
|
117
|
+
per-version cache. When the package's own dependencies are also installed
|
|
118
|
+
in your repo at a version that satisfies its declared range, those copies
|
|
119
|
+
are used, as npm's dedupe would. Otherwise two copies of a shared type
|
|
120
|
+
such as `@nestjs/common` would disagree with each other.
|
|
121
|
+
2. Two TypeScript programs are built over your repo, identical except that
|
|
122
|
+
every import of the package resolves to one version or the other.
|
|
123
|
+
3. Every import of the package is collected: named, default, namespace
|
|
124
|
+
member access, `require()` destructuring, subpaths, and type-only imports.
|
|
125
|
+
4. Each imported symbol's declaration is tokenized and compared between
|
|
126
|
+
versions. Comments and formatting do not count.
|
|
127
|
+
5. Type errors are collected in the importing files for both programs. Errors
|
|
128
|
+
present only with the new version are the breaks. Your pre-existing errors
|
|
129
|
+
cancel out.
|
|
130
|
+
6. Each break is attributed to an imported symbol by the error message, the
|
|
131
|
+
import binding in the failing expression, or a type declared under that
|
|
132
|
+
import. The report says which.
|
|
133
|
+
|
|
134
|
+
If your repo has a `tsconfig.json`, its options are used, so a break is a
|
|
135
|
+
break under your own settings. Without one, bumpcheck uses strict defaults with
|
|
136
|
+
`checkJs` so plain JavaScript repos are analyzed too.
|
|
137
|
+
|
|
138
|
+
## What it does not do
|
|
139
|
+
|
|
140
|
+
- It does not check runtime behavior. A function with the same signature can
|
|
141
|
+
still behave differently. The footer of every report says so.
|
|
142
|
+
- It does not analyze packages that ship no type declarations. The report says
|
|
143
|
+
so instead of reporting zero breaks.
|
|
144
|
+
- It does not follow dynamic `import()`, `export * from`, or a namespace
|
|
145
|
+
passed around as a value. Those appear under "not analyzed".
|
|
146
|
+
- It does not fix anything, read changelogs, or decide whether to merge.
|
|
147
|
+
|
|
148
|
+
## Accuracy
|
|
149
|
+
|
|
150
|
+
[corpus/](corpus/) pins real Dependabot pull requests from public repos at
|
|
151
|
+
their base commit and runs bumpcheck on each bump. A `--oracle` mode then
|
|
152
|
+
installs the new version into the checkout and runs the repo's own `tsc`; the
|
|
153
|
+
new errors it reports are the ground truth.
|
|
154
|
+
|
|
155
|
+
Results so far, from [corpus/results.md](corpus/results.md). Four of the
|
|
156
|
+
pull requests needed a human to change code before merging, which tests the
|
|
157
|
+
case that matters: does the tool stay quiet when it should not?
|
|
158
|
+
|
|
159
|
+
| bump | bumpcheck | tsc oracle | what the human changed |
|
|
160
|
+
|---|---|---|---|
|
|
161
|
+
| zod 3.23.8 → 4.6.5, 36-file API merged without CI | 79 breaks | 84 new errors | nothing; the repo has not compiled since |
|
|
162
|
+
| zod 3.25.76 → 4.6.7, MCP server | 6 breaks | 6 new errors | the schema the 6 test errors pointed at |
|
|
163
|
+
| react-query 4 → 5, 20-hook app | 20 breaks | 28 new errors | 16 hunks, 13 of them at reported lines |
|
|
164
|
+
| react-query 4 → 5, Electron app | 3 breaks | 3 new errors | 1 of the 3 sites; the other 2 landed via a separate PR |
|
|
165
|
+
| msw 1 → 2, tests outside tsconfig | 0, with a note that 1 importing file is outside tsconfig | 0 | the test files tsc does not see |
|
|
166
|
+
| 6 bumps that needed no code changes | 0 breaks each | 0 new errors each | nothing |
|
|
167
|
+
|
|
168
|
+
Every gap between the two columns is TypeScript's "implicitly has an 'any'
|
|
169
|
+
type" follow-on errors, which bumpcheck folds into the root error on the
|
|
170
|
+
same statement. On root causes the lists match, file and line.
|
|
171
|
+
|
|
172
|
+
Two lessons from the corpus are now part of the tool: run with the repo's
|
|
173
|
+
dependencies installed, because types from other packages carry the bumped
|
|
174
|
+
package's types, and say so when files that import the package sit outside
|
|
175
|
+
the tsconfig.
|
|
176
|
+
|
|
177
|
+
Eleven cases is a start, not a statistic. Add one with a pull request URL and
|
|
178
|
+
a base commit in [corpus/cases.json](corpus/cases.json) and run
|
|
179
|
+
`npx tsx corpus/run.ts --oracle`.
|
|
180
|
+
|
|
181
|
+
## Status
|
|
182
|
+
|
|
183
|
+
Early. npm with TypeScript declarations is the only ecosystem. The report
|
|
184
|
+
schema is versioned and will stay backwards compatible within a major.
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
npm install
|
|
190
|
+
npm test
|
|
191
|
+
npm run dev -- zod 3.23.8 4.1.12 --repo ../some-app
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Tests run offline against fixture packages in `test/fixtures`. Add a case by
|
|
195
|
+
planting a change in `demo-lib-v2` and a use in `consumer`, then asserting the
|
|
196
|
+
exact file and line.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
Apache-2.0
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { analyzeNpm } from './npm/analyze.js';
|
|
6
|
+
import { detectChanges } from './git.js';
|
|
7
|
+
import { NpmProvider } from './registry/provider.js';
|
|
8
|
+
import { renderMarkdown, renderText } from './report/render.js';
|
|
9
|
+
const HELP = `bumpcheck — prove whether a dependency bump breaks the code that imports it
|
|
10
|
+
|
|
11
|
+
Usage
|
|
12
|
+
bumpcheck <package> <from> <to> [options]
|
|
13
|
+
bumpcheck --since <git-ref> [options]
|
|
14
|
+
|
|
15
|
+
The second form finds every direct dependency whose version changed in any
|
|
16
|
+
package.json between <git-ref> and HEAD, and checks each in its own
|
|
17
|
+
directory. This is the form for CI on a dependency pull request.
|
|
18
|
+
|
|
19
|
+
Options
|
|
20
|
+
--repo <dir> Repository to analyze (default: current directory)
|
|
21
|
+
--since <ref> Detect bumps from git instead of naming one
|
|
22
|
+
--format <fmt> text | markdown | json (default: text)
|
|
23
|
+
--json-out <file> Also write the full JSON report to a file
|
|
24
|
+
--cache-dir <dir> Where package versions are cached
|
|
25
|
+
--registry <url> npm registry (default: npm config / BUMPCHECK_REGISTRY)
|
|
26
|
+
--no-fail Exit 0 even when breaks are found
|
|
27
|
+
-h, --help Show this help
|
|
28
|
+
|
|
29
|
+
Exit codes
|
|
30
|
+
0 no breaks found
|
|
31
|
+
1 at least one break found
|
|
32
|
+
2 usage or analysis error
|
|
33
|
+
|
|
34
|
+
Example
|
|
35
|
+
bumpcheck axios 1.6.8 1.7.2 --repo ./my-app --format markdown
|
|
36
|
+
`;
|
|
37
|
+
async function main(argv) {
|
|
38
|
+
const { values, positionals } = parseArgs({
|
|
39
|
+
args: argv,
|
|
40
|
+
allowPositionals: true,
|
|
41
|
+
options: {
|
|
42
|
+
repo: { type: 'string' },
|
|
43
|
+
since: { type: 'string' },
|
|
44
|
+
format: { type: 'string', default: 'text' },
|
|
45
|
+
'json-out': { type: 'string' },
|
|
46
|
+
'cache-dir': { type: 'string' },
|
|
47
|
+
registry: { type: 'string' },
|
|
48
|
+
'no-fail': { type: 'boolean', default: false },
|
|
49
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
if (values.help || (values.since ? positionals.length !== 0 : positionals.length !== 3)) {
|
|
53
|
+
process.stdout.write(HELP);
|
|
54
|
+
return values.help ? 0 : 2;
|
|
55
|
+
}
|
|
56
|
+
const format = values.format;
|
|
57
|
+
if (format !== 'text' && format !== 'markdown' && format !== 'json') {
|
|
58
|
+
process.stderr.write(`Unknown format "${format}". Use text, markdown, or json.\n`);
|
|
59
|
+
return 2;
|
|
60
|
+
}
|
|
61
|
+
const providerOpts = {};
|
|
62
|
+
if (values['cache-dir'])
|
|
63
|
+
providerOpts.cacheDir = values['cache-dir'];
|
|
64
|
+
if (values.registry)
|
|
65
|
+
providerOpts.registry = values.registry;
|
|
66
|
+
const repoRoot = path.resolve(values.repo ?? process.cwd());
|
|
67
|
+
const provider = new NpmProvider(providerOpts);
|
|
68
|
+
const detection = values.since
|
|
69
|
+
? detectChanges(repoRoot, values.since)
|
|
70
|
+
: { bumps: [{ dir: '', pkg: positionals[0], from: positionals[1], to: positionals[2] }], transitive: [] };
|
|
71
|
+
const targets = detection.bumps;
|
|
72
|
+
if (targets.length === 0) {
|
|
73
|
+
process.stdout.write(renderNoBumps(values.since, detection, format) + '\n');
|
|
74
|
+
if (values['json-out'])
|
|
75
|
+
await writeFile(values['json-out'], JSON.stringify([], null, 2) + '\n');
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
const reports = [];
|
|
79
|
+
for (const t of targets) {
|
|
80
|
+
reports.push(await analyzeNpm({ repoRoot: path.join(repoRoot, t.dir), pkg: t.pkg, from: t.from, to: t.to, provider }));
|
|
81
|
+
}
|
|
82
|
+
const render = (r, i) => {
|
|
83
|
+
const dir = targets[i].dir;
|
|
84
|
+
const prefix = dir && format !== 'json' ? (format === 'markdown' ? `_in \`${dir}/\`_\n\n` : `in ${dir}/\n`) : '';
|
|
85
|
+
return prefix + (format === 'markdown' ? renderMarkdown(r) : renderText(r));
|
|
86
|
+
};
|
|
87
|
+
const body = format === 'json' ? JSON.stringify(reports.length === 1 ? reports[0] : reports, null, 2) : reports.map(render).join('\n\n');
|
|
88
|
+
process.stdout.write(body + '\n');
|
|
89
|
+
if (values['json-out']) {
|
|
90
|
+
await writeFile(values['json-out'], JSON.stringify(reports.length === 1 ? reports[0] : reports, null, 2) + '\n');
|
|
91
|
+
}
|
|
92
|
+
return reports.some((r) => r.breaks.length > 0) && !values['no-fail'] ? 1 : 0;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A lockfile-only pull request has nothing bumpcheck can check, since it
|
|
96
|
+
* only analyzes packages the repo imports directly. Say what moved anyway,
|
|
97
|
+
* so the comment explains itself.
|
|
98
|
+
*/
|
|
99
|
+
function renderNoBumps(since, detection, format) {
|
|
100
|
+
const md = format === 'markdown';
|
|
101
|
+
const lines = [];
|
|
102
|
+
lines.push(md ? `### bumpcheck` : 'bumpcheck');
|
|
103
|
+
lines.push('');
|
|
104
|
+
lines.push(`No direct dependency changed since ${since}, so there is nothing to typecheck against.`);
|
|
105
|
+
if (detection.transitive.length > 0) {
|
|
106
|
+
const n = detection.transitive.length;
|
|
107
|
+
lines.push('');
|
|
108
|
+
lines.push(`${n} transitive package${n === 1 ? '' : 's'} moved in the lockfile:`);
|
|
109
|
+
lines.push('');
|
|
110
|
+
for (const t of detection.transitive.slice(0, 20)) {
|
|
111
|
+
const where = t.dir ? ` (in ${t.dir}/)` : '';
|
|
112
|
+
lines.push(md ? `- \`${t.pkg}\` ${t.from} → ${t.to}${where}` : ` ${t.pkg} ${t.from} -> ${t.to}${where}`);
|
|
113
|
+
}
|
|
114
|
+
if (n > 20)
|
|
115
|
+
lines.push(md ? `- … ${n - 20} more` : ` … ${n - 20} more`);
|
|
116
|
+
lines.push('');
|
|
117
|
+
lines.push(md
|
|
118
|
+
? '<sub>bumpcheck checks packages this repo imports directly. Transitive changes are listed for the record and are not analyzed.</sub>'
|
|
119
|
+
: 'bumpcheck checks packages this repo imports directly. Transitive changes are listed for the record and are not analyzed.');
|
|
120
|
+
}
|
|
121
|
+
return lines.join('\n');
|
|
122
|
+
}
|
|
123
|
+
main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
|
|
124
|
+
process.stderr.write(`bumpcheck: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
125
|
+
process.exit(2);
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BZ,CAAC;AAEF,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI;QACV,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;YAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;YAC9C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;SACtD;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACxF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACpE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,MAAM,mCAAmC,CAAC,CAAC;QACnF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,YAAY,GAA6C,EAAE,CAAC;IAClE,IAAI,MAAM,CAAC,WAAW,CAAC;QAAE,YAAY,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACrE,IAAI,MAAM,CAAC,QAAQ;QAAE,YAAY,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAE7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,YAAY,CAAC,CAAC;IAE/C,MAAM,SAAS,GAAc,MAAM,CAAC,KAAK;QACvC,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC;QACvC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAE,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC/G,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;IAEhC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAM,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7E,IAAI,MAAM,CAAC,UAAU,CAAC;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAChG,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACzH,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;QAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC;QAC5B,MAAM,MAAM,GAAG,GAAG,IAAI,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjH,OAAO,MAAM,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAClC,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACvB,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACnH,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa,EAAE,SAAoB,EAAE,MAAc;IACxE,MAAM,EAAE,GAAG,MAAM,KAAK,UAAU,CAAC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sCAAsC,KAAK,6CAA6C,CAAC,CAAC;IACrG,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,yBAAyB,CAAC,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAC5G,CAAC;QACD,IAAI,CAAC,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,EAAE;YACA,CAAC,CAAC,qIAAqI;YACvI,CAAC,CAAC,0HAA0H,CAC/H,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC9B,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,GAAY,EAAE,EAAE;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** A direct dependency whose pinned version changed between two git refs. */
|
|
2
|
+
export interface DetectedBump {
|
|
3
|
+
/** Directory of the package.json, relative to the repo root, '' for the root. */
|
|
4
|
+
dir: string;
|
|
5
|
+
pkg: string;
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
}
|
|
9
|
+
/** A lockfile entry that moved without being a direct dependency. */
|
|
10
|
+
export interface TransitiveChange {
|
|
11
|
+
dir: string;
|
|
12
|
+
pkg: string;
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Detection {
|
|
17
|
+
bumps: DetectedBump[];
|
|
18
|
+
transitive: TransitiveChange[];
|
|
19
|
+
}
|
|
20
|
+
/** `^1.2.3`, `~1.2.3`, `1.2.3` -> `1.2.3`; ranges and tags -> undefined. */
|
|
21
|
+
export declare function exactVersion(spec: string | undefined): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Finds direct dependencies whose version changed between `base` and `head`
|
|
24
|
+
* in any package.json, using the lockfile beside it when present so range
|
|
25
|
+
* specs like `^1.2.0` resolve to the versions actually installed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function detectBumps(repoRoot: string, base: string, head?: string): DetectedBump[];
|
|
28
|
+
/**
|
|
29
|
+
* Direct bumps plus transitive lockfile moves. bumpcheck can only analyze
|
|
30
|
+
* what the repo imports directly, so the transitive list exists to explain
|
|
31
|
+
* a lockfile-only pull request rather than to be checked.
|
|
32
|
+
*/
|
|
33
|
+
export declare function detectChanges(repoRoot: string, base: string, head?: string): Detection;
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const DEP_FIELDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
|
|
4
|
+
function git(repo, args) {
|
|
5
|
+
const r = spawnSync('git', args, { cwd: repo, encoding: 'utf8' });
|
|
6
|
+
return r.status === 0 ? r.stdout : undefined;
|
|
7
|
+
}
|
|
8
|
+
function readJson(text) {
|
|
9
|
+
if (!text)
|
|
10
|
+
return undefined;
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(text);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** `^1.2.3`, `~1.2.3`, `1.2.3` -> `1.2.3`; ranges and tags -> undefined. */
|
|
19
|
+
export function exactVersion(spec) {
|
|
20
|
+
if (!spec)
|
|
21
|
+
return undefined;
|
|
22
|
+
const m = /^[\^~]?v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/.exec(spec.trim());
|
|
23
|
+
return m ? m[1] : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Finds direct dependencies whose version changed between `base` and `head`
|
|
27
|
+
* in any package.json, using the lockfile beside it when present so range
|
|
28
|
+
* specs like `^1.2.0` resolve to the versions actually installed.
|
|
29
|
+
*/
|
|
30
|
+
export function detectBumps(repoRoot, base, head = 'HEAD') {
|
|
31
|
+
return detectChanges(repoRoot, base, head).bumps;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Direct bumps plus transitive lockfile moves. bumpcheck can only analyze
|
|
35
|
+
* what the repo imports directly, so the transitive list exists to explain
|
|
36
|
+
* a lockfile-only pull request rather than to be checked.
|
|
37
|
+
*/
|
|
38
|
+
export function detectChanges(repoRoot, base, head = 'HEAD') {
|
|
39
|
+
const changed = git(repoRoot, ['diff', '--name-only', base, head, '--', '*package.json', '*package-lock.json'])
|
|
40
|
+
?.split('\n')
|
|
41
|
+
.map((l) => l.trim())
|
|
42
|
+
.filter((l) => l && !l.includes('node_modules/'));
|
|
43
|
+
if (!changed)
|
|
44
|
+
throw new Error(`git diff ${base} ${head} failed; is ${base} fetched?`);
|
|
45
|
+
const dirs = new Set(changed.map((f) => path.posix.dirname(f)).map((d) => (d === '.' ? '' : d)));
|
|
46
|
+
const bumps = [];
|
|
47
|
+
const transitive = [];
|
|
48
|
+
for (const dir of [...dirs].sort()) {
|
|
49
|
+
const manifestPath = dir ? `${dir}/package.json` : 'package.json';
|
|
50
|
+
const lockPath = dir ? `${dir}/package-lock.json` : 'package-lock.json';
|
|
51
|
+
const before = readJson(git(repoRoot, ['show', `${base}:${manifestPath}`]));
|
|
52
|
+
const after = readJson(git(repoRoot, ['show', `${head}:${manifestPath}`]));
|
|
53
|
+
if (!before || !after)
|
|
54
|
+
continue;
|
|
55
|
+
const lockBefore = readJson(git(repoRoot, ['show', `${base}:${lockPath}`]));
|
|
56
|
+
const lockAfter = readJson(git(repoRoot, ['show', `${head}:${lockPath}`]));
|
|
57
|
+
const resolve = (name, spec, lock) => lock?.packages?.[`node_modules/${name}`]?.version ?? exactVersion(spec);
|
|
58
|
+
const names = new Set();
|
|
59
|
+
for (const field of DEP_FIELDS) {
|
|
60
|
+
for (const n of Object.keys(before[field] ?? {}))
|
|
61
|
+
names.add(n);
|
|
62
|
+
for (const n of Object.keys(after[field] ?? {}))
|
|
63
|
+
names.add(n);
|
|
64
|
+
}
|
|
65
|
+
for (const name of [...names].sort()) {
|
|
66
|
+
const specBefore = DEP_FIELDS.map((f) => before[f]?.[name]).find(Boolean);
|
|
67
|
+
const specAfter = DEP_FIELDS.map((f) => after[f]?.[name]).find(Boolean);
|
|
68
|
+
if (!specBefore || !specAfter)
|
|
69
|
+
continue; // added or removed, not bumped
|
|
70
|
+
const from = resolve(name, specBefore, lockBefore);
|
|
71
|
+
const to = resolve(name, specAfter, lockAfter);
|
|
72
|
+
if (!from || !to || from === to)
|
|
73
|
+
continue;
|
|
74
|
+
bumps.push({ dir, pkg: name, from, to });
|
|
75
|
+
}
|
|
76
|
+
// Top-level lockfile entries that moved but are not direct dependencies.
|
|
77
|
+
const direct = new Set(names);
|
|
78
|
+
const pkgsBefore = lockBefore?.packages ?? {};
|
|
79
|
+
const pkgsAfter = lockAfter?.packages ?? {};
|
|
80
|
+
for (const key of Object.keys(pkgsAfter).sort()) {
|
|
81
|
+
if (!key.startsWith('node_modules/') || key.indexOf('node_modules/', 'node_modules/'.length) !== -1)
|
|
82
|
+
continue;
|
|
83
|
+
const name = key.slice('node_modules/'.length);
|
|
84
|
+
if (direct.has(name))
|
|
85
|
+
continue;
|
|
86
|
+
const from = pkgsBefore[key]?.version;
|
|
87
|
+
const to = pkgsAfter[key]?.version;
|
|
88
|
+
if (from && to && from !== to)
|
|
89
|
+
transitive.push({ dir, pkg: name, from, to });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { bumps, transitive };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { analyzeNpm, type AnalyzeOptions } from './npm/analyze.js';
|
|
2
|
+
export { NpmProvider, LocalProvider, type PackageProvider, type NpmProviderOptions } from './registry/provider.js';
|
|
3
|
+
export { renderText, renderMarkdown } from './report/render.js';
|
|
4
|
+
export * from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAiD,MAAM,wBAAwB,CAAC;AACnH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChE,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Report } from '../types.js';
|
|
2
|
+
import type { PackageProvider } from '../registry/provider.js';
|
|
3
|
+
export interface AnalyzeOptions {
|
|
4
|
+
repoRoot: string;
|
|
5
|
+
pkg: string;
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
provider: PackageProvider;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The whole pipeline:
|
|
12
|
+
* 1. materialize both versions,
|
|
13
|
+
* 2. build one program per version with imports redirected,
|
|
14
|
+
* 3. collect what the repo imports,
|
|
15
|
+
* 4. compare each imported symbol's declaration,
|
|
16
|
+
* 5. diff the type errors; new-only errors are the breaks.
|
|
17
|
+
*/
|
|
18
|
+
export declare function analyzeNpm(opts: AnalyzeOptions): Promise<Report>;
|