@askrjs/cli 0.0.2 → 0.0.3
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 +9 -7
- package/dist/add.js +554 -1
- package/dist/add.js.map +1 -0
- package/dist/cli.js +43 -14
- package/dist/cli.js.map +1 -1
- package/dist/discovery-Difb7Y4G.js +325 -0
- package/dist/discovery-Difb7Y4G.js.map +1 -0
- package/dist/generate.js +396 -0
- package/dist/generate.js.map +1 -0
- package/dist/openapi.js +5 -4
- package/dist/openapi.js.map +1 -1
- package/dist/planner-VAj7qlxr.js +287 -0
- package/dist/planner-VAj7qlxr.js.map +1 -0
- package/dist/range-YUs9eimn.js +127 -0
- package/dist/range-YUs9eimn.js.map +1 -0
- package/dist/registry-CyrRHRG5.js +211 -0
- package/dist/registry-CyrRHRG5.js.map +1 -0
- package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
- package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
- package/dist/specification-DXnDOC-0.js +51 -0
- package/dist/specification-DXnDOC-0.js.map +1 -0
- package/dist/templates/full-stack/AGENTS.md +0 -1
- package/dist/templates/full-stack/README.md +0 -1
- package/dist/templates/full-stack/index.html +0 -1
- package/dist/templates/full-stack/package.json +4 -2
- package/dist/templates/full-stack/server.ts +5 -9
- package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
- package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
- package/dist/templates/full-stack/src/i18n.ts +4 -4
- package/dist/templates/full-stack/src/main.tsx +4 -5
- package/dist/templates/full-stack/src/pages/home.tsx +5 -5
- package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
- package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
- package/dist/templates/full-stack/src/routes.tsx +11 -12
- package/dist/templates/full-stack/src/schemas.ts +1 -2
- package/dist/templates/full-stack/src/server/action-registry.ts +6 -10
- package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
- package/dist/templates/full-stack/src/server/app.ts +67 -57
- package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
- package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
- package/dist/templates/full-stack/src/telemetry.ts +1 -2
- package/dist/templates/full-stack/src/vite-server.d.ts +2 -3
- package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
- package/dist/templates/full-stack/tsconfig.json +0 -1
- package/dist/templates/full-stack/vite.config.ts +5 -6
- package/dist/templates/spa/AGENTS.md +1 -1
- package/dist/templates/spa/package.json +1 -1
- package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
- package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
- package/dist/templates/spa/src/styles.css +1 -1
- package/dist/templates/ssg/tests/ssg-config.test.ts +3 -3
- package/dist/templates/ssr/server.ts +4 -10
- package/dist/templates/ssr/src/entry-server.tsx +6 -4
- package/dist/update.js +284 -2
- package/dist/update.js.map +1 -0
- package/dist/writer-D8qe_7ud.js +228 -0
- package/dist/writer-D8qe_7ud.js.map +1 -0
- package/package.json +11 -15
- package/skills/askr-dashboard-charts/SKILL.md +61 -44
- package/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
- package/templates/full-stack/AGENTS.md +0 -1
- package/templates/full-stack/README.md +0 -1
- package/templates/full-stack/index.html +0 -1
- package/templates/full-stack/package.json +4 -2
- package/templates/full-stack/server.ts +5 -9
- package/templates/full-stack/src/action-authorizations.ts +2 -2
- package/templates/full-stack/src/actions/create-message.ts +5 -5
- package/templates/full-stack/src/i18n.ts +4 -4
- package/templates/full-stack/src/main.tsx +4 -5
- package/templates/full-stack/src/pages/home.tsx +5 -5
- package/templates/full-stack/src/pages/layout.tsx +15 -5
- package/templates/full-stack/src/pages/not-found.tsx +5 -2
- package/templates/full-stack/src/routes.tsx +11 -12
- package/templates/full-stack/src/schemas.ts +1 -2
- package/templates/full-stack/src/server/action-registry.ts +6 -10
- package/templates/full-stack/src/server/actions/create-message.ts +4 -4
- package/templates/full-stack/src/server/app.ts +67 -57
- package/templates/full-stack/src/server/dependencies.ts +10 -10
- package/templates/full-stack/src/server/entry-server.ts +3 -3
- package/templates/full-stack/src/telemetry.ts +1 -2
- package/templates/full-stack/src/vite-server.d.ts +2 -3
- package/templates/full-stack/tests/actions/create-message.test.ts +7 -8
- package/templates/full-stack/tsconfig.json +0 -1
- package/templates/full-stack/vite.config.ts +5 -6
- package/templates/spa/AGENTS.md +1 -1
- package/templates/spa/package.json +1 -1
- package/templates/spa/src/adapters/operations-client.ts +7 -2
- package/templates/spa/src/pages/app/admin-home.tsx +21 -3
- package/templates/spa/src/styles.css +1 -1
- package/templates/ssg/tests/ssg-config.test.ts +3 -3
- package/templates/ssr/server.ts +4 -10
- package/templates/ssr/src/entry-server.tsx +6 -4
- package/dist/add-DqhqRzBQ.js +0 -555
- package/dist/add-DqhqRzBQ.js.map +0 -1
- package/dist/update-DyW1na5V.js +0 -1140
- package/dist/update-DyW1na5V.js.map +0 -1
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { n as isBreakingChange, r as rewriteRange, t as analyzeRange } from "./range-YUs9eimn.js";
|
|
2
|
+
import { t as parseDependencySpecification } from "./specification-DXnDOC-0.js";
|
|
3
|
+
import semver from "semver";
|
|
4
|
+
//#region src/update/planner.ts
|
|
5
|
+
const STATUS_PRIORITY = {
|
|
6
|
+
current: 0,
|
|
7
|
+
local: 1,
|
|
8
|
+
safe: 2,
|
|
9
|
+
breaking: 3,
|
|
10
|
+
manual: 4,
|
|
11
|
+
error: 5
|
|
12
|
+
};
|
|
13
|
+
function publishedVersions(packument) {
|
|
14
|
+
return Object.keys(packument.versions ?? {}).filter((version) => semver.valid(version) !== null).sort(semver.compare);
|
|
15
|
+
}
|
|
16
|
+
function selectedTarget(packument, tag) {
|
|
17
|
+
const value = packument["dist-tags"]?.[tag];
|
|
18
|
+
return typeof value === "string" && semver.valid(value) ? value : null;
|
|
19
|
+
}
|
|
20
|
+
function plannedOccurrence(occurrence, packument, failure, selectedTag, force) {
|
|
21
|
+
const base = {
|
|
22
|
+
workspace: occurrence.workspace,
|
|
23
|
+
manifestPath: occurrence.manifestPath,
|
|
24
|
+
relativeManifestPath: occurrence.relativeManifestPath,
|
|
25
|
+
section: occurrence.section,
|
|
26
|
+
currentSpecification: occurrence.currentSpecification,
|
|
27
|
+
proposedSpecification: null,
|
|
28
|
+
allowedVersion: null
|
|
29
|
+
};
|
|
30
|
+
if (occurrence.kind === "local") return {
|
|
31
|
+
targetVersion: null,
|
|
32
|
+
occurrence: {
|
|
33
|
+
...base,
|
|
34
|
+
status: "local",
|
|
35
|
+
reason: occurrence.reason
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
if (occurrence.kind === "manual") return {
|
|
39
|
+
targetVersion: null,
|
|
40
|
+
occurrence: {
|
|
41
|
+
...base,
|
|
42
|
+
status: "manual",
|
|
43
|
+
reason: occurrence.reason
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
if (failure) return {
|
|
47
|
+
targetVersion: null,
|
|
48
|
+
occurrence: {
|
|
49
|
+
...base,
|
|
50
|
+
status: "error",
|
|
51
|
+
reason: failure
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
if (occurrence.kind === "current") return {
|
|
55
|
+
targetVersion: packument ? selectedTarget(packument, selectedTag) : null,
|
|
56
|
+
occurrence: {
|
|
57
|
+
...base,
|
|
58
|
+
status: "current",
|
|
59
|
+
reason: occurrence.reason
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (!packument) return {
|
|
63
|
+
targetVersion: null,
|
|
64
|
+
occurrence: {
|
|
65
|
+
...base,
|
|
66
|
+
status: "error",
|
|
67
|
+
reason: "package metadata is unavailable"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const targetVersion = selectedTarget(packument, selectedTag);
|
|
71
|
+
if (!targetVersion) return {
|
|
72
|
+
targetVersion: null,
|
|
73
|
+
occurrence: {
|
|
74
|
+
...base,
|
|
75
|
+
status: "error",
|
|
76
|
+
reason: `dist-tag '${selectedTag}' is not published`
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const versions = publishedVersions(packument);
|
|
80
|
+
if (!versions.includes(targetVersion)) return {
|
|
81
|
+
targetVersion: null,
|
|
82
|
+
occurrence: {
|
|
83
|
+
...base,
|
|
84
|
+
status: "error",
|
|
85
|
+
reason: `dist-tag '${selectedTag}' does not identify a published version`
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const allowedVersion = semver.maxSatisfying(versions, occurrence.currentSpecification);
|
|
89
|
+
if (!allowedVersion) return {
|
|
90
|
+
targetVersion,
|
|
91
|
+
occurrence: {
|
|
92
|
+
...base,
|
|
93
|
+
status: "manual",
|
|
94
|
+
reason: "no published version satisfies the current specification"
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
if (semver.satisfies(targetVersion, occurrence.currentSpecification) || !semver.gt(targetVersion, allowedVersion)) return {
|
|
98
|
+
targetVersion,
|
|
99
|
+
occurrence: {
|
|
100
|
+
...base,
|
|
101
|
+
allowedVersion,
|
|
102
|
+
status: "current",
|
|
103
|
+
reason: "selected target is already covered by the current specification"
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const analysis = analyzeRange(occurrence.currentSpecification);
|
|
107
|
+
if (!analysis.shape) return {
|
|
108
|
+
targetVersion,
|
|
109
|
+
occurrence: {
|
|
110
|
+
...base,
|
|
111
|
+
allowedVersion,
|
|
112
|
+
status: "manual",
|
|
113
|
+
reason: analysis.reason
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const breaking = isBreakingChange(allowedVersion, targetVersion);
|
|
117
|
+
const eligible = !breaking || force;
|
|
118
|
+
return {
|
|
119
|
+
targetVersion,
|
|
120
|
+
occurrence: {
|
|
121
|
+
...base,
|
|
122
|
+
allowedVersion,
|
|
123
|
+
proposedSpecification: eligible ? rewriteRange(analysis.shape, targetVersion, breaking) : null,
|
|
124
|
+
status: breaking ? "breaking" : "safe",
|
|
125
|
+
reason: breaking ? eligible ? "latest version is eligible for askr upgrade" : "breaking update is available via askr upgrade" : "compatible update is available"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function occurrenceKey(occurrence, packageName) {
|
|
130
|
+
return [
|
|
131
|
+
occurrence.manifestPath,
|
|
132
|
+
occurrence.section,
|
|
133
|
+
packageName ?? occurrence.package,
|
|
134
|
+
occurrence.currentSpecification
|
|
135
|
+
].join("\0");
|
|
136
|
+
}
|
|
137
|
+
function resolveSpecificationVersion(specification, packument) {
|
|
138
|
+
const versions = publishedVersions(packument);
|
|
139
|
+
const parsed = parseDependencySpecification(specification);
|
|
140
|
+
if (parsed.type === "tag") {
|
|
141
|
+
const tagged = packument["dist-tags"]?.[parsed.rawSpec];
|
|
142
|
+
return typeof tagged === "string" && semver.valid(tagged) ? tagged : null;
|
|
143
|
+
}
|
|
144
|
+
if (parsed.type === "version") return semver.valid(parsed.rawSpec);
|
|
145
|
+
if (parsed.type === "range") return semver.maxSatisfying(versions, parsed.rawSpec);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function versionMetadata(packument, version) {
|
|
149
|
+
const metadata = packument.versions?.[version];
|
|
150
|
+
return metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : null;
|
|
151
|
+
}
|
|
152
|
+
function applyPeerCompatibilityGuard(decisions, contextOccurrences, packuments) {
|
|
153
|
+
const plannedByKey = /* @__PURE__ */ new Map();
|
|
154
|
+
for (const decision of decisions) for (const occurrence of decision.occurrences) plannedByKey.set(occurrenceKey(occurrence, decision.package), occurrence);
|
|
155
|
+
const contextByWorkspace = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const occurrence of contextOccurrences) {
|
|
157
|
+
const entries = contextByWorkspace.get(occurrence.workspace) ?? [];
|
|
158
|
+
entries.push(occurrence);
|
|
159
|
+
contextByWorkspace.set(occurrence.workspace, entries);
|
|
160
|
+
}
|
|
161
|
+
for (const [workspace, context] of contextByWorkspace) {
|
|
162
|
+
const states = context.flatMap((dependency) => {
|
|
163
|
+
if (!dependency.registryManaged) return [];
|
|
164
|
+
const packument = packuments.get(dependency.package);
|
|
165
|
+
if (!packument) return [];
|
|
166
|
+
const planned = plannedByKey.get(occurrenceKey(dependency));
|
|
167
|
+
const currentVersion = resolveSpecificationVersion(dependency.currentSpecification, packument);
|
|
168
|
+
const futureVersion = resolveSpecificationVersion(planned?.proposedSpecification ?? dependency.currentSpecification, packument);
|
|
169
|
+
return currentVersion && futureVersion ? [{
|
|
170
|
+
dependency,
|
|
171
|
+
packument,
|
|
172
|
+
planned,
|
|
173
|
+
currentVersion,
|
|
174
|
+
futureVersion,
|
|
175
|
+
changed: Boolean(planned?.proposedSpecification)
|
|
176
|
+
}] : [];
|
|
177
|
+
});
|
|
178
|
+
const blockers = /* @__PURE__ */ new Map();
|
|
179
|
+
for (const provider of states) {
|
|
180
|
+
const currentPeers = versionMetadata(provider.packument, provider.currentVersion)?.peerDependencies ?? {};
|
|
181
|
+
const futurePeers = versionMetadata(provider.packument, provider.futureVersion)?.peerDependencies ?? {};
|
|
182
|
+
const peerNames = /* @__PURE__ */ new Set([...Object.keys(currentPeers), ...Object.keys(futurePeers)]);
|
|
183
|
+
for (const peerName of peerNames) {
|
|
184
|
+
const currentRequirement = currentPeers[peerName];
|
|
185
|
+
const futureRequirement = futurePeers[peerName];
|
|
186
|
+
if (futureRequirement !== void 0 && typeof futureRequirement !== "string") continue;
|
|
187
|
+
for (const peer of states.filter((state) => state.dependency.package === peerName)) {
|
|
188
|
+
const currentAccepted = typeof currentRequirement !== "string" || semver.satisfies(peer.currentVersion, currentRequirement);
|
|
189
|
+
const futureAccepted = typeof futureRequirement !== "string" || semver.satisfies(peer.futureVersion, futureRequirement);
|
|
190
|
+
if (!currentAccepted || futureAccepted) continue;
|
|
191
|
+
const reason = `${provider.dependency.package}@${provider.futureVersion} requires ${peerName}@${futureRequirement}`;
|
|
192
|
+
if (provider.changed && provider.planned) blockers.set(provider.planned, reason);
|
|
193
|
+
if (peer.changed && peer.planned) blockers.set(peer.planned, reason);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const [planned, reason] of blockers) {
|
|
198
|
+
planned.status = "manual";
|
|
199
|
+
planned.proposedSpecification = null;
|
|
200
|
+
planned.reason = reason;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function aggregateStatus(occurrences) {
|
|
205
|
+
return occurrences.reduce((status, occurrence) => STATUS_PRIORITY[occurrence.status] > STATUS_PRIORITY[status] ? occurrence.status : status, "current");
|
|
206
|
+
}
|
|
207
|
+
function summarize(decisions) {
|
|
208
|
+
const summary = {
|
|
209
|
+
packages: decisions.length,
|
|
210
|
+
occurrences: 0,
|
|
211
|
+
changedOccurrences: 0,
|
|
212
|
+
current: 0,
|
|
213
|
+
safe: 0,
|
|
214
|
+
breaking: 0,
|
|
215
|
+
local: 0,
|
|
216
|
+
manual: 0,
|
|
217
|
+
error: 0
|
|
218
|
+
};
|
|
219
|
+
for (const decision of decisions) {
|
|
220
|
+
decision.status = aggregateStatus(decision.occurrences);
|
|
221
|
+
decision.reason = decision.occurrences.find((entry) => entry.status === decision.status)?.reason ?? "";
|
|
222
|
+
summary[decision.status] += 1;
|
|
223
|
+
summary.occurrences += decision.occurrences.length;
|
|
224
|
+
summary.changedOccurrences += decision.occurrences.filter((entry) => entry.proposedSpecification).length;
|
|
225
|
+
}
|
|
226
|
+
return summary;
|
|
227
|
+
}
|
|
228
|
+
function planUpdates(options) {
|
|
229
|
+
const failures = options.failures ?? /* @__PURE__ */ new Map();
|
|
230
|
+
const tags = options.tags ?? {};
|
|
231
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
232
|
+
for (const occurrence of options.occurrences) {
|
|
233
|
+
const entries = grouped.get(occurrence.package) ?? [];
|
|
234
|
+
entries.push(occurrence);
|
|
235
|
+
grouped.set(occurrence.package, entries);
|
|
236
|
+
}
|
|
237
|
+
const decisions = [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([packageName, occurrences]) => {
|
|
238
|
+
const selectedTag = options.cliTag ?? tags[packageName] ?? "latest";
|
|
239
|
+
const planned = occurrences.map((occurrence) => plannedOccurrence(occurrence, options.packuments.get(packageName), failures.get(packageName), selectedTag, options.force ?? false));
|
|
240
|
+
const targetVersion = planned.find((entry) => entry.targetVersion)?.targetVersion ?? null;
|
|
241
|
+
const plannedOccurrences = planned.map((entry) => entry.occurrence);
|
|
242
|
+
const status = aggregateStatus(plannedOccurrences);
|
|
243
|
+
return {
|
|
244
|
+
package: packageName,
|
|
245
|
+
selectedTag,
|
|
246
|
+
targetVersion,
|
|
247
|
+
status,
|
|
248
|
+
reason: plannedOccurrences.find((entry) => entry.status === status)?.reason ?? "",
|
|
249
|
+
occurrences: plannedOccurrences
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
const selectedNames = new Set(grouped.keys());
|
|
253
|
+
for (const [packageName, failure] of [...failures].sort(([left], [right]) => left.localeCompare(right))) {
|
|
254
|
+
if (selectedNames.has(packageName)) continue;
|
|
255
|
+
const context = (options.contextOccurrences ?? []).filter((occurrence) => occurrence.package === packageName).map((occurrence) => ({
|
|
256
|
+
workspace: occurrence.workspace,
|
|
257
|
+
manifestPath: occurrence.manifestPath,
|
|
258
|
+
relativeManifestPath: occurrence.relativeManifestPath,
|
|
259
|
+
section: occurrence.section,
|
|
260
|
+
currentSpecification: occurrence.currentSpecification,
|
|
261
|
+
proposedSpecification: null,
|
|
262
|
+
allowedVersion: null,
|
|
263
|
+
status: "error",
|
|
264
|
+
reason: `peer compatibility lookup failed: ${failure}`
|
|
265
|
+
}));
|
|
266
|
+
decisions.push({
|
|
267
|
+
package: packageName,
|
|
268
|
+
selectedTag: options.cliTag ?? tags[packageName] ?? "latest",
|
|
269
|
+
targetVersion: null,
|
|
270
|
+
status: "error",
|
|
271
|
+
reason: `peer compatibility lookup failed: ${failure}`,
|
|
272
|
+
occurrences: context
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
decisions.sort((left, right) => left.package.localeCompare(right.package));
|
|
276
|
+
applyPeerCompatibilityGuard(decisions, options.contextOccurrences ?? options.occurrences, options.packuments);
|
|
277
|
+
const summary = summarize(decisions);
|
|
278
|
+
return {
|
|
279
|
+
decisions,
|
|
280
|
+
summary,
|
|
281
|
+
hasErrors: summary.error > 0
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
285
|
+
export { planUpdates };
|
|
286
|
+
|
|
287
|
+
//# sourceMappingURL=planner-VAj7qlxr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-VAj7qlxr.js","names":[],"sources":["../src/update/planner.ts"],"sourcesContent":["import semver from \"semver\";\nimport { analyzeRange, isBreakingChange, rewriteRange } from \"./range\";\nimport { parseDependencySpecification } from \"./specification\";\nimport type {\n DependencyOccurrence,\n PackageDecision,\n Packument,\n PlannedOccurrence,\n UpdatePlan,\n UpdateStatus,\n UpdateSummary,\n} from \"./types\";\n\ninterface PlannerOptions {\n occurrences: DependencyOccurrence[];\n contextOccurrences?: DependencyOccurrence[];\n packuments: Map<string, Packument>;\n failures?: Map<string, string>;\n tags?: Record<string, string>;\n cliTag?: string;\n force?: boolean;\n}\n\ninterface VersionMetadata extends Record<string, unknown> {\n peerDependencies?: Record<string, unknown>;\n}\n\nconst STATUS_PRIORITY: Record<UpdateStatus, number> = {\n current: 0,\n local: 1,\n safe: 2,\n breaking: 3,\n manual: 4,\n error: 5,\n};\n\nfunction publishedVersions(packument: Packument): string[] {\n return Object.keys(packument.versions ?? {})\n .filter((version) => semver.valid(version) !== null)\n .sort(semver.compare);\n}\n\nfunction selectedTarget(packument: Packument, tag: string): string | null {\n const value = packument[\"dist-tags\"]?.[tag];\n return typeof value === \"string\" && semver.valid(value) ? value : null;\n}\n\nfunction plannedOccurrence(\n occurrence: DependencyOccurrence,\n packument: Packument | undefined,\n failure: string | undefined,\n selectedTag: string,\n force: boolean,\n): { occurrence: PlannedOccurrence; targetVersion: string | null } {\n const base = {\n workspace: occurrence.workspace,\n manifestPath: occurrence.manifestPath,\n relativeManifestPath: occurrence.relativeManifestPath,\n section: occurrence.section,\n currentSpecification: occurrence.currentSpecification,\n proposedSpecification: null,\n allowedVersion: null,\n };\n\n if (occurrence.kind === \"local\") {\n return {\n targetVersion: null,\n occurrence: { ...base, status: \"local\", reason: occurrence.reason },\n };\n }\n if (occurrence.kind === \"manual\") {\n return {\n targetVersion: null,\n occurrence: { ...base, status: \"manual\", reason: occurrence.reason },\n };\n }\n if (failure) {\n return {\n targetVersion: null,\n occurrence: { ...base, status: \"error\", reason: failure },\n };\n }\n if (occurrence.kind === \"current\") {\n return {\n targetVersion: packument ? selectedTarget(packument, selectedTag) : null,\n occurrence: { ...base, status: \"current\", reason: occurrence.reason },\n };\n }\n if (!packument) {\n return {\n targetVersion: null,\n occurrence: { ...base, status: \"error\", reason: \"package metadata is unavailable\" },\n };\n }\n\n const targetVersion = selectedTarget(packument, selectedTag);\n if (!targetVersion) {\n return {\n targetVersion: null,\n occurrence: {\n ...base,\n status: \"error\",\n reason: `dist-tag '${selectedTag}' is not published`,\n },\n };\n }\n\n const versions = publishedVersions(packument);\n if (!versions.includes(targetVersion)) {\n return {\n targetVersion: null,\n occurrence: {\n ...base,\n status: \"error\",\n reason: `dist-tag '${selectedTag}' does not identify a published version`,\n },\n };\n }\n const allowedVersion = semver.maxSatisfying(versions, occurrence.currentSpecification);\n if (!allowedVersion) {\n return {\n targetVersion,\n occurrence: {\n ...base,\n status: \"manual\",\n reason: \"no published version satisfies the current specification\",\n },\n };\n }\n if (\n semver.satisfies(targetVersion, occurrence.currentSpecification) ||\n !semver.gt(targetVersion, allowedVersion)\n ) {\n return {\n targetVersion,\n occurrence: {\n ...base,\n allowedVersion,\n status: \"current\",\n reason: \"selected target is already covered by the current specification\",\n },\n };\n }\n\n const analysis = analyzeRange(occurrence.currentSpecification);\n if (!analysis.shape) {\n return {\n targetVersion,\n occurrence: { ...base, allowedVersion, status: \"manual\", reason: analysis.reason },\n };\n }\n\n const breaking = isBreakingChange(allowedVersion, targetVersion);\n const eligible = !breaking || force;\n return {\n targetVersion,\n occurrence: {\n ...base,\n allowedVersion,\n proposedSpecification: eligible\n ? rewriteRange(analysis.shape, targetVersion, breaking)\n : null,\n status: breaking ? \"breaking\" : \"safe\",\n reason: breaking\n ? eligible\n ? \"latest version is eligible for askr upgrade\"\n : \"breaking update is available via askr upgrade\"\n : \"compatible update is available\",\n },\n };\n}\n\nfunction occurrenceKey(\n occurrence: {\n manifestPath: string;\n section: string;\n currentSpecification: string;\n } & ({ package: string } | { package?: never }),\n packageName?: string,\n): string {\n return [\n occurrence.manifestPath,\n occurrence.section,\n packageName ?? occurrence.package,\n occurrence.currentSpecification,\n ].join(\"\\u0000\");\n}\n\nfunction resolveSpecificationVersion(specification: string, packument: Packument): string | null {\n const versions = publishedVersions(packument);\n const parsed = parseDependencySpecification(specification);\n if (parsed.type === \"tag\") {\n const tagged = packument[\"dist-tags\"]?.[parsed.rawSpec];\n return typeof tagged === \"string\" && semver.valid(tagged) ? tagged : null;\n }\n if (parsed.type === \"version\") return semver.valid(parsed.rawSpec);\n if (parsed.type === \"range\") return semver.maxSatisfying(versions, parsed.rawSpec);\n return null;\n}\n\nfunction versionMetadata(packument: Packument, version: string): VersionMetadata | null {\n const metadata = packument.versions?.[version];\n return metadata && typeof metadata === \"object\" && !Array.isArray(metadata)\n ? (metadata as VersionMetadata)\n : null;\n}\n\nfunction applyPeerCompatibilityGuard(\n decisions: PackageDecision[],\n contextOccurrences: DependencyOccurrence[],\n packuments: Map<string, Packument>,\n): void {\n const plannedByKey = new Map<string, PlannedOccurrence>();\n for (const decision of decisions) {\n for (const occurrence of decision.occurrences) {\n plannedByKey.set(occurrenceKey(occurrence, decision.package), occurrence);\n }\n }\n\n const contextByWorkspace = new Map<string, DependencyOccurrence[]>();\n for (const occurrence of contextOccurrences) {\n const entries = contextByWorkspace.get(occurrence.workspace) ?? [];\n entries.push(occurrence);\n contextByWorkspace.set(occurrence.workspace, entries);\n }\n\n for (const [workspace, context] of contextByWorkspace) {\n const states = context.flatMap((dependency) => {\n if (!dependency.registryManaged) return [];\n const packument = packuments.get(dependency.package);\n if (!packument) return [];\n const planned = plannedByKey.get(occurrenceKey(dependency));\n const currentVersion = resolveSpecificationVersion(\n dependency.currentSpecification,\n packument,\n );\n const futureSpecification = planned?.proposedSpecification ?? dependency.currentSpecification;\n const futureVersion = resolveSpecificationVersion(futureSpecification, packument);\n return currentVersion && futureVersion\n ? [\n {\n dependency,\n packument,\n planned,\n currentVersion,\n futureVersion,\n changed: Boolean(planned?.proposedSpecification),\n },\n ]\n : [];\n });\n const blockers = new Map<PlannedOccurrence, string>();\n\n for (const provider of states) {\n const currentPeers =\n versionMetadata(provider.packument, provider.currentVersion)?.peerDependencies ?? {};\n const futurePeers =\n versionMetadata(provider.packument, provider.futureVersion)?.peerDependencies ?? {};\n const peerNames = new Set([...Object.keys(currentPeers), ...Object.keys(futurePeers)]);\n for (const peerName of peerNames) {\n const currentRequirement = currentPeers[peerName];\n const futureRequirement = futurePeers[peerName];\n if (futureRequirement !== undefined && typeof futureRequirement !== \"string\") continue;\n\n for (const peer of states.filter((state) => state.dependency.package === peerName)) {\n const currentAccepted =\n typeof currentRequirement !== \"string\" ||\n semver.satisfies(peer.currentVersion, currentRequirement);\n const futureAccepted =\n typeof futureRequirement !== \"string\" ||\n semver.satisfies(peer.futureVersion, futureRequirement);\n if (!currentAccepted || futureAccepted) continue;\n\n const reason = `${provider.dependency.package}@${provider.futureVersion} requires ${peerName}@${futureRequirement}`;\n if (provider.changed && provider.planned) blockers.set(provider.planned, reason);\n if (peer.changed && peer.planned) blockers.set(peer.planned, reason);\n }\n }\n }\n\n for (const [planned, reason] of blockers) {\n planned.status = \"manual\";\n planned.proposedSpecification = null;\n planned.reason = reason;\n }\n\n void workspace;\n }\n}\n\nfunction aggregateStatus(occurrences: PlannedOccurrence[]): UpdateStatus {\n return occurrences.reduce<UpdateStatus>(\n (status, occurrence) =>\n STATUS_PRIORITY[occurrence.status] > STATUS_PRIORITY[status] ? occurrence.status : status,\n \"current\",\n );\n}\n\nfunction summarize(decisions: PackageDecision[]): UpdateSummary {\n const summary: UpdateSummary = {\n packages: decisions.length,\n occurrences: 0,\n changedOccurrences: 0,\n current: 0,\n safe: 0,\n breaking: 0,\n local: 0,\n manual: 0,\n error: 0,\n };\n for (const decision of decisions) {\n decision.status = aggregateStatus(decision.occurrences);\n decision.reason =\n decision.occurrences.find((entry) => entry.status === decision.status)?.reason ?? \"\";\n summary[decision.status] += 1;\n summary.occurrences += decision.occurrences.length;\n summary.changedOccurrences += decision.occurrences.filter(\n (entry) => entry.proposedSpecification,\n ).length;\n }\n return summary;\n}\n\nexport function planUpdates(options: PlannerOptions): UpdatePlan {\n const failures = options.failures ?? new Map<string, string>();\n const tags = options.tags ?? {};\n const grouped = new Map<string, DependencyOccurrence[]>();\n for (const occurrence of options.occurrences) {\n const entries = grouped.get(occurrence.package) ?? [];\n entries.push(occurrence);\n grouped.set(occurrence.package, entries);\n }\n\n const decisions = [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([packageName, occurrences]): PackageDecision => {\n const selectedTag = options.cliTag ?? tags[packageName] ?? \"latest\";\n const planned = occurrences.map((occurrence) =>\n plannedOccurrence(\n occurrence,\n options.packuments.get(packageName),\n failures.get(packageName),\n selectedTag,\n options.force ?? false,\n ),\n );\n const targetVersion = planned.find((entry) => entry.targetVersion)?.targetVersion ?? null;\n const plannedOccurrences = planned.map((entry) => entry.occurrence);\n const status = aggregateStatus(plannedOccurrences);\n return {\n package: packageName,\n selectedTag,\n targetVersion,\n status,\n reason: plannedOccurrences.find((entry) => entry.status === status)?.reason ?? \"\",\n occurrences: plannedOccurrences,\n };\n });\n\n const selectedNames = new Set(grouped.keys());\n for (const [packageName, failure] of [...failures].sort(([left], [right]) =>\n left.localeCompare(right),\n )) {\n if (selectedNames.has(packageName)) continue;\n const context = (options.contextOccurrences ?? [])\n .filter((occurrence) => occurrence.package === packageName)\n .map(\n (occurrence): PlannedOccurrence => ({\n workspace: occurrence.workspace,\n manifestPath: occurrence.manifestPath,\n relativeManifestPath: occurrence.relativeManifestPath,\n section: occurrence.section,\n currentSpecification: occurrence.currentSpecification,\n proposedSpecification: null,\n allowedVersion: null,\n status: \"error\",\n reason: `peer compatibility lookup failed: ${failure}`,\n }),\n );\n decisions.push({\n package: packageName,\n selectedTag: options.cliTag ?? tags[packageName] ?? \"latest\",\n targetVersion: null,\n status: \"error\",\n reason: `peer compatibility lookup failed: ${failure}`,\n occurrences: context,\n });\n }\n decisions.sort((left, right) => left.package.localeCompare(right.package));\n\n applyPeerCompatibilityGuard(\n decisions,\n options.contextOccurrences ?? options.occurrences,\n options.packuments,\n );\n const summary = summarize(decisions);\n return { decisions, summary, hasErrors: summary.error > 0 };\n}\n"],"mappings":";;;;AA2BA,MAAM,kBAAgD;CACpD,SAAS;CACT,OAAO;CACP,MAAM;CACN,UAAU;CACV,QAAQ;CACR,OAAO;AACT;AAEA,SAAS,kBAAkB,WAAgC;CACzD,OAAO,OAAO,KAAK,UAAU,YAAY,CAAC,CAAC,CAAC,CACzC,QAAQ,YAAY,OAAO,MAAM,OAAO,MAAM,IAAI,CAAC,CACnD,KAAK,OAAO,OAAO;AACxB;AAEA,SAAS,eAAe,WAAsB,KAA4B;CACxE,MAAM,QAAQ,UAAU,YAAY,GAAG;CACvC,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,IAAI,QAAQ;AACpE;AAEA,SAAS,kBACP,YACA,WACA,SACA,aACA,OACiE;CACjE,MAAM,OAAO;EACX,WAAW,WAAW;EACtB,cAAc,WAAW;EACzB,sBAAsB,WAAW;EACjC,SAAS,WAAW;EACpB,sBAAsB,WAAW;EACjC,uBAAuB;EACvB,gBAAgB;CAClB;CAEA,IAAI,WAAW,SAAS,SACtB,OAAO;EACL,eAAe;EACf,YAAY;GAAE,GAAG;GAAM,QAAQ;GAAS,QAAQ,WAAW;EAAO;CACpE;CAEF,IAAI,WAAW,SAAS,UACtB,OAAO;EACL,eAAe;EACf,YAAY;GAAE,GAAG;GAAM,QAAQ;GAAU,QAAQ,WAAW;EAAO;CACrE;CAEF,IAAI,SACF,OAAO;EACL,eAAe;EACf,YAAY;GAAE,GAAG;GAAM,QAAQ;GAAS,QAAQ;EAAQ;CAC1D;CAEF,IAAI,WAAW,SAAS,WACtB,OAAO;EACL,eAAe,YAAY,eAAe,WAAW,WAAW,IAAI;EACpE,YAAY;GAAE,GAAG;GAAM,QAAQ;GAAW,QAAQ,WAAW;EAAO;CACtE;CAEF,IAAI,CAAC,WACH,OAAO;EACL,eAAe;EACf,YAAY;GAAE,GAAG;GAAM,QAAQ;GAAS,QAAQ;EAAkC;CACpF;CAGF,MAAM,gBAAgB,eAAe,WAAW,WAAW;CAC3D,IAAI,CAAC,eACH,OAAO;EACL,eAAe;EACf,YAAY;GACV,GAAG;GACH,QAAQ;GACR,QAAQ,aAAa,YAAY;EACnC;CACF;CAGF,MAAM,WAAW,kBAAkB,SAAS;CAC5C,IAAI,CAAC,SAAS,SAAS,aAAa,GAClC,OAAO;EACL,eAAe;EACf,YAAY;GACV,GAAG;GACH,QAAQ;GACR,QAAQ,aAAa,YAAY;EACnC;CACF;CAEF,MAAM,iBAAiB,OAAO,cAAc,UAAU,WAAW,oBAAoB;CACrF,IAAI,CAAC,gBACH,OAAO;EACL;EACA,YAAY;GACV,GAAG;GACH,QAAQ;GACR,QAAQ;EACV;CACF;CAEF,IACE,OAAO,UAAU,eAAe,WAAW,oBAAoB,KAC/D,CAAC,OAAO,GAAG,eAAe,cAAc,GAExC,OAAO;EACL;EACA,YAAY;GACV,GAAG;GACH;GACA,QAAQ;GACR,QAAQ;EACV;CACF;CAGF,MAAM,WAAW,aAAa,WAAW,oBAAoB;CAC7D,IAAI,CAAC,SAAS,OACZ,OAAO;EACL;EACA,YAAY;GAAE,GAAG;GAAM;GAAgB,QAAQ;GAAU,QAAQ,SAAS;EAAO;CACnF;CAGF,MAAM,WAAW,iBAAiB,gBAAgB,aAAa;CAC/D,MAAM,WAAW,CAAC,YAAY;CAC9B,OAAO;EACL;EACA,YAAY;GACV,GAAG;GACH;GACA,uBAAuB,WACnB,aAAa,SAAS,OAAO,eAAe,QAAQ,IACpD;GACJ,QAAQ,WAAW,aAAa;GAChC,QAAQ,WACJ,WACE,gDACA,kDACF;EACN;CACF;AACF;AAEA,SAAS,cACP,YAKA,aACQ;CACR,OAAO;EACL,WAAW;EACX,WAAW;EACX,eAAe,WAAW;EAC1B,WAAW;CACb,CAAC,CAAC,KAAK,IAAQ;AACjB;AAEA,SAAS,4BAA4B,eAAuB,WAAqC;CAC/F,MAAM,WAAW,kBAAkB,SAAS;CAC5C,MAAM,SAAS,6BAA6B,aAAa;CACzD,IAAI,OAAO,SAAS,OAAO;EACzB,MAAM,SAAS,UAAU,YAAY,GAAG,OAAO;EAC/C,OAAO,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,IAAI,SAAS;CACvE;CACA,IAAI,OAAO,SAAS,WAAW,OAAO,OAAO,MAAM,OAAO,OAAO;CACjE,IAAI,OAAO,SAAS,SAAS,OAAO,OAAO,cAAc,UAAU,OAAO,OAAO;CACjF,OAAO;AACT;AAEA,SAAS,gBAAgB,WAAsB,SAAyC;CACtF,MAAM,WAAW,UAAU,WAAW;CACtC,OAAO,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,IACrE,WACD;AACN;AAEA,SAAS,4BACP,WACA,oBACA,YACM;CACN,MAAM,+BAAe,IAAI,IAA+B;CACxD,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,cAAc,SAAS,aAChC,aAAa,IAAI,cAAc,YAAY,SAAS,OAAO,GAAG,UAAU;CAI5E,MAAM,qCAAqB,IAAI,IAAoC;CACnE,KAAK,MAAM,cAAc,oBAAoB;EAC3C,MAAM,UAAU,mBAAmB,IAAI,WAAW,SAAS,KAAK,CAAC;EACjE,QAAQ,KAAK,UAAU;EACvB,mBAAmB,IAAI,WAAW,WAAW,OAAO;CACtD;CAEA,KAAK,MAAM,CAAC,WAAW,YAAY,oBAAoB;EACrD,MAAM,SAAS,QAAQ,SAAS,eAAe;GAC7C,IAAI,CAAC,WAAW,iBAAiB,OAAO,CAAC;GACzC,MAAM,YAAY,WAAW,IAAI,WAAW,OAAO;GACnD,IAAI,CAAC,WAAW,OAAO,CAAC;GACxB,MAAM,UAAU,aAAa,IAAI,cAAc,UAAU,CAAC;GAC1D,MAAM,iBAAiB,4BACrB,WAAW,sBACX,SACF;GAEA,MAAM,gBAAgB,4BADM,SAAS,yBAAyB,WAAW,sBACF,SAAS;GAChF,OAAO,kBAAkB,gBACrB,CACE;IACE;IACA;IACA;IACA;IACA;IACA,SAAS,QAAQ,SAAS,qBAAqB;GACjD,CACF,IACA,CAAC;EACP,CAAC;EACD,MAAM,2BAAW,IAAI,IAA+B;EAEpD,KAAK,MAAM,YAAY,QAAQ;GAC7B,MAAM,eACJ,gBAAgB,SAAS,WAAW,SAAS,cAAc,CAAC,EAAE,oBAAoB,CAAC;GACrF,MAAM,cACJ,gBAAgB,SAAS,WAAW,SAAS,aAAa,CAAC,EAAE,oBAAoB,CAAC;GACpF,MAAM,4BAAY,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,YAAY,GAAG,GAAG,OAAO,KAAK,WAAW,CAAC,CAAC;GACrF,KAAK,MAAM,YAAY,WAAW;IAChC,MAAM,qBAAqB,aAAa;IACxC,MAAM,oBAAoB,YAAY;IACtC,IAAI,sBAAsB,KAAA,KAAa,OAAO,sBAAsB,UAAU;IAE9E,KAAK,MAAM,QAAQ,OAAO,QAAQ,UAAU,MAAM,WAAW,YAAY,QAAQ,GAAG;KAClF,MAAM,kBACJ,OAAO,uBAAuB,YAC9B,OAAO,UAAU,KAAK,gBAAgB,kBAAkB;KAC1D,MAAM,iBACJ,OAAO,sBAAsB,YAC7B,OAAO,UAAU,KAAK,eAAe,iBAAiB;KACxD,IAAI,CAAC,mBAAmB,gBAAgB;KAExC,MAAM,SAAS,GAAG,SAAS,WAAW,QAAQ,GAAG,SAAS,cAAc,YAAY,SAAS,GAAG;KAChG,IAAI,SAAS,WAAW,SAAS,SAAS,SAAS,IAAI,SAAS,SAAS,MAAM;KAC/E,IAAI,KAAK,WAAW,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS,MAAM;IACrE;GACF;EACF;EAEA,KAAK,MAAM,CAAC,SAAS,WAAW,UAAU;GACxC,QAAQ,SAAS;GACjB,QAAQ,wBAAwB;GAChC,QAAQ,SAAS;EACnB;CAGF;AACF;AAEA,SAAS,gBAAgB,aAAgD;CACvE,OAAO,YAAY,QAChB,QAAQ,eACP,gBAAgB,WAAW,UAAU,gBAAgB,UAAU,WAAW,SAAS,QACrF,SACF;AACF;AAEA,SAAS,UAAU,WAA6C;CAC9D,MAAM,UAAyB;EAC7B,UAAU,UAAU;EACpB,aAAa;EACb,oBAAoB;EACpB,SAAS;EACT,MAAM;EACN,UAAU;EACV,OAAO;EACP,QAAQ;EACR,OAAO;CACT;CACA,KAAK,MAAM,YAAY,WAAW;EAChC,SAAS,SAAS,gBAAgB,SAAS,WAAW;EACtD,SAAS,SACP,SAAS,YAAY,MAAM,UAAU,MAAM,WAAW,SAAS,MAAM,CAAC,EAAE,UAAU;EACpF,QAAQ,SAAS,WAAW;EAC5B,QAAQ,eAAe,SAAS,YAAY;EAC5C,QAAQ,sBAAsB,SAAS,YAAY,QAChD,UAAU,MAAM,qBACnB,CAAC,CAAC;CACJ;CACA,OAAO;AACT;AAEA,SAAgB,YAAY,SAAqC;CAC/D,MAAM,WAAW,QAAQ,4BAAY,IAAI,IAAoB;CAC7D,MAAM,OAAO,QAAQ,QAAQ,CAAC;CAC9B,MAAM,0BAAU,IAAI,IAAoC;CACxD,KAAK,MAAM,cAAc,QAAQ,aAAa;EAC5C,MAAM,UAAU,QAAQ,IAAI,WAAW,OAAO,KAAK,CAAC;EACpD,QAAQ,KAAK,UAAU;EACvB,QAAQ,IAAI,WAAW,SAAS,OAAO;CACzC;CAEA,MAAM,YAAY,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CACrC,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,KAAK,CAAC,CAAC,CACpD,KAAK,CAAC,aAAa,iBAAkC;EACpD,MAAM,cAAc,QAAQ,UAAU,KAAK,gBAAgB;EAC3D,MAAM,UAAU,YAAY,KAAK,eAC/B,kBACE,YACA,QAAQ,WAAW,IAAI,WAAW,GAClC,SAAS,IAAI,WAAW,GACxB,aACA,QAAQ,SAAS,KACnB,CACF;EACA,MAAM,gBAAgB,QAAQ,MAAM,UAAU,MAAM,aAAa,CAAC,EAAE,iBAAiB;EACrF,MAAM,qBAAqB,QAAQ,KAAK,UAAU,MAAM,UAAU;EAClE,MAAM,SAAS,gBAAgB,kBAAkB;EACjD,OAAO;GACL,SAAS;GACT;GACA;GACA;GACA,QAAQ,mBAAmB,MAAM,UAAU,MAAM,WAAW,MAAM,CAAC,EAAE,UAAU;GAC/E,aAAa;EACf;CACF,CAAC;CAEH,MAAM,gBAAgB,IAAI,IAAI,QAAQ,KAAK,CAAC;CAC5C,KAAK,MAAM,CAAC,aAAa,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAChE,KAAK,cAAc,KAAK,CAC1B,GAAG;EACD,IAAI,cAAc,IAAI,WAAW,GAAG;EACpC,MAAM,WAAW,QAAQ,sBAAsB,CAAC,EAAA,CAC7C,QAAQ,eAAe,WAAW,YAAY,WAAW,CAAC,CAC1D,KACE,gBAAmC;GAClC,WAAW,WAAW;GACtB,cAAc,WAAW;GACzB,sBAAsB,WAAW;GACjC,SAAS,WAAW;GACpB,sBAAsB,WAAW;GACjC,uBAAuB;GACvB,gBAAgB;GAChB,QAAQ;GACR,QAAQ,qCAAqC;EAC/C,EACF;EACF,UAAU,KAAK;GACb,SAAS;GACT,aAAa,QAAQ,UAAU,KAAK,gBAAgB;GACpD,eAAe;GACf,QAAQ;GACR,QAAQ,qCAAqC;GAC7C,aAAa;EACf,CAAC;CACH;CACA,UAAU,MAAM,MAAM,UAAU,KAAK,QAAQ,cAAc,MAAM,OAAO,CAAC;CAEzE,4BACE,WACA,QAAQ,sBAAsB,QAAQ,aACtC,QAAQ,UACV;CACA,MAAM,UAAU,UAAU,SAAS;CACnC,OAAO;EAAE;EAAW;EAAS,WAAW,QAAQ,QAAQ;CAAE;AAC5D"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
//#region src/update/range.ts
|
|
3
|
+
const FULL_VERSION = String.raw`\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
4
|
+
const PARTIAL_VERSION = String.raw`\d+(?:\.\d+){0,2}`;
|
|
5
|
+
function analyzeAtomicRange(specification) {
|
|
6
|
+
const value = specification.trim();
|
|
7
|
+
if (/^(?:\*|x|X)$/.test(value)) return {
|
|
8
|
+
shape: null,
|
|
9
|
+
tracking: true,
|
|
10
|
+
reason: "wildcard range tracks the selected tag"
|
|
11
|
+
};
|
|
12
|
+
if (new RegExp(`^${FULL_VERSION}$`).test(value) && semver.valid(value)) return {
|
|
13
|
+
shape: { kind: "exact" },
|
|
14
|
+
tracking: false,
|
|
15
|
+
reason: ""
|
|
16
|
+
};
|
|
17
|
+
const operator = value.match(new RegExp(`^([~^])\\s*(${FULL_VERSION}|${PARTIAL_VERSION})$`));
|
|
18
|
+
if (operator && semver.validRange(value)) return {
|
|
19
|
+
shape: {
|
|
20
|
+
kind: "operator",
|
|
21
|
+
operator: operator[1]
|
|
22
|
+
},
|
|
23
|
+
tracking: false,
|
|
24
|
+
reason: ""
|
|
25
|
+
};
|
|
26
|
+
const bounded = value.match(/^((?:>=|>)\s*\d+(?:\.\d+){0,2})\s+(?:<|<=)\s*\d+(?:\.\d+){0,2}$/);
|
|
27
|
+
if (bounded && semver.validRange(value)) return {
|
|
28
|
+
shape: {
|
|
29
|
+
kind: "bounded",
|
|
30
|
+
lower: bounded[1].replace(/\s+/g, "")
|
|
31
|
+
},
|
|
32
|
+
tracking: false,
|
|
33
|
+
reason: ""
|
|
34
|
+
};
|
|
35
|
+
const xRange = value.match(/^(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?$/);
|
|
36
|
+
if (xRange && semver.validRange(value)) {
|
|
37
|
+
const parts = xRange.slice(1).filter((part) => part !== void 0);
|
|
38
|
+
return {
|
|
39
|
+
shape: {
|
|
40
|
+
kind: "x",
|
|
41
|
+
parts,
|
|
42
|
+
wildcard: parts.find((part) => /^[xX*]$/.test(part)) ?? null
|
|
43
|
+
},
|
|
44
|
+
tracking: false,
|
|
45
|
+
reason: ""
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
shape: null,
|
|
50
|
+
tracking: false,
|
|
51
|
+
reason: "unsupported complex semver range"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function analyzeRange(specification) {
|
|
55
|
+
const clauses = specification.split("||").map((clause) => clause.trim());
|
|
56
|
+
if (clauses.length === 1) return analyzeAtomicRange(specification);
|
|
57
|
+
if (clauses.some((clause) => clause.length === 0)) return {
|
|
58
|
+
shape: null,
|
|
59
|
+
tracking: false,
|
|
60
|
+
reason: "unsupported complex semver range"
|
|
61
|
+
};
|
|
62
|
+
const analyzed = clauses.map(analyzeAtomicRange);
|
|
63
|
+
if (analyzed.some((entry) => !entry.shape || entry.shape.kind === "union" || entry.tracking)) return {
|
|
64
|
+
shape: null,
|
|
65
|
+
tracking: false,
|
|
66
|
+
reason: "unsupported complex semver union"
|
|
67
|
+
};
|
|
68
|
+
const minimums = clauses.map((clause) => semver.minVersion(clause));
|
|
69
|
+
if (minimums.some((version) => version === null)) return {
|
|
70
|
+
shape: null,
|
|
71
|
+
tracking: false,
|
|
72
|
+
reason: "unsupported complex semver union"
|
|
73
|
+
};
|
|
74
|
+
let highestIndex = 0;
|
|
75
|
+
for (let index = 1; index < minimums.length; index += 1) if (semver.gt(minimums[index], minimums[highestIndex])) highestIndex = index;
|
|
76
|
+
return {
|
|
77
|
+
shape: {
|
|
78
|
+
kind: "union",
|
|
79
|
+
clauses: analyzed.map((entry) => entry.shape),
|
|
80
|
+
sourceClauses: clauses,
|
|
81
|
+
highestIndex
|
|
82
|
+
},
|
|
83
|
+
tracking: false,
|
|
84
|
+
reason: ""
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function isBreakingChange(allowedVersion, targetVersion) {
|
|
88
|
+
const allowed = new semver.SemVer(allowedVersion);
|
|
89
|
+
const target = new semver.SemVer(targetVersion);
|
|
90
|
+
if (allowed.major !== target.major) return true;
|
|
91
|
+
return allowed.major === 0 && allowed.minor !== target.minor;
|
|
92
|
+
}
|
|
93
|
+
function nextBreakingBoundary(version) {
|
|
94
|
+
const parsed = new semver.SemVer(version);
|
|
95
|
+
return parsed.major === 0 ? `0.${parsed.minor + 1}.0` : `${parsed.major + 1}.0.0`;
|
|
96
|
+
}
|
|
97
|
+
function rewriteXRange(shape, target) {
|
|
98
|
+
const parsed = new semver.SemVer(target);
|
|
99
|
+
const count = shape.parts.length;
|
|
100
|
+
if (shape.wildcard) {
|
|
101
|
+
const wildcardIndex = shape.parts.findIndex((part) => /^[xX*]$/.test(part));
|
|
102
|
+
if (wildcardIndex === 0) return shape.wildcard;
|
|
103
|
+
if (wildcardIndex === 1) return `${parsed.major}.${shape.wildcard}`;
|
|
104
|
+
return `${parsed.major}.${parsed.minor}.${shape.wildcard}`;
|
|
105
|
+
}
|
|
106
|
+
if (count === 1) return String(parsed.major);
|
|
107
|
+
return `${parsed.major}.${parsed.minor}`;
|
|
108
|
+
}
|
|
109
|
+
function rewriteAtomic(shape, target, forcedBreaking) {
|
|
110
|
+
if (shape.kind === "exact") return target;
|
|
111
|
+
if (shape.kind === "operator") return `${shape.operator}${target}`;
|
|
112
|
+
if (shape.kind === "x") return rewriteXRange(shape, target);
|
|
113
|
+
const boundary = nextBreakingBoundary(target);
|
|
114
|
+
return forcedBreaking ? `>=${target} <${boundary}` : `${shape.lower} <${boundary}`;
|
|
115
|
+
}
|
|
116
|
+
function rewriteRange(shape, target, forcedBreaking) {
|
|
117
|
+
if (shape.kind !== "union") return rewriteAtomic(shape, target, forcedBreaking);
|
|
118
|
+
const highestShape = shape.clauses[shape.highestIndex];
|
|
119
|
+
if (forcedBreaking) return rewriteAtomic(highestShape, target, true);
|
|
120
|
+
const rewritten = [...shape.sourceClauses];
|
|
121
|
+
rewritten[shape.highestIndex] = rewriteAtomic(highestShape, target, false);
|
|
122
|
+
return rewritten.join(" || ");
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { isBreakingChange as n, rewriteRange as r, analyzeRange as t };
|
|
126
|
+
|
|
127
|
+
//# sourceMappingURL=range-YUs9eimn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"range-YUs9eimn.js","names":[],"sources":["../src/update/range.ts"],"sourcesContent":["import semver from \"semver\";\n\nexport type AtomicRangeShape =\n | { kind: \"exact\" }\n | { kind: \"operator\"; operator: \"^\" | \"~\" }\n | {\n kind: \"x\";\n parts: string[];\n wildcard: \"x\" | \"X\" | \"*\" | null;\n }\n | { kind: \"bounded\"; lower: string };\n\nexport type RangeShape =\n | AtomicRangeShape\n | { kind: \"union\"; clauses: AtomicRangeShape[]; sourceClauses: string[]; highestIndex: number };\n\nexport interface RangeAnalysis {\n shape: RangeShape | null;\n tracking: boolean;\n reason: string;\n}\n\nconst FULL_VERSION = String.raw`\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?`;\nconst PARTIAL_VERSION = String.raw`\\d+(?:\\.\\d+){0,2}`;\n\nfunction analyzeAtomicRange(specification: string): RangeAnalysis {\n const value = specification.trim();\n\n if (/^(?:\\*|x|X)$/.test(value)) {\n return { shape: null, tracking: true, reason: \"wildcard range tracks the selected tag\" };\n }\n\n if (new RegExp(`^${FULL_VERSION}$`).test(value) && semver.valid(value)) {\n return { shape: { kind: \"exact\" }, tracking: false, reason: \"\" };\n }\n\n const operator = value.match(new RegExp(`^([~^])\\\\s*(${FULL_VERSION}|${PARTIAL_VERSION})$`));\n if (operator && semver.validRange(value)) {\n return {\n shape: { kind: \"operator\", operator: operator[1] as \"^\" | \"~\" },\n tracking: false,\n reason: \"\",\n };\n }\n\n const bounded = value.match(/^((?:>=|>)\\s*\\d+(?:\\.\\d+){0,2})\\s+(?:<|<=)\\s*\\d+(?:\\.\\d+){0,2}$/);\n if (bounded && semver.validRange(value)) {\n return {\n shape: { kind: \"bounded\", lower: bounded[1].replace(/\\s+/g, \"\") },\n tracking: false,\n reason: \"\",\n };\n }\n\n const xRange = value.match(/^(\\d+|[xX*])(?:\\.(\\d+|[xX*]))?(?:\\.(\\d+|[xX*]))?$/);\n if (xRange && semver.validRange(value)) {\n const parts = xRange.slice(1).filter((part): part is string => part !== undefined);\n const explicitWildcard = parts.find((part) => /^[xX*]$/.test(part));\n return {\n shape: {\n kind: \"x\",\n parts,\n wildcard: (explicitWildcard as \"x\" | \"X\" | \"*\" | undefined) ?? null,\n },\n tracking: false,\n reason: \"\",\n };\n }\n\n return {\n shape: null,\n tracking: false,\n reason: \"unsupported complex semver range\",\n };\n}\n\nexport function analyzeRange(specification: string): RangeAnalysis {\n const clauses = specification.split(\"||\").map((clause) => clause.trim());\n if (clauses.length === 1) return analyzeAtomicRange(specification);\n\n if (clauses.some((clause) => clause.length === 0)) {\n return { shape: null, tracking: false, reason: \"unsupported complex semver range\" };\n }\n\n const analyzed = clauses.map(analyzeAtomicRange);\n if (analyzed.some((entry) => !entry.shape || entry.shape.kind === \"union\" || entry.tracking)) {\n return { shape: null, tracking: false, reason: \"unsupported complex semver union\" };\n }\n\n const minimums = clauses.map((clause) => semver.minVersion(clause));\n if (minimums.some((version) => version === null)) {\n return { shape: null, tracking: false, reason: \"unsupported complex semver union\" };\n }\n\n let highestIndex = 0;\n for (let index = 1; index < minimums.length; index += 1) {\n if (semver.gt(minimums[index]!, minimums[highestIndex]!)) highestIndex = index;\n }\n\n return {\n shape: {\n kind: \"union\",\n clauses: analyzed.map((entry) => entry.shape as AtomicRangeShape),\n sourceClauses: clauses,\n highestIndex,\n },\n tracking: false,\n reason: \"\",\n };\n}\n\nexport function isBreakingChange(allowedVersion: string, targetVersion: string): boolean {\n const allowed = new semver.SemVer(allowedVersion);\n const target = new semver.SemVer(targetVersion);\n if (allowed.major !== target.major) return true;\n return allowed.major === 0 && allowed.minor !== target.minor;\n}\n\nexport function nextBreakingBoundary(version: string): string {\n const parsed = new semver.SemVer(version);\n return parsed.major === 0 ? `0.${parsed.minor + 1}.0` : `${parsed.major + 1}.0.0`;\n}\n\nfunction rewriteXRange(shape: Extract<AtomicRangeShape, { kind: \"x\" }>, target: string): string {\n const parsed = new semver.SemVer(target);\n const count = shape.parts.length;\n\n if (shape.wildcard) {\n const wildcardIndex = shape.parts.findIndex((part) => /^[xX*]$/.test(part));\n if (wildcardIndex === 0) return shape.wildcard;\n if (wildcardIndex === 1) return `${parsed.major}.${shape.wildcard}`;\n return `${parsed.major}.${parsed.minor}.${shape.wildcard}`;\n }\n\n if (count === 1) return String(parsed.major);\n return `${parsed.major}.${parsed.minor}`;\n}\n\nfunction rewriteAtomic(shape: AtomicRangeShape, target: string, forcedBreaking: boolean): string {\n if (shape.kind === \"exact\") return target;\n if (shape.kind === \"operator\") return `${shape.operator}${target}`;\n if (shape.kind === \"x\") return rewriteXRange(shape, target);\n\n const boundary = nextBreakingBoundary(target);\n return forcedBreaking ? `>=${target} <${boundary}` : `${shape.lower} <${boundary}`;\n}\n\nexport function rewriteRange(shape: RangeShape, target: string, forcedBreaking: boolean): string {\n if (shape.kind !== \"union\") return rewriteAtomic(shape, target, forcedBreaking);\n\n const highestShape = shape.clauses[shape.highestIndex];\n if (forcedBreaking) return rewriteAtomic(highestShape, target, true);\n\n const rewritten = [...shape.sourceClauses];\n rewritten[shape.highestIndex] = rewriteAtomic(highestShape, target, false);\n return rewritten.join(\" || \");\n}\n"],"mappings":";;AAsBA,MAAM,eAAe,OAAO,GAAG;AAC/B,MAAM,kBAAkB,OAAO,GAAG;AAElC,SAAS,mBAAmB,eAAsC;CAChE,MAAM,QAAQ,cAAc,KAAK;CAEjC,IAAI,eAAe,KAAK,KAAK,GAC3B,OAAO;EAAE,OAAO;EAAM,UAAU;EAAM,QAAQ;CAAyC;CAGzF,IAAI,IAAI,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC,KAAK,KAAK,KAAK,OAAO,MAAM,KAAK,GACnE,OAAO;EAAE,OAAO,EAAE,MAAM,QAAQ;EAAG,UAAU;EAAO,QAAQ;CAAG;CAGjE,MAAM,WAAW,MAAM,MAAM,IAAI,OAAO,eAAe,aAAa,GAAG,gBAAgB,GAAG,CAAC;CAC3F,IAAI,YAAY,OAAO,WAAW,KAAK,GACrC,OAAO;EACL,OAAO;GAAE,MAAM;GAAY,UAAU,SAAS;EAAgB;EAC9D,UAAU;EACV,QAAQ;CACV;CAGF,MAAM,UAAU,MAAM,MAAM,iEAAiE;CAC7F,IAAI,WAAW,OAAO,WAAW,KAAK,GACpC,OAAO;EACL,OAAO;GAAE,MAAM;GAAW,OAAO,QAAQ,EAAE,CAAC,QAAQ,QAAQ,EAAE;EAAE;EAChE,UAAU;EACV,QAAQ;CACV;CAGF,MAAM,SAAS,MAAM,MAAM,mDAAmD;CAC9E,IAAI,UAAU,OAAO,WAAW,KAAK,GAAG;EACtC,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,SAAyB,SAAS,KAAA,CAAS;EAEjF,OAAO;GACL,OAAO;IACL,MAAM;IACN;IACA,UALqB,MAAM,MAAM,SAAS,UAAU,KAAK,IAAI,CAKnC,KAAqC;GACjE;GACA,UAAU;GACV,QAAQ;EACV;CACF;CAEA,OAAO;EACL,OAAO;EACP,UAAU;EACV,QAAQ;CACV;AACF;AAEA,SAAgB,aAAa,eAAsC;CACjE,MAAM,UAAU,cAAc,MAAM,IAAI,CAAC,CAAC,KAAK,WAAW,OAAO,KAAK,CAAC;CACvE,IAAI,QAAQ,WAAW,GAAG,OAAO,mBAAmB,aAAa;CAEjE,IAAI,QAAQ,MAAM,WAAW,OAAO,WAAW,CAAC,GAC9C,OAAO;EAAE,OAAO;EAAM,UAAU;EAAO,QAAQ;CAAmC;CAGpF,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,IAAI,SAAS,MAAM,UAAU,CAAC,MAAM,SAAS,MAAM,MAAM,SAAS,WAAW,MAAM,QAAQ,GACzF,OAAO;EAAE,OAAO;EAAM,UAAU;EAAO,QAAQ;CAAmC;CAGpF,MAAM,WAAW,QAAQ,KAAK,WAAW,OAAO,WAAW,MAAM,CAAC;CAClE,IAAI,SAAS,MAAM,YAAY,YAAY,IAAI,GAC7C,OAAO;EAAE,OAAO;EAAM,UAAU;EAAO,QAAQ;CAAmC;CAGpF,IAAI,eAAe;CACnB,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GACpD,IAAI,OAAO,GAAG,SAAS,QAAS,SAAS,aAAc,GAAG,eAAe;CAG3E,OAAO;EACL,OAAO;GACL,MAAM;GACN,SAAS,SAAS,KAAK,UAAU,MAAM,KAAyB;GAChE,eAAe;GACf;EACF;EACA,UAAU;EACV,QAAQ;CACV;AACF;AAEA,SAAgB,iBAAiB,gBAAwB,eAAgC;CACvF,MAAM,UAAU,IAAI,OAAO,OAAO,cAAc;CAChD,MAAM,SAAS,IAAI,OAAO,OAAO,aAAa;CAC9C,IAAI,QAAQ,UAAU,OAAO,OAAO,OAAO;CAC3C,OAAO,QAAQ,UAAU,KAAK,QAAQ,UAAU,OAAO;AACzD;AAEA,SAAgB,qBAAqB,SAAyB;CAC5D,MAAM,SAAS,IAAI,OAAO,OAAO,OAAO;CACxC,OAAO,OAAO,UAAU,IAAI,KAAK,OAAO,QAAQ,EAAE,MAAM,GAAG,OAAO,QAAQ,EAAE;AAC9E;AAEA,SAAS,cAAc,OAAiD,QAAwB;CAC9F,MAAM,SAAS,IAAI,OAAO,OAAO,MAAM;CACvC,MAAM,QAAQ,MAAM,MAAM;CAE1B,IAAI,MAAM,UAAU;EAClB,MAAM,gBAAgB,MAAM,MAAM,WAAW,SAAS,UAAU,KAAK,IAAI,CAAC;EAC1E,IAAI,kBAAkB,GAAG,OAAO,MAAM;EACtC,IAAI,kBAAkB,GAAG,OAAO,GAAG,OAAO,MAAM,GAAG,MAAM;EACzD,OAAO,GAAG,OAAO,MAAM,GAAG,OAAO,MAAM,GAAG,MAAM;CAClD;CAEA,IAAI,UAAU,GAAG,OAAO,OAAO,OAAO,KAAK;CAC3C,OAAO,GAAG,OAAO,MAAM,GAAG,OAAO;AACnC;AAEA,SAAS,cAAc,OAAyB,QAAgB,gBAAiC;CAC/F,IAAI,MAAM,SAAS,SAAS,OAAO;CACnC,IAAI,MAAM,SAAS,YAAY,OAAO,GAAG,MAAM,WAAW;CAC1D,IAAI,MAAM,SAAS,KAAK,OAAO,cAAc,OAAO,MAAM;CAE1D,MAAM,WAAW,qBAAqB,MAAM;CAC5C,OAAO,iBAAiB,KAAK,OAAO,IAAI,aAAa,GAAG,MAAM,MAAM,IAAI;AAC1E;AAEA,SAAgB,aAAa,OAAmB,QAAgB,gBAAiC;CAC/F,IAAI,MAAM,SAAS,SAAS,OAAO,cAAc,OAAO,QAAQ,cAAc;CAE9E,MAAM,eAAe,MAAM,QAAQ,MAAM;CACzC,IAAI,gBAAgB,OAAO,cAAc,cAAc,QAAQ,IAAI;CAEnE,MAAM,YAAY,CAAC,GAAG,MAAM,aAAa;CACzC,UAAU,MAAM,gBAAgB,cAAc,cAAc,QAAQ,KAAK;CACzE,OAAO,UAAU,KAAK,MAAM;AAC9B"}
|