breakage 0.8.5 → 0.9.0
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 +163 -47
- package/dist/{breakage-B7dJsgcu.js → breakage-DIY49fzP.js} +331 -217
- package/dist/breakage-DIY49fzP.js.map +1 -0
- package/dist/breakage.d.ts +111 -55
- package/dist/breakage.d.ts.map +1 -1
- package/dist/breakage.js +3 -1
- package/dist/breakage.x.js +78 -80
- package/dist/breakage.x.js.map +1 -1
- package/dist/changesets.d.ts +8 -0
- package/dist/changesets.d.ts.map +1 -0
- package/dist/changesets.js +27 -0
- package/dist/changesets.js.map +1 -0
- package/dist/release-BsdIDT4g.js +69 -0
- package/dist/release-BsdIDT4g.js.map +1 -0
- package/dist/release-D47BqRuB.d.ts +40 -0
- package/dist/release-D47BqRuB.d.ts.map +1 -0
- package/npm.md +55 -33
- package/package.json +45 -6
- package/src/breakage.ts +125 -73
- package/src/breakage.x.ts +148 -127
- package/src/changesets.ts +51 -0
- package/src/config.ts +128 -0
- package/src/npm/check.ts +51 -50
- package/src/npm/cli.ts +26 -22
- package/src/npm/config.ts +38 -6
- package/src/npm/environment.ts +10 -10
- package/src/npm/release.ts +9 -25
- package/src/npm/types.ts +5 -45
- package/src/release.ts +153 -0
- package/src/{npm/command.ts → task.ts} +2 -0
- package/dist/breakage-B7dJsgcu.js.map +0 -1
- package/dist/breakage.$configPath.schema.json +0 -33
- package/dist/breakage.help.schema.json +0 -6
- package/dist/breakage.main.schema.json +0 -33
- package/dist/breakage.npm.check.schema.json +0 -16
- package/dist/breakage.npm.help.schema.json +0 -6
- package/dist/breakage.npm.schema.json +0 -6
- package/dist/breakage.npm.test.$peer.$range.schema.json +0 -16
- package/dist/breakage.npm.test.schema.json +0 -16
- package/dist/breakage.prelude.$configPath.schema.json +0 -31
- package/dist/breakage.prelude.schema.json +0 -31
- package/dist/breakage.schema.schema.json +0 -10
package/dist/breakage.x.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as configFields, c as configSchema, d as loadConfig, f as resolveConfig, h as errorMessage, i as npmTest, l as defaultConfig, m as breakagePrelude, n as formatNpmReport, o as configOptions, p as validateConfig, r as npmCheck, s as configPath, t as breakage } from "./breakage-DIY49fzP.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import logger from "takua";
|
|
5
|
-
import { readFile } from "node:fs/promises";
|
|
6
|
-
import { inspect } from "node:util";
|
|
7
5
|
import { type } from "arktype";
|
|
8
6
|
import { cli, completionResponse, encapsulate, help, logWarnings, noOptions, optional, options, parseBooleanOption, required } from "comline";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
//#region src/npm/cli.ts
|
|
7
|
+
import { inspect } from "node:util";
|
|
8
|
+
// src/npm/cli.ts
|
|
12
9
|
const common = {
|
|
10
|
+
release: configOptions.optionConfigs.release,
|
|
11
|
+
npm: configOptions.optionConfigs.npm,
|
|
13
12
|
config: {
|
|
13
|
+
schema: type(`string`),
|
|
14
14
|
required: false,
|
|
15
|
-
description: `Configuration file (defaults to breakage.config.ts
|
|
15
|
+
description: `Configuration file (defaults to breakage.config.ts).`,
|
|
16
16
|
example: `--config ./breakage.config.ts`,
|
|
17
17
|
completion: {
|
|
18
18
|
fileSystem: `files`,
|
|
@@ -20,6 +20,7 @@ const common = {
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
json: {
|
|
23
|
+
schema: type(`boolean`),
|
|
23
24
|
required: false,
|
|
24
25
|
description: `Emit the structured result.`,
|
|
25
26
|
example: `--json`,
|
|
@@ -29,10 +30,13 @@ const common = {
|
|
|
29
30
|
const npmCheckManual = options(`Check npm peer compatibility and changes in declared support.`, type({
|
|
30
31
|
"config?": `string`,
|
|
31
32
|
"json?": `boolean`,
|
|
32
|
-
"coverageOnly?": `boolean
|
|
33
|
+
"coverageOnly?": `boolean`,
|
|
34
|
+
"release?": configOptions.optionsSchema.get(`release`),
|
|
35
|
+
"npm?": configOptions.optionsSchema.get(`npm`)
|
|
33
36
|
}), {
|
|
34
37
|
...common,
|
|
35
38
|
coverageOnly: {
|
|
39
|
+
schema: type(`boolean`),
|
|
36
40
|
aliases: [`coverage-only`],
|
|
37
41
|
required: false,
|
|
38
42
|
description: `Audit coverage and support changes without executing assertions.`,
|
|
@@ -43,10 +47,13 @@ const npmCheckManual = options(`Check npm peer compatibility and changes in decl
|
|
|
43
47
|
const npmTestManual = options(`Run current contracts in matching complete peer environments.`, type({
|
|
44
48
|
"config?": `string`,
|
|
45
49
|
"json?": `boolean`,
|
|
46
|
-
"representative?": `string
|
|
50
|
+
"representative?": `string`,
|
|
51
|
+
"release?": configOptions.optionsSchema.get(`release`),
|
|
52
|
+
"npm?": configOptions.optionsSchema.get(`npm`)
|
|
47
53
|
}), {
|
|
48
54
|
...common,
|
|
49
55
|
representative: {
|
|
56
|
+
schema: type(`string`),
|
|
50
57
|
required: false,
|
|
51
58
|
description: `Select an exact configured representative path relative to the package.`,
|
|
52
59
|
example: `--representative peer-environments/react-19`,
|
|
@@ -56,14 +63,10 @@ const npmTestManual = options(`Run current contracts in matching complete peer e
|
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
});
|
|
59
|
-
function defaultConfig(directory) {
|
|
60
|
-
return path.join(directory, existsSync(path.join(directory, `breakage.config.ts`)) ? `breakage.config.ts` : `breakage.config.json`);
|
|
61
|
-
}
|
|
62
66
|
async function runNpmCli(action, opts, peerSelection) {
|
|
63
67
|
try {
|
|
64
68
|
const filename = path.resolve(opts.config ?? defaultConfig(process.cwd()));
|
|
65
|
-
const
|
|
66
|
-
const config = record(loaded) ? loaded.npm : void 0;
|
|
69
|
+
const config = (await loadConfig(filename)).npm;
|
|
67
70
|
validateConfig(config);
|
|
68
71
|
let selection;
|
|
69
72
|
if (action === `test`) {
|
|
@@ -87,18 +90,14 @@ async function runNpmCli(action, opts, peerSelection) {
|
|
|
87
90
|
return 2;
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
testCommand: `string`,
|
|
97
|
-
certifyCommand: `string`,
|
|
98
|
-
"baseDirname?": `string`,
|
|
99
|
-
"verbose?": `boolean`
|
|
100
|
-
}), {
|
|
93
|
+
// src/breakage.x.ts
|
|
94
|
+
const commandOverrides = /* @__PURE__ */ new Set();
|
|
95
|
+
const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, configSchema, {
|
|
96
|
+
release: { configOnly: true },
|
|
97
|
+
npm: { configOnly: true },
|
|
98
|
+
out: { configOnly: true },
|
|
101
99
|
tagPattern: {
|
|
100
|
+
schema: configFields.tagPattern,
|
|
102
101
|
aliases: [`tag-pattern`],
|
|
103
102
|
completion: { repeatable: false },
|
|
104
103
|
flag: `g`,
|
|
@@ -107,6 +106,7 @@ const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, type
|
|
|
107
106
|
example: `--tagPattern="my-library"`
|
|
108
107
|
},
|
|
109
108
|
baselineFile: {
|
|
109
|
+
schema: configFields.baselineFile,
|
|
110
110
|
aliases: [`baseline-file`],
|
|
111
111
|
completion: {
|
|
112
112
|
repeatable: false,
|
|
@@ -117,30 +117,41 @@ const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, type
|
|
|
117
117
|
example: `--baseline-file=.breakage/baseline.json`
|
|
118
118
|
},
|
|
119
119
|
testPattern: {
|
|
120
|
+
schema: configFields.testPattern,
|
|
120
121
|
aliases: [`test-pattern`, `pattern`],
|
|
121
122
|
completion: { repeatable: false },
|
|
122
123
|
flag: `p`,
|
|
123
|
-
required:
|
|
124
|
+
required: false,
|
|
124
125
|
description: `The pattern to match test files that test the public API of the library.`,
|
|
125
126
|
example: `--pattern="*__public.test.ts"`
|
|
126
127
|
},
|
|
127
128
|
testCommand: {
|
|
129
|
+
parse: (value) => {
|
|
130
|
+
commandOverrides.add(`testCommand`);
|
|
131
|
+
return value;
|
|
132
|
+
},
|
|
133
|
+
schema: configFields.testCommand,
|
|
128
134
|
aliases: [`test-command`],
|
|
129
135
|
completion: { repeatable: false },
|
|
130
136
|
flag: `t`,
|
|
131
|
-
required:
|
|
137
|
+
required: false,
|
|
132
138
|
description: `Complete bash command that runs the tests for the library's public API.`,
|
|
133
139
|
example: `--testCommand="npm run test"`
|
|
134
140
|
},
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
test: {
|
|
142
|
+
parse: (value) => {
|
|
143
|
+
commandOverrides.add(`test`);
|
|
144
|
+
return value;
|
|
145
|
+
},
|
|
146
|
+
schema: configFields.test,
|
|
137
147
|
completion: { repeatable: false },
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
example: `--certifyCommand=\tsx scripts/certify-major-version-bump.node`
|
|
148
|
+
required: false,
|
|
149
|
+
description: `Shell command running the restored public contracts.`,
|
|
150
|
+
example: `--test="npm run test:public"`
|
|
142
151
|
},
|
|
143
152
|
baseDirname: {
|
|
153
|
+
parse: (value) => path.resolve(value),
|
|
154
|
+
schema: configFields.baseDirname,
|
|
144
155
|
aliases: [`base-dir`, `base-dirname`],
|
|
145
156
|
completion: {
|
|
146
157
|
repeatable: false,
|
|
@@ -152,6 +163,7 @@ const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, type
|
|
|
152
163
|
example: `--baseDirname=./packages/my-package`
|
|
153
164
|
},
|
|
154
165
|
verbose: {
|
|
166
|
+
schema: configFields.verbose,
|
|
155
167
|
completion: { repeatable: false },
|
|
156
168
|
flag: `v`,
|
|
157
169
|
required: false,
|
|
@@ -160,16 +172,7 @@ const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, type
|
|
|
160
172
|
parse: parseBooleanOption
|
|
161
173
|
}
|
|
162
174
|
});
|
|
163
|
-
const PRELUDE_MANUAL = options(`Resolve and fetch the release baseline for a cacheable compatibility check.`,
|
|
164
|
-
"tagPattern?": `string`,
|
|
165
|
-
"baseDirname?": `string`,
|
|
166
|
-
"out?": `string`,
|
|
167
|
-
"testPattern?": `string`,
|
|
168
|
-
"testCommand?": `string`,
|
|
169
|
-
"certifyCommand?": `string`,
|
|
170
|
-
"baselineFile?": `string`,
|
|
171
|
-
"verbose?": `boolean`
|
|
172
|
-
}), {
|
|
175
|
+
const PRELUDE_MANUAL = options(`Resolve and fetch the release baseline for a cacheable compatibility check.`, configSchema, {
|
|
173
176
|
...BREAKAGE_MANUAL.optionConfigs,
|
|
174
177
|
testPattern: {
|
|
175
178
|
...BREAKAGE_MANUAL.optionConfigs.testPattern,
|
|
@@ -179,11 +182,8 @@ const PRELUDE_MANUAL = options(`Resolve and fetch the release baseline for a cac
|
|
|
179
182
|
...BREAKAGE_MANUAL.optionConfigs.testCommand,
|
|
180
183
|
required: false
|
|
181
184
|
},
|
|
182
|
-
certifyCommand: {
|
|
183
|
-
...BREAKAGE_MANUAL.optionConfigs.certifyCommand,
|
|
184
|
-
required: false
|
|
185
|
-
},
|
|
186
185
|
out: {
|
|
186
|
+
schema: configFields.out,
|
|
187
187
|
completion: {
|
|
188
188
|
repeatable: false,
|
|
189
189
|
fileSystem: `files`
|
|
@@ -193,22 +193,17 @@ const PRELUDE_MANUAL = options(`Resolve and fetch the release baseline for a cac
|
|
|
193
193
|
example: `--out=.breakage/baseline.json`
|
|
194
194
|
}
|
|
195
195
|
});
|
|
196
|
-
|
|
197
|
-
aliases: [`out-dir`],
|
|
198
|
-
completion: {
|
|
199
|
-
repeatable: false,
|
|
200
|
-
fileSystem: `directories`
|
|
201
|
-
},
|
|
202
|
-
flag: `o`,
|
|
203
|
-
required: false,
|
|
204
|
-
description: `Directory to write the schema to.`,
|
|
205
|
-
example: `--outdir=./dist`
|
|
206
|
-
} });
|
|
196
|
+
let loadedConfigPath;
|
|
207
197
|
const parse = cli({
|
|
208
198
|
cliName: `breakage`,
|
|
199
|
+
discoverConfigPath: (segments) => {
|
|
200
|
+
if (segments[0] === `help` || segments[0] === `npm`) return void 0;
|
|
201
|
+
const explicit = segments[0] === `prelude` ? segments[1] : segments[0];
|
|
202
|
+
loadedConfigPath = configPath(explicit ?? defaultConfig(process.cwd()), explicit !== void 0);
|
|
203
|
+
return loadedConfigPath;
|
|
204
|
+
},
|
|
209
205
|
routes: optional({
|
|
210
206
|
help: null,
|
|
211
|
-
schema: null,
|
|
212
207
|
npm: optional({
|
|
213
208
|
help: null,
|
|
214
209
|
check: null,
|
|
@@ -221,7 +216,6 @@ const parse = cli({
|
|
|
221
216
|
"": BREAKAGE_MANUAL,
|
|
222
217
|
$configPath: BREAKAGE_MANUAL,
|
|
223
218
|
help: noOptions(`Show usage.`),
|
|
224
|
-
schema: SCHEMA_MANUAL,
|
|
225
219
|
npm: noOptions(`Show npm compatibility commands.`),
|
|
226
220
|
"npm/help": noOptions(`Show npm compatibility commands.`),
|
|
227
221
|
"npm/check": npmCheckManual,
|
|
@@ -233,10 +227,6 @@ const parse = cli({
|
|
|
233
227
|
positionalCompletions: {
|
|
234
228
|
$configPath: { fileSystem: `files` },
|
|
235
229
|
"prelude/$configPath": { fileSystem: `files` }
|
|
236
|
-
},
|
|
237
|
-
discoverConfigPath: (args) => {
|
|
238
|
-
if (args[0] === `help` || args[0] === `schema` || args[0] === `npm`) return;
|
|
239
|
-
return (args[0] === `prelude` ? args[1] : args[0]) ?? defaultConfig(process.cwd());
|
|
240
230
|
}
|
|
241
231
|
}, {
|
|
242
232
|
info: (message, ...data) => logger.info(`breakage`, message, data),
|
|
@@ -244,9 +234,10 @@ const parse = cli({
|
|
|
244
234
|
});
|
|
245
235
|
const completion = await completionResponse(parse.definition, process.argv);
|
|
246
236
|
if (completion !== void 0) process.stdout.write(completion);
|
|
247
|
-
else {
|
|
248
|
-
const { inputs, warnings
|
|
237
|
+
else try {
|
|
238
|
+
const { inputs, warnings } = await parse.async(process.argv);
|
|
249
239
|
logWarnings(warnings);
|
|
240
|
+
if (process.argv.slice(2).some((arg) => /^(?:--certifyCommand|--certify-command|-c)(?:=|$)/.test(arg))) throw new Error(`certifyCommand was removed. Configure release.resolveDelta and release.policy instead.`);
|
|
250
241
|
switch (inputs.case) {
|
|
251
242
|
case `npm`:
|
|
252
243
|
case `npm/help`:
|
|
@@ -262,36 +253,41 @@ else {
|
|
|
262
253
|
case `npm/test/$peer/$range`:
|
|
263
254
|
process.exitCode = await runNpmCli(`test`, inputs.opts, inputs.params);
|
|
264
255
|
break;
|
|
265
|
-
case `schema`:
|
|
266
|
-
{
|
|
267
|
-
const { outdir } = inputs.opts;
|
|
268
|
-
writeJsonSchema(outdir ?? `.`);
|
|
269
|
-
process.stdout.write(`📝 Wrote json.schema.`);
|
|
270
|
-
}
|
|
271
|
-
break;
|
|
272
256
|
case `prelude`:
|
|
273
257
|
case `prelude/$configPath`: {
|
|
258
|
+
const config = resolveConfig(inputs.opts, loadedConfigPath);
|
|
274
259
|
const baseline = await breakagePrelude({
|
|
275
|
-
...
|
|
276
|
-
out:
|
|
260
|
+
...config,
|
|
261
|
+
out: config.out ?? `.breakage/baseline.json`
|
|
277
262
|
});
|
|
278
263
|
process.stdout.write(`Pinned ${baseline.ref} at ${baseline.commit}.\n`);
|
|
279
264
|
break;
|
|
280
265
|
}
|
|
281
266
|
case ``:
|
|
282
267
|
case `$configPath`: {
|
|
283
|
-
const
|
|
268
|
+
const merged = resolveConfig(inputs.opts, loadedConfigPath);
|
|
269
|
+
if (commandOverrides.has(`testCommand`) && !commandOverrides.has(`test`)) delete merged.test;
|
|
270
|
+
if (commandOverrides.has(`test`) && !commandOverrides.has(`testCommand`)) delete merged.testCommand;
|
|
271
|
+
if (!merged.testPattern) throw new Error(`required arguments were not provided: testPattern.`);
|
|
272
|
+
const { returnValue } = await encapsulate(() => breakage({
|
|
273
|
+
...merged,
|
|
274
|
+
testPattern: merged.testPattern
|
|
275
|
+
}), {
|
|
284
276
|
console: true,
|
|
285
277
|
stdout: true
|
|
286
278
|
});
|
|
279
|
+
if (`release` in returnValue && returnValue.release) {
|
|
280
|
+
const { previousVersion, version, delta, breaking } = returnValue.release;
|
|
281
|
+
process.stdout.write(`Release: ${previousVersion} → ${version} (${delta}; ${breaking ? `breaking` : `compatible`}).\n`);
|
|
282
|
+
}
|
|
287
283
|
if (`testResult` in returnValue && returnValue.breakingChangesFound) process.stdout.write(returnValue.testResult);
|
|
288
284
|
if (`breakingChangesFound` in returnValue) {
|
|
289
285
|
if (returnValue.breakingChangesFound) {
|
|
290
|
-
if (returnValue.
|
|
291
|
-
process.stdout.write(`👷 Breaking changes
|
|
286
|
+
if (returnValue.release?.breaking) {
|
|
287
|
+
process.stdout.write(`👷 Breaking changes are covered by the breaking release.`);
|
|
292
288
|
process.exit(0);
|
|
293
289
|
} else {
|
|
294
|
-
process.stdout.write(`❌ Breaking changes
|
|
290
|
+
process.stdout.write(`❌ Breaking changes require a breaking release.`);
|
|
295
291
|
process.exit(1);
|
|
296
292
|
}
|
|
297
293
|
} else {
|
|
@@ -304,8 +300,10 @@ else {
|
|
|
304
300
|
}
|
|
305
301
|
}
|
|
306
302
|
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
process.stderr.write(`Breakage setup error: ${errorMessage(error)}\n`);
|
|
305
|
+
process.exitCode = 2;
|
|
307
306
|
}
|
|
308
|
-
//#endregion
|
|
309
307
|
export {};
|
|
310
308
|
|
|
311
309
|
//# sourceMappingURL=breakage.x.js.map
|
package/dist/breakage.x.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breakage.x.js","names":[],"sources":["../src/npm/cli.ts","../src/breakage.x.ts"],"sourcesContent":["import { existsSync } from \"node:fs\"\nimport { readFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\n\nimport { type } from \"arktype\"\nimport type { OptionsGroup } from \"comline\"\nimport { options, parseBooleanOption } from \"comline\"\n\nimport { formatNpmReport, npmCheck, npmTest } from \"./check.ts\"\nimport { errorMessage } from \"./command.ts\"\nimport { validateConfig } from \"./config.ts\"\nimport { record } from \"./manifest.ts\"\nimport type { NpmTestSelection } from \"./types.ts\"\n\ntype CommonOptions = { config?: string | undefined; json?: boolean | undefined }\ntype CheckOptions = CommonOptions & { coverageOnly?: boolean | undefined }\ntype TestOptions = CommonOptions & { representative?: string | undefined }\n\nconst common = {\n\tconfig: {\n\t\trequired: false,\n\t\tdescription: `Configuration file (defaults to breakage.config.ts, then .json).`,\n\t\texample: `--config ./breakage.config.ts`,\n\t\tcompletion: { fileSystem: `files` as const, repeatable: false },\n\t},\n\tjson: {\n\t\trequired: false,\n\t\tdescription: `Emit the structured result.`,\n\t\texample: `--json`,\n\t\tparse: parseBooleanOption,\n\t},\n}\n\nexport const npmCheckManual: OptionsGroup<CheckOptions> = options(\n\t`Check npm peer compatibility and changes in declared support.`,\n\ttype({ \"config?\": `string`, \"json?\": `boolean`, \"coverageOnly?\": `boolean` }),\n\t{\n\t\t...common,\n\t\tcoverageOnly: {\n\t\t\taliases: [`coverage-only`],\n\t\t\trequired: false,\n\t\t\tdescription: `Audit coverage and support changes without executing assertions.`,\n\t\t\texample: `--coverage-only`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n)\n\nexport const npmTestManual: OptionsGroup<TestOptions> = options(\n\t`Run current contracts in matching complete peer environments.`,\n\ttype({\n\t\t\"config?\": `string`,\n\t\t\"json?\": `boolean`,\n\t\t\"representative?\": `string`,\n\t}),\n\t{\n\t\t...common,\n\t\trepresentative: {\n\t\t\trequired: false,\n\t\t\tdescription: `Select an exact configured representative path relative to the package.`,\n\t\t\texample: `--representative peer-environments/react-19`,\n\t\t\tcompletion: { fileSystem: `directories`, repeatable: false },\n\t\t},\n\t},\n)\n\nexport function defaultConfig(directory: string): string {\n\treturn path.join(\n\t\tdirectory,\n\t\texistsSync(path.join(directory, `breakage.config.ts`))\n\t\t\t? `breakage.config.ts`\n\t\t\t: `breakage.config.json`,\n\t)\n}\n\nexport async function runNpmCli(\n\taction: `check` | `test`,\n\topts: CheckOptions & TestOptions,\n\tpeerSelection?: { peer: string; range: string },\n): Promise<number> {\n\ttry {\n\t\tconst filename = path.resolve(opts.config ?? defaultConfig(process.cwd()))\n\t\tconst loaded: unknown = filename.endsWith(`.json`)\n\t\t\t? JSON.parse(await readFile(filename, `utf8`))\n\t\t\t: ((await import(pathToFileURL(filename).href)) as { default: unknown })\n\t\t\t\t\t.default\n\t\tconst config = record(loaded) ? loaded.npm : undefined\n\t\tvalidateConfig(config)\n\t\tlet selection: NpmTestSelection | undefined\n\t\tif (action === `test`) {\n\t\t\tif (peerSelection && opts.representative)\n\t\t\t\tthrow new Error(`Choose a peer range or a representative, not both.`)\n\t\t\tselection =\n\t\t\t\tpeerSelection ??\n\t\t\t\t(opts.representative\n\t\t\t\t\t? { representative: opts.representative }\n\t\t\t\t\t: undefined)\n\t\t\tif (!selection)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Use npm test <peer> <range> or npm test --representative <path>.`,\n\t\t\t\t)\n\t\t}\n\t\tconst options = {\n\t\t\tbaseDirectory: path.dirname(filename),\n\t\t\tcoverageOnly: opts.coverageOnly ?? false,\n\t\t}\n\t\tconst report = selection\n\t\t\t? await npmTest(config, selection, options)\n\t\t\t: await npmCheck(config, options)\n\t\tprocess.stdout.write(\n\t\t\topts.json\n\t\t\t\t? `${JSON.stringify(report, null, 2)}\\n`\n\t\t\t\t: formatNpmReport(report),\n\t\t)\n\t\treturn report.exitCode\n\t} catch (error) {\n\t\tconst message = errorMessage(error)\n\t\tprocess.stdout.write(\n\t\t\topts.json\n\t\t\t\t? `${JSON.stringify({ exitCode: 2, errors: [message] })}\\n`\n\t\t\t\t: `npm setup error: ${message}\\n`,\n\t\t)\n\t\treturn 2\n\t}\n}\n","#!/usr/bin/env node\n\nimport { inspect } from \"node:util\"\n\nimport { type } from \"arktype\"\nimport type { OptionsGroup } from \"comline\"\nimport {\n\tcli,\n\tcompletionResponse,\n\tencapsulate,\n\thelp,\n\tlogWarnings,\n\tnoOptions,\n\toptional,\n\toptions,\n\tparseBooleanOption,\n\trequired,\n} from \"comline\"\nimport logger from \"takua\"\n\nimport type { BreakageOptions } from \"./breakage.ts\"\nimport { breakage, breakagePrelude } from \"./breakage.ts\"\nimport {\n\tdefaultConfig,\n\tnpmCheckManual,\n\tnpmTestManual,\n\trunNpmCli,\n} from \"./npm/cli.ts\"\n\nconst BREAKAGE_MANUAL = options(\n\t`Check for breaking changes in a package.`,\n\ttype({\n\t\t\"tagPattern?\": `string`,\n\t\t\"baselineFile?\": `string`,\n\t\ttestPattern: `string`,\n\t\ttestCommand: `string`,\n\t\tcertifyCommand: `string`,\n\t\t\"baseDirname?\": `string`,\n\t\t\"verbose?\": `boolean`,\n\t}),\n\t{\n\t\ttagPattern: {\n\t\t\taliases: [`tag-pattern`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `g`,\n\t\t\trequired: false,\n\t\t\tdescription: `RegExp which, if found matched to a git tag, will be considered a release tag for your library.`,\n\t\t\texample: `--tagPattern=\"my-library\"`,\n\t\t},\n\t\tbaselineFile: {\n\t\t\taliases: [`baseline-file`],\n\t\t\tcompletion: { repeatable: false, fileSystem: `files` },\n\t\t\trequired: false,\n\t\t\tdescription: `Use the exact locally fetched commit from a prelude snapshot instead of discovering remote tags.`,\n\t\t\texample: `--baseline-file=.breakage/baseline.json`,\n\t\t},\n\t\ttestPattern: {\n\t\t\taliases: [`test-pattern`, `pattern`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `p`,\n\t\t\trequired: true,\n\t\t\tdescription: `The pattern to match test files that test the public API of the library.`,\n\t\t\texample: `--pattern=\"*__public.test.ts\"`,\n\t\t},\n\t\ttestCommand: {\n\t\t\taliases: [`test-command`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `t`,\n\t\t\trequired: true,\n\t\t\tdescription: `Complete bash command that runs the tests for the library's public API.`,\n\t\t\texample: `--testCommand=\"npm run test\"`,\n\t\t},\n\t\tcertifyCommand: {\n\t\t\taliases: [`certify-command`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `c`,\n\t\t\trequired: true,\n\t\t\tdescription: `Complete bash command that determines whether a major version bump for your package is indicated in the workspace. Exit code 0 indicates that a major version bump is indicated, and exit code 1 indicates that no major version bump is indicated.`,\n\t\t\texample: `--certifyCommand=\\tsx scripts/certify-major-version-bump.node`,\n\t\t},\n\t\tbaseDirname: {\n\t\t\taliases: [`base-dir`, `base-dirname`],\n\t\t\tcompletion: { repeatable: false, fileSystem: `directories` },\n\t\t\tflag: `d`,\n\t\t\trequired: false,\n\t\t\tdescription: `The base directory to run the command from.`,\n\t\t\texample: `--baseDirname=./packages/my-package`,\n\t\t},\n\t\tverbose: {\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `v`,\n\t\t\trequired: false,\n\t\t\tdescription: `Prints out more information about the process.`,\n\t\t\texample: `--verbose`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n) satisfies OptionsGroup<BreakageOptions>\n\nconst PRELUDE_MANUAL = options(\n\t`Resolve and fetch the release baseline for a cacheable compatibility check.`,\n\ttype({\n\t\t\"tagPattern?\": `string`,\n\t\t\"baseDirname?\": `string`,\n\t\t\"out?\": `string`,\n\t\t\"testPattern?\": `string`,\n\t\t\"testCommand?\": `string`,\n\t\t\"certifyCommand?\": `string`,\n\t\t\"baselineFile?\": `string`,\n\t\t\"verbose?\": `boolean`,\n\t}),\n\t{\n\t\t...BREAKAGE_MANUAL.optionConfigs,\n\t\ttestPattern: {\n\t\t\t...BREAKAGE_MANUAL.optionConfigs.testPattern,\n\t\t\trequired: false,\n\t\t},\n\t\ttestCommand: {\n\t\t\t...BREAKAGE_MANUAL.optionConfigs.testCommand,\n\t\t\trequired: false,\n\t\t},\n\t\tcertifyCommand: {\n\t\t\t...BREAKAGE_MANUAL.optionConfigs.certifyCommand,\n\t\t\trequired: false,\n\t\t},\n\t\tout: {\n\t\t\tcompletion: { repeatable: false, fileSystem: `files` },\n\t\t\trequired: false,\n\t\t\tdescription: `Gitignored snapshot path relative to the base directory (default: .breakage/baseline.json).`,\n\t\t\texample: `--out=.breakage/baseline.json`,\n\t\t},\n\t},\n)\n\nconst SCHEMA_MANUAL = options(\n\t`Create a copy of the schema for configuring breakage.`,\n\ttype({ \"outdir?\": `string` }),\n\t{\n\t\toutdir: {\n\t\t\taliases: [`out-dir`],\n\t\t\tcompletion: { repeatable: false, fileSystem: `directories` },\n\t\t\tflag: `o`,\n\t\t\trequired: false,\n\t\t\tdescription: `Directory to write the schema to.`,\n\t\t\texample: `--outdir=./dist`,\n\t\t},\n\t},\n)\n\nconst parse = cli(\n\t{\n\t\tcliName: `breakage`,\n\t\troutes: optional({\n\t\t\thelp: null,\n\t\t\tschema: null,\n\t\t\tnpm: optional({\n\t\t\t\thelp: null,\n\t\t\t\tcheck: null,\n\t\t\t\ttest: optional({ $peer: required({ $range: null }) }),\n\t\t\t}),\n\t\t\tprelude: optional({ $configPath: null }),\n\t\t\t$configPath: null,\n\t\t}),\n\t\trouteOptions: {\n\t\t\t\"\": BREAKAGE_MANUAL,\n\t\t\t$configPath: BREAKAGE_MANUAL,\n\t\t\thelp: noOptions(`Show usage.`),\n\t\t\tschema: SCHEMA_MANUAL,\n\t\t\tnpm: noOptions(`Show npm compatibility commands.`),\n\t\t\t\"npm/help\": noOptions(`Show npm compatibility commands.`),\n\t\t\t\"npm/check\": npmCheckManual,\n\t\t\t\"npm/test\": npmTestManual,\n\t\t\t\"npm/test/$peer/$range\": npmTestManual,\n\t\t\tprelude: PRELUDE_MANUAL,\n\t\t\t\"prelude/$configPath\": PRELUDE_MANUAL,\n\t\t},\n\t\tpositionalCompletions: {\n\t\t\t$configPath: { fileSystem: `files` },\n\t\t\t\"prelude/$configPath\": { fileSystem: `files` },\n\t\t},\n\t\tdiscoverConfigPath: (args: readonly string[]) => {\n\t\t\tif (args[0] === `help` || args[0] === `schema` || args[0] === `npm`) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst configPath =\n\t\t\t\t(args[0] === `prelude` ? args[1] : args[0]) ??\n\t\t\t\tdefaultConfig(process.cwd())\n\t\t\treturn configPath\n\t\t},\n\t},\n\t{\n\t\tinfo: (message, ...data) => logger.info(`breakage`, message, data),\n\t\terror: (message, ...data) => logger.error(`breakage`, message, data),\n\t},\n)\n\nconst completion = await completionResponse(parse.definition, process.argv)\nif (completion !== undefined) {\n\tprocess.stdout.write(completion)\n} else {\n\tconst { inputs, warnings, writeJsonSchema } = parse(process.argv)\n\tlogWarnings(warnings)\n\n\tswitch (inputs.case) {\n\t\tcase `npm`:\n\t\tcase `npm/help`:\n\t\tcase `help`:\n\t\t\tconsole.log(help(parse.definition))\n\t\t\tbreak\n\t\tcase `npm/check`:\n\t\t\tprocess.exitCode = await runNpmCli(`check`, inputs.opts)\n\t\t\tbreak\n\t\tcase `npm/test`:\n\t\t\tprocess.exitCode = await runNpmCli(`test`, inputs.opts)\n\t\t\tbreak\n\t\tcase `npm/test/$peer/$range`:\n\t\t\tprocess.exitCode = await runNpmCli(`test`, inputs.opts, inputs.params)\n\t\t\tbreak\n\t\tcase `schema`:\n\t\t\t{\n\t\t\t\tconst { outdir } = inputs.opts\n\t\t\t\twriteJsonSchema(outdir ?? `.`)\n\t\t\t\tprocess.stdout.write(`📝 Wrote json.schema.`)\n\t\t\t}\n\t\t\tbreak\n\t\tcase `prelude`:\n\t\tcase `prelude/$configPath`: {\n\t\t\tconst baseline = await breakagePrelude({\n\t\t\t\t...inputs.opts,\n\t\t\t\tout: inputs.opts.out ?? `.breakage/baseline.json`,\n\t\t\t})\n\t\t\tprocess.stdout.write(`Pinned ${baseline.ref} at ${baseline.commit}.\\n`)\n\t\t\tbreak\n\t\t}\n\t\tcase ``:\n\t\tcase `$configPath`: {\n\t\t\tconst { returnValue } = await encapsulate(() => breakage(inputs.opts), {\n\t\t\t\tconsole: true,\n\t\t\t\tstdout: true,\n\t\t\t})\n\t\t\tif (`testResult` in returnValue && returnValue.breakingChangesFound) {\n\t\t\t\tprocess.stdout.write(returnValue.testResult)\n\t\t\t}\n\t\t\tif (`breakingChangesFound` in returnValue) {\n\t\t\t\tif (returnValue.breakingChangesFound) {\n\t\t\t\t\tif (returnValue.breakingChangesCertified) {\n\t\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t\t`👷 Breaking changes were found and certified.`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tprocess.exit(0)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t\t`❌ Breaking changes were found, but not certified.`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tprocess.exit(1)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tprocess.stdout.write(`✅ No breaking changes were found.`)\n\t\t\t\t\tprocess.exit(0)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t`💥 Breakage failed to determine breaking changes.` +\n\t\t\t\t\t\t`\\n` +\n\t\t\t\t\t\tinspect(returnValue),\n\t\t\t\t)\n\t\t\t\tprocess.exit(2)\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"breakage.x.js","names":[],"sources":["../src/npm/cli.ts","../src/breakage.x.ts"],"sourcesContent":["import path from \"node:path\"\n\nimport { type } from \"arktype\"\nimport type { OptionsGroup } from \"comline\"\nimport { options, parseBooleanOption } from \"comline\"\n\nimport { configOptions, defaultConfig, loadConfig } from \"../config.ts\"\n\nimport { formatNpmReport, npmCheck, npmTest } from \"./check.ts\"\nimport { errorMessage } from \"../task.ts\"\nimport { validateConfig } from \"./config.ts\"\nimport type { NpmTestSelection } from \"./types.ts\"\n\ntype CommonOptions = {\n\tconfig?: string | undefined\n\tjson?: boolean | undefined\n\trelease?: import(\"../release.ts\").ReleaseConfig\n\tnpm?: import(\"./types.ts\").NpmConfig\n}\ntype CheckOptions = CommonOptions & { coverageOnly?: boolean | undefined }\ntype TestOptions = CommonOptions & { representative?: string | undefined }\n\nconst common = {\n\trelease: configOptions.optionConfigs.release,\n\tnpm: configOptions.optionConfigs.npm,\n\tconfig: {\n\t\tschema: type(`string`),\n\t\trequired: false,\n\t\tdescription: `Configuration file (defaults to breakage.config.ts).`,\n\t\texample: `--config ./breakage.config.ts`,\n\t\tcompletion: { fileSystem: `files` as const, repeatable: false },\n\t},\n\tjson: {\n\t\tschema: type(`boolean`),\n\t\trequired: false,\n\t\tdescription: `Emit the structured result.`,\n\t\texample: `--json`,\n\t\tparse: parseBooleanOption,\n\t},\n}\n\nexport const npmCheckManual: OptionsGroup<CheckOptions> = options(\n\t`Check npm peer compatibility and changes in declared support.`,\n\ttype({\n\t\t\"config?\": `string`,\n\t\t\"json?\": `boolean`,\n\t\t\"coverageOnly?\": `boolean`,\n\t\t\"release?\": configOptions.optionsSchema.get(`release`),\n\t\t\"npm?\": configOptions.optionsSchema.get(`npm`),\n\t}),\n\t{\n\t\t...common,\n\t\tcoverageOnly: {\n\t\t\tschema: type(`boolean`),\n\t\t\taliases: [`coverage-only`],\n\t\t\trequired: false,\n\t\t\tdescription: `Audit coverage and support changes without executing assertions.`,\n\t\t\texample: `--coverage-only`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n)\n\nexport const npmTestManual: OptionsGroup<TestOptions> = options(\n\t`Run current contracts in matching complete peer environments.`,\n\ttype({\n\t\t\"config?\": `string`,\n\t\t\"json?\": `boolean`,\n\t\t\"representative?\": `string`,\n\t\t\"release?\": configOptions.optionsSchema.get(`release`),\n\t\t\"npm?\": configOptions.optionsSchema.get(`npm`),\n\t}),\n\t{\n\t\t...common,\n\t\trepresentative: {\n\t\t\tschema: type(`string`),\n\t\t\trequired: false,\n\t\t\tdescription: `Select an exact configured representative path relative to the package.`,\n\t\t\texample: `--representative peer-environments/react-19`,\n\t\t\tcompletion: { fileSystem: `directories`, repeatable: false },\n\t\t},\n\t},\n)\n\nexport async function runNpmCli(\n\taction: `check` | `test`,\n\topts: CheckOptions & TestOptions,\n\tpeerSelection?: { peer: string; range: string },\n): Promise<number> {\n\ttry {\n\t\tconst filename = path.resolve(opts.config ?? defaultConfig(process.cwd()))\n\t\tconst config = (await loadConfig(filename)).npm\n\t\tvalidateConfig(config)\n\t\tlet selection: NpmTestSelection | undefined\n\t\tif (action === `test`) {\n\t\t\tif (peerSelection && opts.representative)\n\t\t\t\tthrow new Error(`Choose a peer range or a representative, not both.`)\n\t\t\tselection =\n\t\t\t\tpeerSelection ??\n\t\t\t\t(opts.representative\n\t\t\t\t\t? { representative: opts.representative }\n\t\t\t\t\t: undefined)\n\t\t\tif (!selection)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Use npm test <peer> <range> or npm test --representative <path>.`,\n\t\t\t\t)\n\t\t}\n\t\tconst options = {\n\t\t\tbaseDirectory: path.dirname(filename),\n\t\t\tcoverageOnly: opts.coverageOnly ?? false,\n\t\t}\n\t\tconst report = selection\n\t\t\t? await npmTest(config, selection, options)\n\t\t\t: await npmCheck(config, options)\n\t\tprocess.stdout.write(\n\t\t\topts.json\n\t\t\t\t? `${JSON.stringify(report, null, 2)}\\n`\n\t\t\t\t: formatNpmReport(report),\n\t\t)\n\t\treturn report.exitCode\n\t} catch (error) {\n\t\tconst message = errorMessage(error)\n\t\tprocess.stdout.write(\n\t\t\topts.json\n\t\t\t\t? `${JSON.stringify({ exitCode: 2, errors: [message] })}\\n`\n\t\t\t\t: `npm setup error: ${message}\\n`,\n\t\t)\n\t\treturn 2\n\t}\n}\n","#!/usr/bin/env node\n\nimport path from \"node:path\"\nimport { inspect } from \"node:util\"\n\nimport {\n\tcli,\n\tcompletionResponse,\n\tencapsulate,\n\thelp,\n\tlogWarnings,\n\tnoOptions,\n\toptional,\n\toptions,\n\tparseBooleanOption,\n\trequired,\n} from \"comline\"\nimport logger from \"takua\"\n\nimport {\n\tdefaultConfig,\n\tconfigPath,\n\tresolveConfig,\n\tconfigSchema,\n\tconfigFields,\n} from \"./config.ts\"\nimport { breakage, breakagePrelude } from \"./breakage.ts\"\nimport { errorMessage } from \"./task.ts\"\nimport { npmCheckManual, npmTestManual, runNpmCli } from \"./npm/cli.ts\"\n\n// Either command spelling can override the other spelling in a config file.\nconst commandOverrides = new Set<`test` | `testCommand`>()\n\nconst BREAKAGE_MANUAL = options(\n\t`Check for breaking changes in a package.`,\n\tconfigSchema,\n\t{\n\t\trelease: { configOnly: true },\n\t\tnpm: { configOnly: true },\n\t\tout: { configOnly: true },\n\t\ttagPattern: {\n\t\t\tschema: configFields.tagPattern,\n\t\t\taliases: [`tag-pattern`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `g`,\n\t\t\trequired: false,\n\t\t\tdescription: `RegExp which, if found matched to a git tag, will be considered a release tag for your library.`,\n\t\t\texample: `--tagPattern=\"my-library\"`,\n\t\t},\n\t\tbaselineFile: {\n\t\t\tschema: configFields.baselineFile,\n\t\t\taliases: [`baseline-file`],\n\t\t\tcompletion: { repeatable: false, fileSystem: `files` },\n\t\t\trequired: false,\n\t\t\tdescription: `Use the exact locally fetched commit from a prelude snapshot instead of discovering remote tags.`,\n\t\t\texample: `--baseline-file=.breakage/baseline.json`,\n\t\t},\n\t\ttestPattern: {\n\t\t\tschema: configFields.testPattern,\n\t\t\taliases: [`test-pattern`, `pattern`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `p`,\n\t\t\trequired: false,\n\t\t\tdescription: `The pattern to match test files that test the public API of the library.`,\n\t\t\texample: `--pattern=\"*__public.test.ts\"`,\n\t\t},\n\t\ttestCommand: {\n\t\t\tparse: (value) => {\n\t\t\t\tcommandOverrides.add(`testCommand`)\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tschema: configFields.testCommand,\n\t\t\taliases: [`test-command`],\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `t`,\n\t\t\trequired: false,\n\t\t\tdescription: `Complete bash command that runs the tests for the library's public API.`,\n\t\t\texample: `--testCommand=\"npm run test\"`,\n\t\t},\n\t\ttest: {\n\t\t\tparse: (value) => {\n\t\t\t\tcommandOverrides.add(`test`)\n\t\t\t\treturn value\n\t\t\t},\n\t\t\tschema: configFields.test,\n\t\t\tcompletion: { repeatable: false },\n\t\t\trequired: false,\n\t\t\tdescription: `Shell command running the restored public contracts.`,\n\t\t\texample: `--test=\"npm run test:public\"`,\n\t\t},\n\t\tbaseDirname: {\n\t\t\tparse: (value) => path.resolve(value),\n\t\t\tschema: configFields.baseDirname,\n\t\t\taliases: [`base-dir`, `base-dirname`],\n\t\t\tcompletion: { repeatable: false, fileSystem: `directories` },\n\t\t\tflag: `d`,\n\t\t\trequired: false,\n\t\t\tdescription: `The base directory to run the command from.`,\n\t\t\texample: `--baseDirname=./packages/my-package`,\n\t\t},\n\t\tverbose: {\n\t\t\tschema: configFields.verbose,\n\t\t\tcompletion: { repeatable: false },\n\t\t\tflag: `v`,\n\t\t\trequired: false,\n\t\t\tdescription: `Prints out more information about the process.`,\n\t\t\texample: `--verbose`,\n\t\t\tparse: parseBooleanOption,\n\t\t},\n\t},\n)\n\nconst PRELUDE_MANUAL = options(\n\t`Resolve and fetch the release baseline for a cacheable compatibility check.`,\n\tconfigSchema,\n\t{\n\t\t...BREAKAGE_MANUAL.optionConfigs,\n\t\ttestPattern: {\n\t\t\t...BREAKAGE_MANUAL.optionConfigs.testPattern,\n\t\t\trequired: false,\n\t\t},\n\t\ttestCommand: {\n\t\t\t...BREAKAGE_MANUAL.optionConfigs.testCommand,\n\t\t\trequired: false,\n\t\t},\n\t\tout: {\n\t\t\tschema: configFields.out,\n\t\t\tcompletion: { repeatable: false, fileSystem: `files` },\n\t\t\trequired: false,\n\t\t\tdescription: `Gitignored snapshot path relative to the base directory (default: .breakage/baseline.json).`,\n\t\t\texample: `--out=.breakage/baseline.json`,\n\t\t},\n\t},\n)\n\nlet loadedConfigPath: string | undefined\nconst parse = cli(\n\t{\n\t\tcliName: `breakage`,\n\t\tdiscoverConfigPath: (segments: readonly string[]) => {\n\t\t\tif (segments[0] === `help` || segments[0] === `npm`) return undefined\n\t\t\tconst explicit = segments[0] === `prelude` ? segments[1] : segments[0]\n\t\t\tloadedConfigPath = configPath(\n\t\t\t\texplicit ?? defaultConfig(process.cwd()),\n\t\t\t\texplicit !== undefined,\n\t\t\t)\n\t\t\treturn loadedConfigPath\n\t\t},\n\t\troutes: optional({\n\t\t\thelp: null,\n\t\t\tnpm: optional({\n\t\t\t\thelp: null,\n\t\t\t\tcheck: null,\n\t\t\t\ttest: optional({ $peer: required({ $range: null }) }),\n\t\t\t}),\n\t\t\tprelude: optional({ $configPath: null }),\n\t\t\t$configPath: null,\n\t\t}),\n\t\trouteOptions: {\n\t\t\t\"\": BREAKAGE_MANUAL,\n\t\t\t$configPath: BREAKAGE_MANUAL,\n\t\t\thelp: noOptions(`Show usage.`),\n\t\t\tnpm: noOptions(`Show npm compatibility commands.`),\n\t\t\t\"npm/help\": noOptions(`Show npm compatibility commands.`),\n\t\t\t\"npm/check\": npmCheckManual,\n\t\t\t\"npm/test\": npmTestManual,\n\t\t\t\"npm/test/$peer/$range\": npmTestManual,\n\t\t\tprelude: PRELUDE_MANUAL,\n\t\t\t\"prelude/$configPath\": PRELUDE_MANUAL,\n\t\t},\n\t\tpositionalCompletions: {\n\t\t\t$configPath: { fileSystem: `files` },\n\t\t\t\"prelude/$configPath\": { fileSystem: `files` },\n\t\t},\n\t},\n\t{\n\t\tinfo: (message, ...data) => logger.info(`breakage`, message, data),\n\t\terror: (message, ...data) => logger.error(`breakage`, message, data),\n\t},\n)\n\nconst completion = await completionResponse(parse.definition, process.argv)\nif (completion !== undefined) {\n\tprocess.stdout.write(completion)\n} else {\n\ttry {\n\t\tconst { inputs, warnings } = await parse.async(process.argv)\n\t\tlogWarnings(warnings)\n\t\tif (\n\t\t\tprocess.argv\n\t\t\t\t.slice(2)\n\t\t\t\t.some((arg) =>\n\t\t\t\t\t/^(?:--certifyCommand|--certify-command|-c)(?:=|$)/.test(arg),\n\t\t\t\t)\n\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`certifyCommand was removed. Configure release.resolveDelta and release.policy instead.`,\n\t\t\t)\n\n\t\tswitch (inputs.case) {\n\t\t\tcase `npm`:\n\t\t\tcase `npm/help`:\n\t\t\tcase `help`:\n\t\t\t\tconsole.log(help(parse.definition))\n\t\t\t\tbreak\n\t\t\tcase `npm/check`:\n\t\t\t\tprocess.exitCode = await runNpmCli(`check`, inputs.opts)\n\t\t\t\tbreak\n\t\t\tcase `npm/test`:\n\t\t\t\tprocess.exitCode = await runNpmCli(`test`, inputs.opts)\n\t\t\t\tbreak\n\t\t\tcase `npm/test/$peer/$range`:\n\t\t\t\tprocess.exitCode = await runNpmCli(`test`, inputs.opts, inputs.params)\n\t\t\t\tbreak\n\t\t\tcase `prelude`:\n\t\t\tcase `prelude/$configPath`: {\n\t\t\t\tconst config = resolveConfig(inputs.opts, loadedConfigPath)\n\t\t\t\tconst baseline = await breakagePrelude({\n\t\t\t\t\t...config,\n\t\t\t\t\tout: config.out ?? `.breakage/baseline.json`,\n\t\t\t\t})\n\t\t\t\tprocess.stdout.write(`Pinned ${baseline.ref} at ${baseline.commit}.\\n`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase ``:\n\t\t\tcase `$configPath`: {\n\t\t\t\tconst merged = resolveConfig(inputs.opts, loadedConfigPath)\n\t\t\t\tif (\n\t\t\t\t\tcommandOverrides.has(`testCommand`) &&\n\t\t\t\t\t!commandOverrides.has(`test`)\n\t\t\t\t)\n\t\t\t\t\tdelete merged.test\n\t\t\t\tif (\n\t\t\t\t\tcommandOverrides.has(`test`) &&\n\t\t\t\t\t!commandOverrides.has(`testCommand`)\n\t\t\t\t)\n\t\t\t\t\tdelete merged.testCommand\n\t\t\t\tif (!merged.testPattern)\n\t\t\t\t\tthrow new Error(`required arguments were not provided: testPattern.`)\n\t\t\t\tconst { returnValue } = await encapsulate(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tbreakage({\n\t\t\t\t\t\t\t...merged,\n\t\t\t\t\t\t\ttestPattern: merged.testPattern!,\n\t\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tconsole: true,\n\t\t\t\t\t\tstdout: true,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif (`release` in returnValue && returnValue.release) {\n\t\t\t\t\tconst { previousVersion, version, delta, breaking } =\n\t\t\t\t\t\treturnValue.release\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t`Release: ${previousVersion} → ${version} (${delta}; ${breaking ? `breaking` : `compatible`}).\\n`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tif (`testResult` in returnValue && returnValue.breakingChangesFound) {\n\t\t\t\t\tprocess.stdout.write(returnValue.testResult)\n\t\t\t\t}\n\t\t\t\tif (`breakingChangesFound` in returnValue) {\n\t\t\t\t\tif (returnValue.breakingChangesFound) {\n\t\t\t\t\t\tif (returnValue.release?.breaking) {\n\t\t\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t\t\t`👷 Breaking changes are covered by the breaking release.`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tprocess.exit(0)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t\t\t`❌ Breaking changes require a breaking release.`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tprocess.exit(1)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprocess.stdout.write(`✅ No breaking changes were found.`)\n\t\t\t\t\t\tprocess.exit(0)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t`💥 Breakage failed to determine breaking changes.` +\n\t\t\t\t\t\t\t`\\n` +\n\t\t\t\t\t\t\tinspect(returnValue),\n\t\t\t\t\t)\n\t\t\t\t\tprocess.exit(2)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tprocess.stderr.write(`Breakage setup error: ${errorMessage(error)}\\n`)\n\t\tprocess.exitCode = 2\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { c as VersionTransition, n as ReleaseDeltaContext } from "./release-D47BqRuB.js";
|
|
2
|
+
/** Read the actual Changesets plan, including dependent bumps and prerelease state. */
|
|
3
|
+
export declare function readChangesetsReleasePlan(directory?: string): Promise<ReadonlyMap<string, string>>;
|
|
4
|
+
/** Compare the selected baseline (or current manifest) with the planned or versioned release. */
|
|
5
|
+
export declare function changesetsReleaseDelta({ directory }?: {
|
|
6
|
+
directory?: string;
|
|
7
|
+
}): (context: ReleaseDeltaContext) => Promise<VersionTransition>;
|
|
8
|
+
//# sourceMappingURL=changesets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changesets.d.ts","names":[],"sources":["../src/changesets.ts"],"mappings":";;wBAasB,0BACrB,qBACE,QAAQ;;wBAkBK,yBACf;EACI;KACJ,SAAS,wBACL,QAAQ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { s as versionTransition } from "./release-BsdIDT4g.js";
|
|
2
|
+
import { assembleReleasePlan } from "@changesets/assemble-release-plan";
|
|
3
|
+
import { readConfig } from "@changesets/config";
|
|
4
|
+
import { readPreState } from "@changesets/pre";
|
|
5
|
+
import { readChangesets } from "@changesets/read";
|
|
6
|
+
import { getPackages } from "@manypkg/get-packages";
|
|
7
|
+
// src/changesets.ts
|
|
8
|
+
/** Read the actual Changesets plan, including dependent bumps and prerelease state. */
|
|
9
|
+
async function readChangesetsReleasePlan(directory = process.cwd()) {
|
|
10
|
+
const packages = await getPackages(directory);
|
|
11
|
+
const root = packages.rootDir;
|
|
12
|
+
const { config, errors } = await readConfig(root, packages);
|
|
13
|
+
if (errors) throw new Error(errors.join(`\n`));
|
|
14
|
+
const [changesets, preState] = await Promise.all([readChangesets(root), readPreState(root)]);
|
|
15
|
+
const plan = assembleReleasePlan(changesets, packages, config, preState);
|
|
16
|
+
return new Map(plan.releases.flatMap(({ name, newVersion }) => newVersion === void 0 ? [] : [[name, newVersion]]));
|
|
17
|
+
}
|
|
18
|
+
/** Compare the selected baseline (or current manifest) with the planned or versioned release. */
|
|
19
|
+
function changesetsReleaseDelta({ directory } = {}) {
|
|
20
|
+
return async ({ packageName, packageDirectory, currentVersion, baseline }) => {
|
|
21
|
+
const version = (await readChangesetsReleasePlan(directory ?? packageDirectory)).get(packageName) ?? currentVersion;
|
|
22
|
+
return versionTransition(baseline?.version ?? currentVersion, version);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export { changesetsReleaseDelta, readChangesetsReleasePlan };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=changesets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changesets.js","names":[],"sources":["../src/changesets.ts"],"sourcesContent":["import { assembleReleasePlan } from \"@changesets/assemble-release-plan\"\nimport { readConfig } from \"@changesets/config\"\nimport { readPreState } from \"@changesets/pre\"\nimport { readChangesets } from \"@changesets/read\"\nimport { getPackages } from \"@manypkg/get-packages\"\n\nimport {\n\tversionTransition,\n\ttype ReleaseDeltaContext,\n\ttype VersionTransition,\n} from \"./release.ts\"\n\n/** Read the actual Changesets plan, including dependent bumps and prerelease state. */\nexport async function readChangesetsReleasePlan(\n\tdirectory: string = process.cwd(),\n): Promise<ReadonlyMap<string, string>> {\n\tconst packages = await getPackages(directory)\n\tconst root = packages.rootDir\n\tconst { config, errors } = await readConfig(root, packages)\n\tif (errors) throw new Error(errors.join(`\\n`))\n\tconst [changesets, preState] = await Promise.all([\n\t\treadChangesets(root),\n\t\treadPreState(root),\n\t])\n\tconst plan = assembleReleasePlan(changesets, packages, config, preState)\n\treturn new Map(\n\t\tplan.releases.flatMap(({ name, newVersion }) =>\n\t\t\tnewVersion === undefined ? [] : [[name, newVersion] as const],\n\t\t),\n\t)\n}\n\n/** Compare the selected baseline (or current manifest) with the planned or versioned release. */\nexport function changesetsReleaseDelta({\n\tdirectory,\n}: { directory?: string } = {}): (\n\tcontext: ReleaseDeltaContext,\n) => Promise<VersionTransition> {\n\treturn async ({\n\t\tpackageName,\n\t\tpackageDirectory,\n\t\tcurrentVersion,\n\t\tbaseline,\n\t}) => {\n\t\tconst version =\n\t\t\t(await readChangesetsReleasePlan(directory ?? packageDirectory)).get(\n\t\t\t\tpackageName,\n\t\t\t) ?? currentVersion\n\t\treturn versionTransition(baseline?.version ?? currentVersion, version)\n\t}\n}\n"],"mappings":";;;;;;;;AAaA,eAAsB,0BACrB,YAAoB,QAAQ,IAAI,GACO;CACvC,MAAM,WAAW,MAAM,YAAY,SAAS;CAC5C,MAAM,OAAO,SAAS;CACtB,MAAM,EAAE,QAAQ,WAAW,MAAM,WAAW,MAAM,QAAQ;CAC1D,IAAI,QAAQ,MAAM,IAAI,MAAM,OAAO,KAAK,IAAI,CAAC;CAC7C,MAAM,CAAC,YAAY,YAAY,MAAM,QAAQ,IAAI,CAChD,eAAe,IAAI,GACnB,aAAa,IAAI,CAClB,CAAC;CACD,MAAM,OAAO,oBAAoB,YAAY,UAAU,QAAQ,QAAQ;CACvE,OAAO,IAAI,IACV,KAAK,SAAS,SAAS,EAAE,MAAM,iBAC9B,eAAe,KAAA,IAAY,CAAC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAU,CAC7D,CACD;AACD;;AAGA,SAAgB,uBAAuB,EACtC,cAC2B,CAAC,GAEG;CAC/B,OAAO,OAAO,EACb,aACA,kBACA,gBACA,eACK;EACL,MAAM,WACJ,MAAM,0BAA0B,aAAa,gBAAgB,EAAA,CAAG,IAChE,WACD,KAAK;EACN,OAAO,kBAAkB,UAAU,WAAW,gBAAgB,OAAO;CACtE;AACD"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { type } from "arktype";
|
|
3
|
+
// src/release.ts
|
|
4
|
+
const releaseSchema = type({
|
|
5
|
+
"+": `reject`,
|
|
6
|
+
"resolveDelta?": type(`Function`).as(),
|
|
7
|
+
"policy?": type(`Function`).as()
|
|
8
|
+
});
|
|
9
|
+
/** Choose which version increments permit breaking changes. Prerelease-only increments do not. */
|
|
10
|
+
function semverPolicy({ beforeV1 = `major` } = {}) {
|
|
11
|
+
if (![
|
|
12
|
+
`major`,
|
|
13
|
+
`minor`,
|
|
14
|
+
`patch`
|
|
15
|
+
].includes(beforeV1)) throw new Error(`Invalid beforeV1 policy.`);
|
|
16
|
+
return ({ previousVersion, version }) => {
|
|
17
|
+
const previous = new semver.SemVer(previousVersion);
|
|
18
|
+
const next = new semver.SemVer(version);
|
|
19
|
+
if (next.major > previous.major) return true;
|
|
20
|
+
if (previous.major !== 0 || beforeV1 === `major`) return false;
|
|
21
|
+
return next.minor > previous.minor || beforeV1 === `patch` && next.patch > previous.patch;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Describe a version transition without deciding whether it permits breakage. */
|
|
25
|
+
function versionTransition(previousVersion, version) {
|
|
26
|
+
if (!semver.valid(previousVersion) || !semver.valid(version)) throw new Error(`Expected exact semantic versions.`);
|
|
27
|
+
return {
|
|
28
|
+
previousVersion,
|
|
29
|
+
version,
|
|
30
|
+
delta: semver.diff(previousVersion, version) ?? `none`
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Pure comparison; equal and older versions never permit breaking changes. */
|
|
34
|
+
function versionDelta(previousVersion, version, policy = semverPolicy()) {
|
|
35
|
+
const evidence = versionTransition(previousVersion, version);
|
|
36
|
+
const breaking = semver.gt(version, previousVersion) ? policy(evidence) : false;
|
|
37
|
+
if (typeof breaking !== `boolean`) throw new Error(`Release policy must return a boolean.`);
|
|
38
|
+
return {
|
|
39
|
+
...evidence,
|
|
40
|
+
breaking
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function validateRelease(value) {
|
|
44
|
+
if (typeof value !== `object` || value === null || Array.isArray(value)) throw new Error(`release must be an object.`);
|
|
45
|
+
if (`version` in value) throw new Error(`release.version was removed. Use release.resolveDelta to return a version transition.`);
|
|
46
|
+
releaseSchema.assert(value);
|
|
47
|
+
}
|
|
48
|
+
/** Resolve and validate release evidence; policy is applied separately. */
|
|
49
|
+
async function resolveReleaseDelta(config, context) {
|
|
50
|
+
validateRelease(config);
|
|
51
|
+
const transition = config.resolveDelta ? await config.resolveDelta(context) : versionTransition(context.baseline?.version ?? context.currentVersion, context.currentVersion);
|
|
52
|
+
if (transition === void 0) return void 0;
|
|
53
|
+
if (typeof transition !== `object` || transition === null || Array.isArray(transition) || typeof transition.previousVersion !== `string` || !semver.valid(transition.previousVersion) || typeof transition.version !== `string` || !semver.valid(transition.version) || !semver.valid(context.currentVersion) || semver.lt(transition.version, context.currentVersion)) throw new Error(`Invalid release transition for ${context.packageName}; expected exact versions and a current/newer target.`);
|
|
54
|
+
if (context.baseline && transition.previousVersion !== context.baseline.version) throw new Error(`Release transition for ${context.packageName} does not match the selected baseline.`);
|
|
55
|
+
const evidence = versionTransition(transition.previousVersion, transition.version);
|
|
56
|
+
if (transition.delta !== evidence.delta) throw new Error(`Release transition for ${context.packageName} has an inconsistent semver delta.`);
|
|
57
|
+
return evidence;
|
|
58
|
+
}
|
|
59
|
+
/** Removed hooks must fail explicitly, including in untyped configurations. */
|
|
60
|
+
function rejectCertificationOptions(value) {
|
|
61
|
+
for (const key of [
|
|
62
|
+
`certifyCommand`,
|
|
63
|
+
`releaseIntent`,
|
|
64
|
+
`certifyBreaking`
|
|
65
|
+
]) if (key in value) throw new Error(`${key} was removed. Use release.resolveDelta and release.policy instead.`);
|
|
66
|
+
}
|
|
67
|
+
export { validateRelease as a, semverPolicy as i, releaseSchema as n, versionDelta as o, resolveReleaseDelta as r, versionTransition as s, rejectCertificationOptions as t };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=release-BsdIDT4g.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-BsdIDT4g.js","names":[],"sources":["../src/release.ts"],"sourcesContent":["// cspell:words premajor preminor prepatch\nimport semver from \"semver\"\nimport { type } from \"arktype\"\n\nexport type ReleaseDeltaContext = {\n\tpackageName: string\n\tpackageDirectory: string\n\tcurrentVersion: string\n\t/** The selected historical release, when checking compatibility. */\n\tbaseline?: { version: string; ref?: string; commit?: string }\n}\nexport type VersionTransition = {\n\tpreviousVersion: string\n\tversion: string\n\tdelta:\n\t\t| `major`\n\t\t| `premajor`\n\t\t| `minor`\n\t\t| `preminor`\n\t\t| `patch`\n\t\t| `prepatch`\n\t\t| `prerelease`\n\t\t| `release`\n\t\t| `none`\n}\nexport type ReleaseDeltaResolver = (\n\tcontext: ReleaseDeltaContext,\n) => VersionTransition | undefined | Promise<VersionTransition | undefined>\nexport type VersionDelta = VersionTransition & { breaking: boolean }\nexport type SemverPolicyOptions = { beforeV1?: `major` | `minor` | `patch` }\nexport type ReleasePolicyFunction = (delta: VersionTransition) => boolean\nexport type ReleasePolicy = ReleasePolicyFunction\nexport const releaseSchema = type({\n\t\"+\": `reject`,\n\t\"resolveDelta?\": type(`Function`).as<ReleaseDeltaResolver>(),\n\t\"policy?\": type(`Function`).as<ReleasePolicy>(),\n})\nexport type ReleaseConfig = typeof releaseSchema.infer\n\n/** Choose which version increments permit breaking changes. Prerelease-only increments do not. */\nexport function semverPolicy({\n\tbeforeV1 = `major`,\n}: SemverPolicyOptions = {}): ReleasePolicyFunction {\n\tif (![`major`, `minor`, `patch`].includes(beforeV1))\n\t\tthrow new Error(`Invalid beforeV1 policy.`)\n\treturn ({ previousVersion, version }) => {\n\t\tconst previous = new semver.SemVer(previousVersion)\n\t\tconst next = new semver.SemVer(version)\n\t\tif (next.major > previous.major) return true\n\t\tif (previous.major !== 0 || beforeV1 === `major`) return false\n\t\treturn (\n\t\t\tnext.minor > previous.minor ||\n\t\t\t(beforeV1 === `patch` && next.patch > previous.patch)\n\t\t)\n\t}\n}\n\n/** Describe a version transition without deciding whether it permits breakage. */\nexport function versionTransition(\n\tpreviousVersion: string,\n\tversion: string,\n): VersionTransition {\n\tif (!semver.valid(previousVersion) || !semver.valid(version))\n\t\tthrow new Error(`Expected exact semantic versions.`)\n\treturn {\n\t\tpreviousVersion,\n\t\tversion,\n\t\tdelta: semver.diff(previousVersion, version) ?? `none`,\n\t}\n}\n\n/** Pure comparison; equal and older versions never permit breaking changes. */\nexport function versionDelta(\n\tpreviousVersion: string,\n\tversion: string,\n\tpolicy: ReleasePolicy = semverPolicy(),\n): VersionDelta {\n\tconst evidence = versionTransition(previousVersion, version)\n\tconst breaking = semver.gt(version, previousVersion)\n\t\t? policy(evidence)\n\t\t: false\n\tif (typeof breaking !== `boolean`)\n\t\tthrow new Error(`Release policy must return a boolean.`)\n\treturn { ...evidence, breaking }\n}\n\nexport function validateRelease(\n\tvalue: unknown,\n): asserts value is ReleaseConfig {\n\tif (typeof value !== `object` || value === null || Array.isArray(value))\n\t\tthrow new Error(`release must be an object.`)\n\tif (`version` in value)\n\t\tthrow new Error(\n\t\t\t`release.version was removed. Use release.resolveDelta to return a version transition.`,\n\t\t)\n\treleaseSchema.assert(value)\n}\n\n/** Resolve and validate release evidence; policy is applied separately. */\nexport async function resolveReleaseDelta(\n\tconfig: ReleaseConfig,\n\tcontext: ReleaseDeltaContext,\n): Promise<VersionTransition | undefined> {\n\tvalidateRelease(config)\n\tconst transition = config.resolveDelta\n\t\t? await config.resolveDelta(context)\n\t\t: versionTransition(\n\t\t\t\tcontext.baseline?.version ?? context.currentVersion,\n\t\t\t\tcontext.currentVersion,\n\t\t\t)\n\tif (transition === undefined) return undefined\n\tif (\n\t\ttypeof transition !== `object` ||\n\t\ttransition === null ||\n\t\tArray.isArray(transition) ||\n\t\ttypeof transition.previousVersion !== `string` ||\n\t\t!semver.valid(transition.previousVersion) ||\n\t\ttypeof transition.version !== `string` ||\n\t\t!semver.valid(transition.version) ||\n\t\t!semver.valid(context.currentVersion) ||\n\t\tsemver.lt(transition.version, context.currentVersion)\n\t)\n\t\tthrow new Error(\n\t\t\t`Invalid release transition for ${context.packageName}; expected exact versions and a current/newer target.`,\n\t\t)\n\tif (\n\t\tcontext.baseline &&\n\t\ttransition.previousVersion !== context.baseline.version\n\t)\n\t\tthrow new Error(\n\t\t\t`Release transition for ${context.packageName} does not match the selected baseline.`,\n\t\t)\n\tconst evidence = versionTransition(\n\t\ttransition.previousVersion,\n\t\ttransition.version,\n\t)\n\tif (transition.delta !== evidence.delta)\n\t\tthrow new Error(\n\t\t\t`Release transition for ${context.packageName} has an inconsistent semver delta.`,\n\t\t)\n\t// Only evidence crosses this boundary; resolver-supplied policy decisions are ignored.\n\treturn evidence\n}\n\n/** Removed hooks must fail explicitly, including in untyped configurations. */\nexport function rejectCertificationOptions(value: object): void {\n\tfor (const key of [`certifyCommand`, `releaseIntent`, `certifyBreaking`]) {\n\t\tif (key in value)\n\t\t\tthrow new Error(\n\t\t\t\t`${key} was removed. Use release.resolveDelta and release.policy instead.`,\n\t\t\t)\n\t}\n}\n"],"mappings":";;;AAgCA,MAAa,gBAAgB,KAAK;CACjC,KAAK;CACL,iBAAiB,KAAK,UAAU,CAAC,CAAC,GAAyB;CAC3D,WAAW,KAAK,UAAU,CAAC,CAAC,GAAkB;AAC/C,CAAC;;AAID,SAAgB,aAAa,EAC5B,WAAW,YACa,CAAC,GAA0B;CACnD,IAAI,CAAC;EAAC;EAAS;EAAS;CAAO,CAAC,CAAC,SAAS,QAAQ,GACjD,MAAM,IAAI,MAAM,0BAA0B;CAC3C,QAAQ,EAAE,iBAAiB,cAAc;EACxC,MAAM,WAAW,IAAI,OAAO,OAAO,eAAe;EAClD,MAAM,OAAO,IAAI,OAAO,OAAO,OAAO;EACtC,IAAI,KAAK,QAAQ,SAAS,OAAO,OAAO;EACxC,IAAI,SAAS,UAAU,KAAK,aAAa,SAAS,OAAO;EACzD,OACC,KAAK,QAAQ,SAAS,SACrB,aAAa,WAAW,KAAK,QAAQ,SAAS;CAEjD;AACD;;AAGA,SAAgB,kBACf,iBACA,SACoB;CACpB,IAAI,CAAC,OAAO,MAAM,eAAe,KAAK,CAAC,OAAO,MAAM,OAAO,GAC1D,MAAM,IAAI,MAAM,mCAAmC;CACpD,OAAO;EACN;EACA;EACA,OAAO,OAAO,KAAK,iBAAiB,OAAO,KAAK;CACjD;AACD;;AAGA,SAAgB,aACf,iBACA,SACA,SAAwB,aAAa,GACtB;CACf,MAAM,WAAW,kBAAkB,iBAAiB,OAAO;CAC3D,MAAM,WAAW,OAAO,GAAG,SAAS,eAAe,IAChD,OAAO,QAAQ,IACf;CACH,IAAI,OAAO,aAAa,WACvB,MAAM,IAAI,MAAM,uCAAuC;CACxD,OAAO;EAAE,GAAG;EAAU;CAAS;AAChC;AAEA,SAAgB,gBACf,OACiC;CACjC,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACrE,MAAM,IAAI,MAAM,4BAA4B;CAC7C,IAAI,aAAa,OAChB,MAAM,IAAI,MACT,uFACD;CACD,cAAc,OAAO,KAAK;AAC3B;;AAGA,eAAsB,oBACrB,QACA,SACyC;CACzC,gBAAgB,MAAM;CACtB,MAAM,aAAa,OAAO,eACvB,MAAM,OAAO,aAAa,OAAO,IACjC,kBACA,QAAQ,UAAU,WAAW,QAAQ,gBACrC,QAAQ,cACT;CACF,IAAI,eAAe,KAAA,GAAW,OAAO,KAAA;CACrC,IACC,OAAO,eAAe,YACtB,eAAe,QACf,MAAM,QAAQ,UAAU,KACxB,OAAO,WAAW,oBAAoB,YACtC,CAAC,OAAO,MAAM,WAAW,eAAe,KACxC,OAAO,WAAW,YAAY,YAC9B,CAAC,OAAO,MAAM,WAAW,OAAO,KAChC,CAAC,OAAO,MAAM,QAAQ,cAAc,KACpC,OAAO,GAAG,WAAW,SAAS,QAAQ,cAAc,GAEpD,MAAM,IAAI,MACT,kCAAkC,QAAQ,YAAY,sDACvD;CACD,IACC,QAAQ,YACR,WAAW,oBAAoB,QAAQ,SAAS,SAEhD,MAAM,IAAI,MACT,0BAA0B,QAAQ,YAAY,uCAC/C;CACD,MAAM,WAAW,kBAChB,WAAW,iBACX,WAAW,OACZ;CACA,IAAI,WAAW,UAAU,SAAS,OACjC,MAAM,IAAI,MACT,0BAA0B,QAAQ,YAAY,mCAC/C;CAED,OAAO;AACR;;AAGA,SAAgB,2BAA2B,OAAqB;CAC/D,KAAK,MAAM,OAAO;EAAC;EAAkB;EAAiB;CAAiB,GACtE,IAAI,OAAO,OACV,MAAM,IAAI,MACT,GAAG,IAAI,mEACR;AAEH"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
type ReleaseDeltaContext = {
|
|
2
|
+
packageName: string;
|
|
3
|
+
packageDirectory: string;
|
|
4
|
+
currentVersion: string;
|
|
5
|
+
/** The selected historical release, when checking compatibility. */
|
|
6
|
+
baseline?: {
|
|
7
|
+
version: string;
|
|
8
|
+
ref?: string;
|
|
9
|
+
commit?: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
type VersionTransition = {
|
|
13
|
+
previousVersion: string;
|
|
14
|
+
version: string;
|
|
15
|
+
delta: `major` | `premajor` | `minor` | `preminor` | `patch` | `prepatch` | `prerelease` | `release` | `none`;
|
|
16
|
+
};
|
|
17
|
+
type ReleaseDeltaResolver = (context: ReleaseDeltaContext) => VersionTransition | undefined | Promise<VersionTransition | undefined>;
|
|
18
|
+
type VersionDelta = VersionTransition & {
|
|
19
|
+
breaking: boolean;
|
|
20
|
+
};
|
|
21
|
+
type SemverPolicyOptions = {
|
|
22
|
+
beforeV1?: `major` | `minor` | `patch`;
|
|
23
|
+
};
|
|
24
|
+
type ReleasePolicyFunction = (delta: VersionTransition) => boolean;
|
|
25
|
+
type ReleasePolicy = ReleasePolicyFunction;
|
|
26
|
+
declare const releaseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
27
|
+
resolveDelta?: ReleaseDeltaResolver;
|
|
28
|
+
policy?: ReleasePolicyFunction;
|
|
29
|
+
}, {}>;
|
|
30
|
+
type ReleaseConfig = typeof releaseSchema.infer;
|
|
31
|
+
/** Choose which version increments permit breaking changes. Prerelease-only increments do not. */
|
|
32
|
+
declare function semverPolicy({ beforeV1 }?: SemverPolicyOptions): ReleasePolicyFunction;
|
|
33
|
+
/** Describe a version transition without deciding whether it permits breakage. */
|
|
34
|
+
declare function versionTransition(previousVersion: string, version: string): VersionTransition;
|
|
35
|
+
/** Pure comparison; equal and older versions never permit breaking changes. */
|
|
36
|
+
declare function versionDelta(previousVersion: string, version: string, policy?: ReleasePolicy): VersionDelta;
|
|
37
|
+
/** Resolve and validate release evidence; policy is applied separately. */
|
|
38
|
+
declare function resolveReleaseDelta(config: ReleaseConfig, context: ReleaseDeltaContext): Promise<VersionTransition | undefined>;
|
|
39
|
+
export { ReleasePolicyFunction as a, VersionTransition as c, versionDelta as d, versionTransition as f, ReleasePolicy as i, resolveReleaseDelta as l, ReleaseDeltaContext as n, SemverPolicyOptions as o, ReleaseDeltaResolver as r, VersionDelta as s, ReleaseConfig as t, semverPolicy as u };
|
|
40
|
+
//# sourceMappingURL=release-D47BqRuB.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-D47BqRuB.d.ts","names":[],"sources":["../src/release.ts"],"mappings":"A,KAIY;EACX;EACA;EACA;;EAEA;IAAa;IAAiB;IAAc;;;KAEjC;EACX;EACA;EACA;;KAWW,wBACX,SAAS,wBACL,gCAAgC,QAAQ;KACjC,eAAe;EAAsB;;KACrC;EAAwB;;KACxB,yBAAyB,OAAO;KAChC,gBAAgB;cACf,6DAAa;;;;KAKd,uBAAuB,cAAc;;iBAGjC,eACf,aACE,sBAA2B;;iBAgBd,kBACf,yBACA,kBACE;;iBAWa,aACf,yBACA,iBACA,SAAQ,gBACN;;iBAuBmB,oBACrB,QAAQ,eACR,SAAS,sBACP,QAAQ"}
|